1 /* 2 Copyright (c) 2004-2011, 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 5 */ 6 7 /* 8 This is an optimized version of Dojo, built for deployment and not for 9 development. To get sources and documentation, please visit: 10 11 http://dojotoolkit.org 12 */ 13 14 ;(function(){ 15 16 /* 17 dojo, dijit, and dojox must always be the first three, and in that order. 18 djConfig.scopeMap = [ 19 ["dojo", "fojo"], 20 ["dijit", "fijit"], 21 ["dojox", "fojox"] 22 23 ] 24 */ 25 26 /**Build will replace this comment with a scoped djConfig **/ 27 28 //The null below can be relaced by a build-time value used instead of djConfig.scopeMap. 29 var sMap = null; 30 31 //See if new scopes need to be defined. 32 if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){ 33 var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {}; 34 sMap = sMap || djConfig.scopeMap; 35 for(var i = 0; i < sMap.length; i++){ 36 //Make local variables, then global variables that use the locals. 37 var newScope = sMap[i]; 38 scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';"; 39 scopePrefix += (i == 0 ? "" : ",") + newScope[0]; 40 scopeSuffix += (i == 0 ? "" : ",") + newScope[1]; 41 scopeMap[newScope[0]] = newScope[1]; 42 scopeMapRev[newScope[1]] = newScope[0]; 43 } 44 45 eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];"); 46 47 dojo._scopePrefixArgs = scopePrefix; 48 dojo._scopePrefix = "(function(" + scopePrefix + "){"; 49 dojo._scopeSuffix = "})(" + scopeSuffix + ")"; 50 dojo._scopeMap = scopeMap; 51 dojo._scopeMapRev = scopeMapRev; 52 } 53 54 /*===== 55 // note: 56 // 'djConfig' does not exist under 'dojo.*' so that it can be set before the 57 // 'dojo' variable exists. 58 // note: 59 // Setting any of these variables *after* the library has loaded does 60 // nothing at all. 61 62 djConfig = { 63 // summary: 64 // Application code can set the global 'djConfig' prior to loading 65 // the library to override certain global settings for how dojo works. 66 // 67 // isDebug: Boolean 68 // Defaults to `false`. If set to `true`, ensures that Dojo provides 69 // extended debugging feedback via Firebug. If Firebug is not available 70 // on your platform, setting `isDebug` to `true` will force Dojo to 71 // pull in (and display) the version of Firebug Lite which is 72 // integrated into the Dojo distribution, thereby always providing a 73 // debugging/logging console when `isDebug` is enabled. Note that 74 // Firebug's `console.*` methods are ALWAYS defined by Dojo. If 75 // `isDebug` is false and you are on a platform without Firebug, these 76 // methods will be defined as no-ops. 77 isDebug: false, 78 // debugAtAllCosts: Boolean 79 // Defaults to `false`. If set to `true`, this triggers an alternate 80 // mode of the package system in which dependencies are detected and 81 // only then are resources evaluated in dependency order via 82 // `<script>` tag inclusion. This may double-request resources and 83 // cause problems with scripts which expect `dojo.require()` to 84 // preform synchronously. `debugAtAllCosts` can be an invaluable 85 // debugging aid, but when using it, ensure that all code which 86 // depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers. 87 // Due to the somewhat unpredictable side-effects of using 88 // `debugAtAllCosts`, it is strongly recommended that you enable this 89 // flag as a last resort. `debugAtAllCosts` has no effect when loading 90 // resources across domains. For usage information, see the 91 // [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb) 92 debugAtAllCosts: false, 93 // locale: String 94 // The locale to assume for loading localized resources in this page, 95 // specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt). 96 // Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`. 97 // See the documentation for `dojo.i18n` and `dojo.requireLocalization` 98 // for details on loading localized resources. If no locale is specified, 99 // Dojo assumes the locale of the user agent, according to `navigator.userLanguage` 100 // or `navigator.language` properties. 101 locale: undefined, 102 // extraLocale: Array 103 // No default value. Specifies additional locales whose 104 // resources should also be loaded alongside the default locale when 105 // calls to `dojo.requireLocalization()` are processed. 106 extraLocale: undefined, 107 // baseUrl: String 108 // The directory in which `dojo.js` is located. Under normal 109 // conditions, Dojo auto-detects the correct location from which it 110 // was loaded. You may need to manually configure `baseUrl` in cases 111 // where you have renamed `dojo.js` or in which `<base>` tags confuse 112 // some browsers (e.g. IE 6). The variable `dojo.baseUrl` is assigned 113 // either the value of `djConfig.baseUrl` if one is provided or the 114 // auto-detected root if not. Other modules are located relative to 115 // this path. The path should end in a slash. 116 baseUrl: undefined, 117 // modulePaths: Object 118 // A map of module names to paths relative to `dojo.baseUrl`. The 119 // key/value pairs correspond directly to the arguments which 120 // `dojo.registerModulePath` accepts. Specifiying 121 // `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent 122 // of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple 123 // modules may be configured via `djConfig.modulePaths`. 124 modulePaths: {}, 125 // afterOnLoad: Boolean 126 // Indicates Dojo was added to the page after the page load. In this case 127 // Dojo will not wait for the page DOMContentLoad/load events and fire 128 // its dojo.addOnLoad callbacks after making sure all outstanding 129 // dojo.required modules have loaded. Only works with a built dojo.js, 130 // it does not work the dojo.js directly from source control. 131 afterOnLoad: false, 132 // addOnLoad: Function or Array 133 // Adds a callback via dojo.addOnLoad. Useful when Dojo is added after 134 // the page loads and djConfig.afterOnLoad is true. Supports the same 135 // arguments as dojo.addOnLoad. When using a function reference, use 136 // `djConfig.addOnLoad = function(){};`. For object with function name use 137 // `djConfig.addOnLoad = [myObject, "functionName"];` and for object with 138 // function reference use 139 // `djConfig.addOnLoad = [myObject, function(){}];` 140 addOnLoad: null, 141 // require: Array 142 // An array of module names to be loaded immediately after dojo.js has been included 143 // in a page. 144 require: [], 145 // defaultDuration: Array 146 // Default duration, in milliseconds, for wipe and fade animations within dijits. 147 // Assigned to dijit.defaultDuration. 148 defaultDuration: 200, 149 // dojoBlankHtmlUrl: String 150 // Used by some modules to configure an empty iframe. Used by dojo.io.iframe and 151 // dojo.back, and dijit popup support in IE where an iframe is needed to make sure native 152 // controls do not bleed through the popups. Normally this configuration variable 153 // does not need to be set, except when using cross-domain/CDN Dojo builds. 154 // Save dojo/resources/blank.html to your domain and set `djConfig.dojoBlankHtmlUrl` 155 // to the path on your domain your copy of blank.html. 156 dojoBlankHtmlUrl: undefined, 157 // ioPublish: Boolean? 158 // Set this to true to enable publishing of topics for the different phases of 159 // IO operations. Publishing is done via dojo.publish. See dojo.__IoPublish for a list 160 // of topics that are published. 161 ioPublish: false, 162 // useCustomLogger: Anything? 163 // If set to a value that evaluates to true such as a string or array and 164 // isDebug is true and Firebug is not available or running, then it bypasses 165 // the creation of Firebug Lite allowing you to define your own console object. 166 useCustomLogger: undefined, 167 // transparentColor: Array 168 // Array containing the r, g, b components used as transparent color in dojo.Color; 169 // if undefined, [255,255,255] (white) will be used. 170 transparentColor: undefined, 171 // skipIeDomLoaded: Boolean 172 // For IE only, skip the DOMContentLoaded hack used. Sometimes it can cause an Operation 173 // Aborted error if the rest of the page triggers script defers before the DOM is ready. 174 // If this is config value is set to true, then dojo.addOnLoad callbacks will not be 175 // triggered until the page load event, which is after images and iframes load. If you 176 // want to trigger the callbacks sooner, you can put a script block in the bottom of 177 // your HTML that calls dojo._loadInit();. If you are using multiversion support, change 178 // "dojo." to the appropriate scope name for dojo. 179 skipIeDomLoaded: false 180 } 181 =====*/ 182 183 (function(){ 184 // firebug stubs 185 186 if(typeof this["loadFirebugConsole"] == "function"){ 187 // for Firebug 1.2 188 this["loadFirebugConsole"](); 189 }else{ 190 this.console = this.console || {}; 191 192 // Be careful to leave 'log' always at the end 193 var cn = [ 194 "assert", "count", "debug", "dir", "dirxml", "error", "group", 195 "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd", 196 "trace", "warn", "log" 197 ]; 198 var i = 0, tn; 199 while((tn=cn[i++])){ 200 if(!console[tn]){ 201 (function(){ 202 var tcn = tn+""; 203 console[tcn] = ('log' in console) ? function(){ 204 var a = Array.apply({}, arguments); 205 a.unshift(tcn+":"); 206 console["log"](a.join(" ")); 207 } : function(){} 208 console[tcn]._fake = true; 209 })(); 210 } 211 } 212 } 213 214 //TODOC: HOW TO DOC THIS? 215 // dojo is the root variable of (almost all) our public symbols -- make sure it is defined. 216 if(typeof dojo == "undefined"){ 217 dojo = { 218 _scopeName: "dojo", 219 _scopePrefix: "", 220 _scopePrefixArgs: "", 221 _scopeSuffix: "", 222 _scopeMap: {}, 223 _scopeMapRev: {} 224 }; 225 } 226 227 var d = dojo; 228 229 //Need placeholders for dijit and dojox for scoping code. 230 if(typeof dijit == "undefined"){ 231 dijit = {_scopeName: "dijit"}; 232 } 233 if(typeof dojox == "undefined"){ 234 dojox = {_scopeName: "dojox"}; 235 } 236 237 if(!d._scopeArgs){ 238 d._scopeArgs = [dojo, dijit, dojox]; 239 } 240 241 /*===== 242 dojo.global = { 243 // summary: 244 // Alias for the global scope 245 // (e.g. the window object in a browser). 246 // description: 247 // Refer to 'dojo.global' rather than referring to window to ensure your 248 // code runs correctly in contexts other than web browsers (e.g. Rhino on a server). 249 } 250 =====*/ 251 d.global = this; 252 253 d.config =/*===== djConfig = =====*/{ 254 isDebug: false, 255 debugAtAllCosts: false 256 }; 257 258 // FIXME: 2.0, drop djConfig support. Use dojoConfig exclusively for global config. 259 var cfg = typeof djConfig != "undefined" ? djConfig : 260 typeof dojoConfig != "undefined" ? dojoConfig : null; 261 262 if(cfg){ 263 for(var c in cfg){ 264 d.config[c] = cfg[c]; 265 } 266 } 267 268 /*===== 269 // Override locale setting, if specified 270 dojo.locale = { 271 // summary: the locale as defined by Dojo (read-only) 272 }; 273 =====*/ 274 dojo.locale = d.config.locale; 275 276 var rev = "$Rev: 24595 $".match(/\d+/); 277 278 /*===== 279 dojo.version = function(){ 280 // summary: 281 // Version number of the Dojo Toolkit 282 // major: Integer 283 // Major version. If total version is "1.2.0beta1", will be 1 284 // minor: Integer 285 // Minor version. If total version is "1.2.0beta1", will be 2 286 // patch: Integer 287 // Patch version. If total version is "1.2.0beta1", will be 0 288 // flag: String 289 // Descriptor flag. If total version is "1.2.0beta1", will be "beta1" 290 // revision: Number 291 // The SVN rev from which dojo was pulled 292 this.major = 0; 293 this.minor = 0; 294 this.patch = 0; 295 this.flag = ""; 296 this.revision = 0; 297 } 298 =====*/ 299 dojo.version = { 300 major: 1, minor: 6, patch: 1, flag: "", 301 revision: rev ? +rev[0] : NaN, 302 toString: function(){ 303 with(d.version){ 304 return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String 305 } 306 } 307 } 308 309 // Register with the OpenAjax hub 310 if(typeof OpenAjax != "undefined"){ 311 OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString()); 312 } 313 314 var extraNames, extraLen, empty = {}; 315 for(var i in {toString: 1}){ extraNames = []; break; } 316 dojo._extraNames = extraNames = extraNames || ["hasOwnProperty", "valueOf", "isPrototypeOf", 317 "propertyIsEnumerable", "toLocaleString", "toString", "constructor"]; 318 extraLen = extraNames.length; 319 320 dojo._mixin = function(/*Object*/ target, /*Object*/ source){ 321 // summary: 322 // Adds all properties and methods of source to target. This addition 323 // is "prototype extension safe", so that instances of objects 324 // will not pass along prototype defaults. 325 var name, s, i; 326 for(name in source){ 327 // the "tobj" condition avoid copying properties in "source" 328 // inherited from Object.prototype. For example, if target has a custom 329 // toString() method, don't overwrite it with the toString() method 330 // that source inherited from Object.prototype 331 s = source[name]; 332 if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){ 333 target[name] = s; 334 } 335 } 336 // IE doesn't recognize some custom functions in for..in 337 if(extraLen && source){ 338 for(i = 0; i < extraLen; ++i){ 339 name = extraNames[i]; 340 s = source[name]; 341 if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){ 342 target[name] = s; 343 } 344 } 345 } 346 return target; // Object 347 } 348 349 dojo.mixin = function(/*Object*/obj, /*Object...*/props){ 350 // summary: 351 // Adds all properties and methods of props to obj and returns the 352 // (now modified) obj. 353 // description: 354 // `dojo.mixin` can mix multiple source objects into a 355 // destination object which is then returned. Unlike regular 356 // `for...in` iteration, `dojo.mixin` is also smart about avoiding 357 // extensions which other toolkits may unwisely add to the root 358 // object prototype 359 // obj: 360 // The object to mix properties into. Also the return value. 361 // props: 362 // One or more objects whose values are successively copied into 363 // obj. If more than one of these objects contain the same value, 364 // the one specified last in the function call will "win". 365 // example: 366 // make a shallow copy of an object 367 // | var copy = dojo.mixin({}, source); 368 // example: 369 // many class constructors often take an object which specifies 370 // values to be configured on the object. In this case, it is 371 // often simplest to call `dojo.mixin` on the `this` object: 372 // | dojo.declare("acme.Base", null, { 373 // | constructor: function(properties){ 374 // | // property configuration: 375 // | dojo.mixin(this, properties); 376 // | 377 // | console.log(this.quip); 378 // | // ... 379 // | }, 380 // | quip: "I wasn't born yesterday, you know - I've seen movies.", 381 // | // ... 382 // | }); 383 // | 384 // | // create an instance of the class and configure it 385 // | var b = new acme.Base({quip: "That's what it does!" }); 386 // example: 387 // copy in properties from multiple objects 388 // | var flattened = dojo.mixin( 389 // | { 390 // | name: "Frylock", 391 // | braces: true 392 // | }, 393 // | { 394 // | name: "Carl Brutanananadilewski" 395 // | } 396 // | ); 397 // | 398 // | // will print "Carl Brutanananadilewski" 399 // | console.log(flattened.name); 400 // | // will print "true" 401 // | console.log(flattened.braces); 402 if(!obj){ obj = {}; } 403 for(var i=1, l=arguments.length; i<l; i++){ 404 d._mixin(obj, arguments[i]); 405 } 406 return obj; // Object 407 } 408 409 dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){ 410 var obj=context || d.global; 411 for(var i=0, p; obj && (p=parts[i]); i++){ 412 if(i == 0 && d._scopeMap[p]){ 413 p = d._scopeMap[p]; 414 } 415 obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined)); 416 } 417 return obj; // mixed 418 } 419 420 dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){ 421 // summary: 422 // Set a property from a dot-separated string, such as "A.B.C" 423 // description: 424 // Useful for longer api chains where you have to test each object in 425 // the chain, or when you have an object reference in string format. 426 // Objects are created as needed along `path`. Returns the passed 427 // value if setting is successful or `undefined` if not. 428 // name: 429 // Path to a property, in the form "A.B.C". 430 // context: 431 // Optional. Object to use as root of path. Defaults to 432 // `dojo.global`. 433 // example: 434 // set the value of `foo.bar.baz`, regardless of whether 435 // intermediate objects already exist: 436 // | dojo.setObject("foo.bar.baz", value); 437 // example: 438 // without `dojo.setObject`, we often see code like this: 439 // | // ensure that intermediate objects are available 440 // | if(!obj["parent"]){ obj.parent = {}; } 441 // | if(!obj.parent["child"]){ obj.parent.child= {}; } 442 // | // now we can safely set the property 443 // | obj.parent.child.prop = "some value"; 444 // wheras with `dojo.setObject`, we can shorten that to: 445 // | dojo.setObject("parent.child.prop", "some value", obj); 446 var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context); 447 return obj && p ? (obj[p]=value) : undefined; // Object 448 } 449 450 dojo.getObject = function(/*String*/name, /*Boolean?*/create, /*Object?*/context){ 451 // summary: 452 // Get a property from a dot-separated string, such as "A.B.C" 453 // description: 454 // Useful for longer api chains where you have to test each object in 455 // the chain, or when you have an object reference in string format. 456 // name: 457 // Path to an property, in the form "A.B.C". 458 // create: 459 // Optional. Defaults to `false`. If `true`, Objects will be 460 // created at any point along the 'path' that is undefined. 461 // context: 462 // Optional. Object to use as root of path. Defaults to 463 // 'dojo.global'. Null may be passed. 464 return d._getProp(name.split("."), create, context); // Object 465 } 466 467 dojo.exists = function(/*String*/name, /*Object?*/obj){ 468 // summary: 469 // determine if an object supports a given method 470 // description: 471 // useful for longer api chains where you have to test each object in 472 // the chain. Useful for object and method detection. 473 // name: 474 // Path to an object, in the form "A.B.C". 475 // obj: 476 // Object to use as root of path. Defaults to 477 // 'dojo.global'. Null may be passed. 478 // example: 479 // | // define an object 480 // | var foo = { 481 // | bar: { } 482 // | }; 483 // | 484 // | // search the global scope 485 // | dojo.exists("foo.bar"); // true 486 // | dojo.exists("foo.bar.baz"); // false 487 // | 488 // | // search from a particular scope 489 // | dojo.exists("bar", foo); // true 490 // | dojo.exists("bar.baz", foo); // false 491 return d.getObject(name, false, obj) !== undefined; // Boolean 492 } 493 494 dojo["eval"] = function(/*String*/ scriptFragment){ 495 // summary: 496 // A legacy method created for use exclusively by internal Dojo methods. Do not use 497 // this method directly, the behavior of this eval will differ from the normal 498 // browser eval. 499 // description: 500 // Placed in a separate function to minimize size of trapped 501 // exceptions. Calling eval() directly from some other scope may 502 // complicate tracebacks on some platforms. 503 // returns: 504 // The result of the evaluation. Often `undefined` 505 return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // Object 506 } 507 508 /*===== 509 dojo.deprecated = function(behaviour, extra, removal){ 510 // summary: 511 // Log a debug message to indicate that a behavior has been 512 // deprecated. 513 // behaviour: String 514 // The API or behavior being deprecated. Usually in the form 515 // of "myApp.someFunction()". 516 // extra: String? 517 // Text to append to the message. Often provides advice on a 518 // new function or facility to achieve the same goal during 519 // the deprecation period. 520 // removal: String? 521 // Text to indicate when in the future the behavior will be 522 // removed. Usually a version number. 523 // example: 524 // | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0"); 525 } 526 527 dojo.experimental = function(moduleName, extra){ 528 // summary: Marks code as experimental. 529 // description: 530 // This can be used to mark a function, file, or module as 531 // experimental. Experimental code is not ready to be used, and the 532 // APIs are subject to change without notice. Experimental code may be 533 // completed deleted without going through the normal deprecation 534 // process. 535 // moduleName: String 536 // The name of a module, or the name of a module file or a specific 537 // function 538 // extra: String? 539 // some additional message for the user 540 // example: 541 // | dojo.experimental("dojo.data.Result"); 542 // example: 543 // | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA"); 544 } 545 =====*/ 546 547 //Real functions declared in dojo._firebug.firebug. 548 d.deprecated = d.experimental = function(){}; 549 550 })(); 551 // vim:ai:ts=4:noet 552 553 /* 554 * loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains 555 * all of the package loading methods. 556 */ 557 (function(){ 558 var d = dojo, currentModule; 559 560 d.mixin(d, { 561 _loadedModules: {}, 562 _inFlightCount: 0, 563 _hasResource: {}, 564 565 _modulePrefixes: { 566 dojo: { name: "dojo", value: "." }, 567 // dojox: { name: "dojox", value: "../dojox" }, 568 // dijit: { name: "dijit", value: "../dijit" }, 569 doh: { name: "doh", value: "../util/doh" }, 570 tests: { name: "tests", value: "tests" } 571 }, 572 573 _moduleHasPrefix: function(/*String*/module){ 574 // summary: checks to see if module has been established 575 var mp = d._modulePrefixes; 576 return !!(mp[module] && mp[module].value); // Boolean 577 }, 578 579 _getModulePrefix: function(/*String*/module){ 580 // summary: gets the prefix associated with module 581 var mp = d._modulePrefixes; 582 if(d._moduleHasPrefix(module)){ 583 return mp[module].value; // String 584 } 585 return module; // String 586 }, 587 588 _loadedUrls: [], 589 590 //WARNING: 591 // This variable is referenced by packages outside of bootstrap: 592 // FloatingPane.js and undo/browser.js 593 _postLoad: false, 594 595 //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad. 596 _loaders: [], 597 _unloaders: [], 598 _loadNotifying: false 599 }); 600 601 602 dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){ 603 // summary: 604 // Load a Javascript module given a relative path 605 // 606 // description: 607 // Loads and interprets the script located at relpath, which is 608 // relative to the script root directory. If the script is found but 609 // its interpretation causes a runtime exception, that exception is 610 // not caught by us, so the caller will see it. We return a true 611 // value if and only if the script is found. 612 // 613 // relpath: 614 // A relative path to a script (no leading '/', and typically ending 615 // in '.js'). 616 // module: 617 // A module whose existance to check for after loading a path. Can be 618 // used to determine success or failure of the load. 619 // cb: 620 // a callback function to pass the result of evaluating the script 621 622 var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : d.baseUrl) + relpath; 623 try{ 624 currentModule = module; 625 return !module ? d._loadUri(uri, cb) : d._loadUriAndCheck(uri, module, cb); // Boolean 626 }catch(e){ 627 console.error(e); 628 return false; // Boolean 629 }finally{ 630 currentModule = null; 631 } 632 } 633 634 dojo._loadUri = function(/*String*/uri, /*Function?*/cb){ 635 // summary: 636 // Loads JavaScript from a URI 637 // description: 638 // Reads the contents of the URI, and evaluates the contents. This is 639 // used to load modules as well as resource bundles. Returns true if 640 // it succeeded. Returns false if the URI reading failed. Throws if 641 // the evaluation throws. 642 // uri: a uri which points at the script to be loaded 643 // cb: 644 // a callback function to process the result of evaluating the script 645 // as an expression, typically used by the resource bundle loader to 646 // load JSON-style resources 647 648 if(d._loadedUrls[uri]){ 649 return true; // Boolean 650 } 651 d._inFlightCount++; // block addOnLoad calls that arrive while we're busy downloading 652 var contents = d._getText(uri, true); 653 if(contents){ // not 404, et al 654 d._loadedUrls[uri] = true; 655 d._loadedUrls.push(uri); 656 if(cb){ 657 //conditional to support script-inject i18n bundle format 658 contents = /^define\(/.test(contents) ? contents : '('+contents+')'; 659 }else{ 660 //Only do the scoping if no callback. If a callback is specified, 661 //it is most likely the i18n bundle stuff. 662 contents = d._scopePrefix + contents + d._scopeSuffix; 663 } 664 if(!d.isIE){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug 665 var value = d["eval"](contents); 666 if(cb){ cb(value); } 667 } 668 // Check to see if we need to call _callLoaded() due to an addOnLoad() that arrived while we were busy downloading 669 if(--d._inFlightCount == 0 && d._postLoad && d._loaders.length){ 670 // We shouldn't be allowed to get here but Firefox allows an event 671 // (mouse, keybd, async xhrGet) to interrupt a synchronous xhrGet. 672 // If the current script block contains multiple require() statements, then after each 673 // require() returns, inFlightCount == 0, but we want to hold the _callLoaded() until 674 // all require()s are done since the out-of-sequence addOnLoad() presumably needs them all. 675 // setTimeout allows the next require() to start (if needed), and then we check this again. 676 setTimeout(function(){ 677 // If inFlightCount > 0, then multiple require()s are running sequentially and 678 // the next require() started after setTimeout() was executed but before we got here. 679 if(d._inFlightCount == 0){ 680 d._callLoaded(); 681 } 682 }, 0); 683 } 684 return !!contents; // Boolean: contents? true : false 685 } 686 687 // FIXME: probably need to add logging to this method 688 dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){ 689 // summary: calls loadUri then findModule and returns true if both succeed 690 var ok = false; 691 try{ 692 ok = d._loadUri(uri, cb); 693 }catch(e){ 694 console.error("failed loading " + uri + " with error: " + e); 695 } 696 return !!(ok && d._loadedModules[moduleName]); // Boolean 697 } 698 699 dojo.loaded = function(){ 700 // summary: 701 // signal fired when initial environment and package loading is 702 // complete. You should use dojo.addOnLoad() instead of doing a 703 // direct dojo.connect() to this method in order to handle 704 // initialization tasks that require the environment to be 705 // initialized. In a browser host, declarative widgets will 706 // be constructed when this function finishes runing. 707 d._loadNotifying = true; 708 d._postLoad = true; 709 var mll = d._loaders; 710 711 //Clear listeners so new ones can be added 712 //For other xdomain package loads after the initial load. 713 d._loaders = []; 714 715 for(var x = 0; x < mll.length; x++){ 716 mll[x](); 717 } 718 719 d._loadNotifying = false; 720 721 //Make sure nothing else got added to the onload queue 722 //after this first run. If something did, and we are not waiting for any 723 //more inflight resources, run again. 724 if(d._postLoad && d._inFlightCount == 0 && mll.length){ 725 d._callLoaded(); 726 } 727 } 728 729 dojo.unloaded = function(){ 730 // summary: 731 // signal fired by impending environment destruction. You should use 732 // dojo.addOnUnload() instead of doing a direct dojo.connect() to this 733 // method to perform page/application cleanup methods. See 734 // dojo.addOnUnload for more info. 735 var mll = d._unloaders; 736 while(mll.length){ 737 (mll.pop())(); 738 } 739 } 740 741 d._onto = function(arr, obj, fn){ 742 if(!fn){ 743 arr.push(obj); 744 }else if(fn){ 745 var func = (typeof fn == "string") ? obj[fn] : fn; 746 arr.push(function(){ func.call(obj); }); 747 } 748 } 749 750 dojo.ready = dojo.addOnLoad = function(/*Object*/obj, /*String|Function?*/functionName){ 751 // summary: 752 // Registers a function to be triggered after the DOM and dojo.require() calls 753 // have finished loading. 754 // 755 // description: 756 // Registers a function to be triggered after the DOM has finished 757 // loading and `dojo.require` modules have loaded. Widgets declared in markup 758 // have been instantiated if `djConfig.parseOnLoad` is true when this fires. 759 // 760 // Images and CSS files may or may not have finished downloading when 761 // the specified function is called. (Note that widgets' CSS and HTML 762 // code is guaranteed to be downloaded before said widgets are 763 // instantiated, though including css resouces BEFORE any script elements 764 // is highly recommended). 765 // 766 // example: 767 // Register an anonymous function to run when everything is ready 768 // | dojo.addOnLoad(function(){ doStuff(); }); 769 // 770 // example: 771 // Register a function to run when everything is ready by pointer: 772 // | var init = function(){ doStuff(); } 773 // | dojo.addOnLoad(init); 774 // 775 // example: 776 // Register a function to run scoped to `object`, either by name or anonymously: 777 // | dojo.addOnLoad(object, "functionName"); 778 // | dojo.addOnLoad(object, function(){ doStuff(); }); 779 780 d._onto(d._loaders, obj, functionName); 781 782 //Added for xdomain loading. dojo.addOnLoad is used to 783 //indicate callbacks after doing some dojo.require() statements. 784 //In the xdomain case, if all the requires are loaded (after initial 785 //page load), then immediately call any listeners. 786 if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){ 787 d._callLoaded(); 788 } 789 } 790 791 //Support calling dojo.addOnLoad via djConfig.addOnLoad. Support all the 792 //call permutations of dojo.addOnLoad. Mainly useful when dojo is added 793 //to the page after the page has loaded. 794 var dca = d.config.addOnLoad; 795 if(dca){ 796 d.addOnLoad[(dca instanceof Array ? "apply" : "call")](d, dca); 797 } 798 799 dojo._modulesLoaded = function(){ 800 if(d._postLoad){ return; } 801 if(d._inFlightCount > 0){ 802 console.warn("files still in flight!"); 803 return; 804 } 805 d._callLoaded(); 806 } 807 808 dojo._callLoaded = function(){ 809 810 // The "object" check is for IE, and the other opera check fixes an 811 // issue in Opera where it could not find the body element in some 812 // widget test cases. For 0.9, maybe route all browsers through the 813 // setTimeout (need protection still for non-browser environments 814 // though). This might also help the issue with FF 2.0 and freezing 815 // issues where we try to do sync xhr while background css images are 816 // being loaded (trac #2572)? Consider for 0.9. 817 if(typeof setTimeout == "object" || (d.config.useXDomain && d.isOpera)){ 818 setTimeout( 819 d.isAIR ? function(){ d.loaded(); } : d._scopeName + ".loaded();", 820 0); 821 }else{ 822 d.loaded(); 823 } 824 } 825 826 dojo._getModuleSymbols = function(/*String*/modulename){ 827 // summary: 828 // Converts a module name in dotted JS notation to an array 829 // representing the path in the source tree 830 var syms = modulename.split("."); 831 for(var i = syms.length; i>0; i--){ 832 var parentModule = syms.slice(0, i).join("."); 833 if(i == 1 && !d._moduleHasPrefix(parentModule)){ 834 // Support default module directory (sibling of dojo) for top-level modules 835 syms[0] = "../" + syms[0]; 836 }else{ 837 var parentModulePath = d._getModulePrefix(parentModule); 838 if(parentModulePath != parentModule){ 839 syms.splice(0, i, parentModulePath); 840 break; 841 } 842 } 843 } 844 return syms; // Array 845 } 846 847 dojo._global_omit_module_check = false; 848 849 dojo.loadInit = function(/*Function*/init){ 850 // summary: 851 // Executes a function that needs to be executed for the loader's dojo.requireIf 852 // resolutions to work. This is needed mostly for the xdomain loader case where 853 // a function needs to be executed to set up the possible values for a dojo.requireIf 854 // call. 855 // init: 856 // a function reference. Executed immediately. 857 // description: This function is mainly a marker for the xdomain loader to know parts of 858 // code that needs be executed outside the function wrappper that is placed around modules. 859 // The init function could be executed more than once, and it should make no assumptions 860 // on what is loaded, or what modules are available. Only the functionality in Dojo Base 861 // is allowed to be used. Avoid using this method. For a valid use case, 862 // see the source for dojox.gfx. 863 init(); 864 } 865 866 dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){ 867 // summary: 868 // loads a Javascript module from the appropriate URI 869 // 870 // moduleName: String 871 // module name to load, using periods for separators, 872 // e.g. "dojo.date.locale". Module paths are de-referenced by dojo's 873 // internal mapping of locations to names and are disambiguated by 874 // longest prefix. See `dojo.registerModulePath()` for details on 875 // registering new modules. 876 // 877 // omitModuleCheck: Boolean? 878 // if `true`, omitModuleCheck skips the step of ensuring that the 879 // loaded file actually defines the symbol it is referenced by. 880 // For example if it called as `dojo.require("a.b.c")` and the 881 // file located at `a/b/c.js` does not define an object `a.b.c`, 882 // and exception will be throws whereas no exception is raised 883 // when called as `dojo.require("a.b.c", true)` 884 // 885 // description: 886 // Modules are loaded via dojo.require by using one of two loaders: the normal loader 887 // and the xdomain loader. The xdomain loader is used when dojo was built with a 888 // custom build that specified loader=xdomain and the module lives on a modulePath 889 // that is a whole URL, with protocol and a domain. The versions of Dojo that are on 890 // the Google and AOL CDNs use the xdomain loader. 891 // 892 // If the module is loaded via the xdomain loader, it is an asynchronous load, since 893 // the module is added via a dynamically created script tag. This 894 // means that dojo.require() can return before the module has loaded. However, this 895 // should only happen in the case where you do dojo.require calls in the top-level 896 // HTML page, or if you purposely avoid the loader checking for dojo.require 897 // dependencies in your module by using a syntax like dojo["require"] to load the module. 898 // 899 // Sometimes it is useful to not have the loader detect the dojo.require calls in the 900 // module so that you can dynamically load the modules as a result of an action on the 901 // page, instead of right at module load time. 902 // 903 // Also, for script blocks in an HTML page, the loader does not pre-process them, so 904 // it does not know to download the modules before the dojo.require calls occur. 905 // 906 // So, in those two cases, when you want on-the-fly module loading or for script blocks 907 // in the HTML page, special care must be taken if the dojo.required code is loaded 908 // asynchronously. To make sure you can execute code that depends on the dojo.required 909 // modules, be sure to add the code that depends on the modules in a dojo.addOnLoad() 910 // callback. dojo.addOnLoad waits for all outstanding modules to finish loading before 911 // executing. 912 // 913 // This type of syntax works with both xdomain and normal loaders, so it is good 914 // practice to always use this idiom for on-the-fly code loading and in HTML script 915 // blocks. If at some point you change loaders and where the code is loaded from, 916 // it will all still work. 917 // 918 // More on how dojo.require 919 // `dojo.require("A.B")` first checks to see if symbol A.B is 920 // defined. If it is, it is simply returned (nothing to do). 921 // 922 // If it is not defined, it will look for `A/B.js` in the script root 923 // directory. 924 // 925 // `dojo.require` throws an exception if it cannot find a file 926 // to load, or if the symbol `A.B` is not defined after loading. 927 // 928 // It returns the object `A.B`, but note the caveats above about on-the-fly loading and 929 // HTML script blocks when the xdomain loader is loading a module. 930 // 931 // `dojo.require()` does nothing about importing symbols into 932 // the current namespace. It is presumed that the caller will 933 // take care of that. 934 // 935 // example: 936 // To use dojo.require in conjunction with dojo.ready: 937 // 938 // | dojo.require("foo"); 939 // | dojo.require("bar"); 940 // | dojo.addOnLoad(function(){ 941 // | //you can now safely do something with foo and bar 942 // | }); 943 // 944 // example: 945 // For example, to import all symbols into a local block, you might write: 946 // 947 // | with (dojo.require("A.B")) { 948 // | ... 949 // | } 950 // 951 // And to import just the leaf symbol to a local variable: 952 // 953 // | var B = dojo.require("A.B"); 954 // | ... 955 // 956 // returns: 957 // the required namespace object 958 omitModuleCheck = d._global_omit_module_check || omitModuleCheck; 959 960 //Check if it is already loaded. 961 var module = d._loadedModules[moduleName]; 962 if(module){ 963 return module; 964 } 965 966 // convert periods to slashes 967 var relpath = d._getModuleSymbols(moduleName).join("/") + '.js'; 968 var modArg = !omitModuleCheck ? moduleName : null; 969 var ok = d._loadPath(relpath, modArg); 970 if(!ok && !omitModuleCheck){ 971 throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'"); 972 } 973 974 // check that the symbol was defined 975 // Don't bother if we're doing xdomain (asynchronous) loading. 976 if(!omitModuleCheck && !d._isXDomain){ 977 // pass in false so we can give better error 978 module = d._loadedModules[moduleName]; 979 if(!module){ 980 throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'"); 981 } 982 } 983 984 return module; 985 } 986 987 dojo.provide = function(/*String*/ resourceName){ 988 // summary: 989 // Register a resource with the package system. Works in conjunction with `dojo.require` 990 // 991 // description: 992 // Each javascript source file is called a resource. When a 993 // resource is loaded by the browser, `dojo.provide()` registers 994 // that it has been loaded. 995 // 996 // Each javascript source file must have at least one 997 // `dojo.provide()` call at the top of the file, corresponding to 998 // the file name. For example, `js/dojo/foo.js` must have 999 // `dojo.provide("dojo.foo");` before any calls to 1000 // `dojo.require()` are made. 1001 // 1002 // For backwards compatibility reasons, in addition to registering 1003 // the resource, `dojo.provide()` also ensures that the javascript 1004 // object for the module exists. For example, 1005 // `dojo.provide("dojox.data.FlickrStore")`, in addition to 1006 // registering that `FlickrStore.js` is a resource for the 1007 // `dojox.data` module, will ensure that the `dojox.data` 1008 // javascript object exists, so that calls like 1009 // `dojo.data.foo = function(){ ... }` don't fail. 1010 // 1011 // In the case of a build where multiple javascript source files 1012 // are combined into one bigger file (similar to a .lib or .jar 1013 // file), that file may contain multiple dojo.provide() calls, to 1014 // note that it includes multiple resources. 1015 // 1016 // resourceName: String 1017 // A dot-sperated string identifying a resource. 1018 // 1019 // example: 1020 // Safely create a `my` object, and make dojo.require("my.CustomModule") work 1021 // | dojo.provide("my.CustomModule"); 1022 1023 //Make sure we have a string. 1024 resourceName = resourceName + ""; 1025 return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object 1026 } 1027 1028 //Start of old bootstrap2: 1029 1030 dojo.platformRequire = function(/*Object*/modMap){ 1031 // summary: 1032 // require one or more modules based on which host environment 1033 // Dojo is currently operating in 1034 // description: 1035 // This method takes a "map" of arrays which one can use to 1036 // optionally load dojo modules. The map is indexed by the 1037 // possible dojo.name_ values, with two additional values: 1038 // "default" and "common". The items in the "default" array will 1039 // be loaded if none of the other items have been choosen based on 1040 // dojo.name_, set by your host environment. The items in the 1041 // "common" array will *always* be loaded, regardless of which 1042 // list is chosen. 1043 // example: 1044 // | dojo.platformRequire({ 1045 // | browser: [ 1046 // | "foo.sample", // simple module 1047 // | "foo.test", 1048 // | ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require) 1049 // | ], 1050 // | default: [ "foo.sample._base" ], 1051 // | common: [ "important.module.common" ] 1052 // | }); 1053 1054 var common = modMap.common || []; 1055 var result = common.concat(modMap[d._name] || modMap["default"] || []); 1056 1057 for(var x=0; x<result.length; x++){ 1058 var curr = result[x]; 1059 if(curr.constructor == Array){ 1060 d._loadModule.apply(d, curr); 1061 }else{ 1062 d._loadModule(curr); 1063 } 1064 } 1065 } 1066 1067 dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){ 1068 // summary: 1069 // If the condition is true then call `dojo.require()` for the specified 1070 // resource 1071 // 1072 // example: 1073 // | dojo.requireIf(dojo.isBrowser, "my.special.Module"); 1074 1075 if(condition === true){ 1076 // FIXME: why do we support chained require()'s here? does the build system? 1077 var args = []; 1078 for(var i = 1; i < arguments.length; i++){ 1079 args.push(arguments[i]); 1080 } 1081 d.require.apply(d, args); 1082 } 1083 } 1084 1085 dojo.requireAfterIf = d.requireIf; 1086 1087 dojo.registerModulePath = function(/*String*/module, /*String*/prefix){ 1088 // summary: 1089 // Maps a module name to a path 1090 // description: 1091 // An unregistered module is given the default path of ../[module], 1092 // relative to Dojo root. For example, module acme is mapped to 1093 // ../acme. If you want to use a different module name, use 1094 // dojo.registerModulePath. 1095 // example: 1096 // If your dojo.js is located at this location in the web root: 1097 // | /myapp/js/dojo/dojo/dojo.js 1098 // and your modules are located at: 1099 // | /myapp/js/foo/bar.js 1100 // | /myapp/js/foo/baz.js 1101 // | /myapp/js/foo/thud/xyzzy.js 1102 // Your application can tell Dojo to locate the "foo" namespace by calling: 1103 // | dojo.registerModulePath("foo", "../../foo"); 1104 // At which point you can then use dojo.require() to load the 1105 // modules (assuming they provide() the same things which are 1106 // required). The full code might be: 1107 // | <script type="text/javascript" 1108 // | src="/myapp/js/dojo/dojo/dojo.js"></script> 1109 // | <script type="text/javascript"> 1110 // | dojo.registerModulePath("foo", "../../foo"); 1111 // | dojo.require("foo.bar"); 1112 // | dojo.require("foo.baz"); 1113 // | dojo.require("foo.thud.xyzzy"); 1114 // | </script> 1115 d._modulePrefixes[module] = { name: module, value: prefix }; 1116 }; 1117 1118 dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){ 1119 // summary: 1120 // Declares translated resources and loads them if necessary, in the 1121 // same style as dojo.require. Contents of the resource bundle are 1122 // typically strings, but may be any name/value pair, represented in 1123 // JSON format. See also `dojo.i18n.getLocalization`. 1124 // 1125 // description: 1126 // Load translated resource bundles provided underneath the "nls" 1127 // directory within a package. Translated resources may be located in 1128 // different packages throughout the source tree. 1129 // 1130 // Each directory is named for a locale as specified by RFC 3066, 1131 // (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase. 1132 // Note that the two bundles in the example do not define all the 1133 // same variants. For a given locale, bundles will be loaded for 1134 // that locale and all more general locales above it, including a 1135 // fallback at the root directory. For example, a declaration for 1136 // the "de-at" locale will first load `nls/de-at/bundleone.js`, 1137 // then `nls/de/bundleone.js` and finally `nls/bundleone.js`. The 1138 // data will be flattened into a single Object so that lookups 1139 // will follow this cascading pattern. An optional build step can 1140 // preload the bundles to avoid data redundancy and the multiple 1141 // network hits normally required to load these resources. 1142 // 1143 // moduleName: 1144 // name of the package containing the "nls" directory in which the 1145 // bundle is found 1146 // 1147 // bundleName: 1148 // bundle name, i.e. the filename without the '.js' suffix. Using "nls" as a 1149 // a bundle name is not supported, since "nls" is the name of the folder 1150 // that holds bundles. Using "nls" as the bundle name will cause problems 1151 // with the custom build. 1152 // 1153 // locale: 1154 // the locale to load (optional) By default, the browser's user 1155 // locale as defined by dojo.locale 1156 // 1157 // availableFlatLocales: 1158 // A comma-separated list of the available, flattened locales for this 1159 // bundle. This argument should only be set by the build process. 1160 // 1161 // example: 1162 // A particular widget may define one or more resource bundles, 1163 // structured in a program as follows, where moduleName is 1164 // mycode.mywidget and bundleNames available include bundleone and 1165 // bundletwo: 1166 // | ... 1167 // | mycode/ 1168 // | mywidget/ 1169 // | nls/ 1170 // | bundleone.js (the fallback translation, English in this example) 1171 // | bundletwo.js (also a fallback translation) 1172 // | de/ 1173 // | bundleone.js 1174 // | bundletwo.js 1175 // | de-at/ 1176 // | bundleone.js 1177 // | en/ 1178 // | (empty; use the fallback translation) 1179 // | en-us/ 1180 // | bundleone.js 1181 // | en-gb/ 1182 // | bundleone.js 1183 // | es/ 1184 // | bundleone.js 1185 // | bundletwo.js 1186 // | ...etc 1187 // | ... 1188 // 1189 1190 d.require("dojo.i18n"); 1191 d.i18n._requireLocalization.apply(d.hostenv, arguments); 1192 }; 1193 1194 1195 var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"), 1196 ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$"); 1197 1198 dojo._Url = function(/*dojo._Url|String...*/){ 1199 // summary: 1200 // Constructor to create an object representing a URL. 1201 // It is marked as private, since we might consider removing 1202 // or simplifying it. 1203 // description: 1204 // Each argument is evaluated in order relative to the next until 1205 // a canonical uri is produced. To get an absolute Uri relative to 1206 // the current document use: 1207 // new dojo._Url(document.baseURI, url) 1208 1209 var n = null, 1210 _a = arguments, 1211 uri = [_a[0]]; 1212 // resolve uri components relative to each other 1213 for(var i = 1; i<_a.length; i++){ 1214 if(!_a[i]){ continue; } 1215 1216 // Safari doesn't support this.constructor so we have to be explicit 1217 // FIXME: Tracked (and fixed) in Webkit bug 3537. 1218 // http://bugs.webkit.org/show_bug.cgi?id=3537 1219 var relobj = new d._Url(_a[i]+""), 1220 uriobj = new d._Url(uri[0]+""); 1221 1222 if( 1223 relobj.path == "" && 1224 !relobj.scheme && 1225 !relobj.authority && 1226 !relobj.query 1227 ){ 1228 if(relobj.fragment != n){ 1229 uriobj.fragment = relobj.fragment; 1230 } 1231 relobj = uriobj; 1232 }else if(!relobj.scheme){ 1233 relobj.scheme = uriobj.scheme; 1234 1235 if(!relobj.authority){ 1236 relobj.authority = uriobj.authority; 1237 1238 if(relobj.path.charAt(0) != "/"){ 1239 var path = uriobj.path.substring(0, 1240 uriobj.path.lastIndexOf("/") + 1) + relobj.path; 1241 1242 var segs = path.split("/"); 1243 for(var j = 0; j < segs.length; j++){ 1244 if(segs[j] == "."){ 1245 // flatten "./" references 1246 if(j == segs.length - 1){ 1247 segs[j] = ""; 1248 }else{ 1249 segs.splice(j, 1); 1250 j--; 1251 } 1252 }else if(j > 0 && !(j == 1 && segs[0] == "") && 1253 segs[j] == ".." && segs[j-1] != ".."){ 1254 // flatten "../" references 1255 if(j == (segs.length - 1)){ 1256 segs.splice(j, 1); 1257 segs[j - 1] = ""; 1258 }else{ 1259 segs.splice(j - 1, 2); 1260 j -= 2; 1261 } 1262 } 1263 } 1264 relobj.path = segs.join("/"); 1265 } 1266 } 1267 } 1268 1269 uri = []; 1270 if(relobj.scheme){ 1271 uri.push(relobj.scheme, ":"); 1272 } 1273 if(relobj.authority){ 1274 uri.push("//", relobj.authority); 1275 } 1276 uri.push(relobj.path); 1277 if(relobj.query){ 1278 uri.push("?", relobj.query); 1279 } 1280 if(relobj.fragment){ 1281 uri.push("#", relobj.fragment); 1282 } 1283 } 1284 1285 this.uri = uri.join(""); 1286 1287 // break the uri into its main components 1288 var r = this.uri.match(ore); 1289 1290 this.scheme = r[2] || (r[1] ? "" : n); 1291 this.authority = r[4] || (r[3] ? "" : n); 1292 this.path = r[5]; // can never be undefined 1293 this.query = r[7] || (r[6] ? "" : n); 1294 this.fragment = r[9] || (r[8] ? "" : n); 1295 1296 if(this.authority != n){ 1297 // server based naming authority 1298 r = this.authority.match(ire); 1299 1300 this.user = r[3] || n; 1301 this.password = r[4] || n; 1302 this.host = r[6] || r[7]; // ipv6 || ipv4 1303 this.port = r[9] || n; 1304 } 1305 } 1306 1307 dojo._Url.prototype.toString = function(){ return this.uri; }; 1308 1309 dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){ 1310 // summary: 1311 // Returns a `dojo._Url` object relative to a module. 1312 // example: 1313 // | var pngPath = dojo.moduleUrl("acme","images/small.png"); 1314 // | console.dir(pngPath); // list the object properties 1315 // | // create an image and set it's source to pngPath's value: 1316 // | var img = document.createElement("img"); 1317 // | // NOTE: we assign the string representation of the url object 1318 // | img.src = pngPath.toString(); 1319 // | // add our image to the document 1320 // | dojo.body().appendChild(img); 1321 // example: 1322 // you may de-reference as far as you like down the package 1323 // hierarchy. This is sometimes handy to avoid lenghty relative 1324 // urls or for building portable sub-packages. In this example, 1325 // the `acme.widget` and `acme.util` directories may be located 1326 // under different roots (see `dojo.registerModulePath`) but the 1327 // the modules which reference them can be unaware of their 1328 // relative locations on the filesystem: 1329 // | // somewhere in a configuration block 1330 // | dojo.registerModulePath("acme.widget", "../../acme/widget"); 1331 // | dojo.registerModulePath("acme.util", "../../util"); 1332 // | 1333 // | // ... 1334 // | 1335 // | // code in a module using acme resources 1336 // | var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html"); 1337 // | var dataPath = dojo.moduleUrl("acme.util","resources/data.json"); 1338 1339 var loc = d._getModuleSymbols(module).join('/'); 1340 if(!loc){ return null; } 1341 if(loc.lastIndexOf("/") != loc.length-1){ 1342 loc += "/"; 1343 } 1344 1345 //If the path is an absolute path (starts with a / or is on another 1346 //domain/xdomain) then don't add the baseUrl. 1347 var colonIndex = loc.indexOf(":"); 1348 if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){ 1349 loc = d.baseUrl + loc; 1350 } 1351 1352 return new d._Url(loc, url); // dojo._Url 1353 }; 1354 1355 1356 1357 })(); 1358 1359 /*===== 1360 dojo.isBrowser = { 1361 // example: 1362 // | if(dojo.isBrowser){ ... } 1363 }; 1364 1365 dojo.isFF = { 1366 // example: 1367 // | if(dojo.isFF > 1){ ... } 1368 }; 1369 1370 dojo.isIE = { 1371 // example: 1372 // | if(dojo.isIE > 6){ 1373 // | // we are IE7 1374 // | } 1375 }; 1376 1377 dojo.isSafari = { 1378 // example: 1379 // | if(dojo.isSafari){ ... } 1380 // example: 1381 // Detect iPhone: 1382 // | if(dojo.isSafari && navigator.userAgent.indexOf("iPhone") != -1){ 1383 // | // we are iPhone. Note, iPod touch reports "iPod" above and fails this test. 1384 // | } 1385 }; 1386 1387 dojo = { 1388 // isBrowser: Boolean 1389 // True if the client is a web-browser 1390 isBrowser: true, 1391 // isFF: Number | undefined 1392 // Version as a Number if client is FireFox. undefined otherwise. Corresponds to 1393 // major detected FireFox version (1.5, 2, 3, etc.) 1394 isFF: 2, 1395 // isIE: Number | undefined 1396 // Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to 1397 // major detected IE version (6, 7, 8, etc.) 1398 isIE: 6, 1399 // isKhtml: Number | undefined 1400 // Version as a Number if client is a KHTML browser. undefined otherwise. Corresponds to major 1401 // detected version. 1402 isKhtml: 0, 1403 // isWebKit: Number | undefined 1404 // Version as a Number if client is a WebKit-derived browser (Konqueror, 1405 // Safari, Chrome, etc.). undefined otherwise. 1406 isWebKit: 0, 1407 // isMozilla: Number | undefined 1408 // Version as a Number if client is a Mozilla-based browser (Firefox, 1409 // SeaMonkey). undefined otherwise. Corresponds to major detected version. 1410 isMozilla: 0, 1411 // isOpera: Number | undefined 1412 // Version as a Number if client is Opera. undefined otherwise. Corresponds to 1413 // major detected version. 1414 isOpera: 0, 1415 // isSafari: Number | undefined 1416 // Version as a Number if client is Safari or iPhone. undefined otherwise. 1417 isSafari: 0, 1418 // isChrome: Number | undefined 1419 // Version as a Number if client is Chrome browser. undefined otherwise. 1420 isChrome: 0 1421 // isMac: Boolean 1422 // True if the client runs on Mac 1423 } 1424 =====*/ 1425 if(typeof window != 'undefined'){ 1426 dojo.isBrowser = true; 1427 dojo._name = "browser"; 1428 1429 1430 // attempt to figure out the path to dojo if it isn't set in the config 1431 (function(){ 1432 var d = dojo; 1433 1434 // this is a scope protection closure. We set browser versions and grab 1435 // the URL we were loaded from here. 1436 1437 // grab the node we were loaded from 1438 if(document && document.getElementsByTagName){ 1439 var scripts = document.getElementsByTagName("script"); 1440 var rePkg = /dojo(\.xd)?\.js(\W|$)/i; 1441 for(var i = 0; i < scripts.length; i++){ 1442 var src = scripts[i].getAttribute("src"); 1443 if(!src){ continue; } 1444 var m = src.match(rePkg); 1445 if(m){ 1446 // find out where we came from 1447 if(!d.config.baseUrl){ 1448 d.config.baseUrl = src.substring(0, m.index); 1449 } 1450 // and find out if we need to modify our behavior 1451 var cfg = (scripts[i].getAttribute("djConfig") || scripts[i].getAttribute("data-dojo-config")); 1452 if(cfg){ 1453 var cfgo = eval("({ "+cfg+" })"); 1454 for(var x in cfgo){ 1455 dojo.config[x] = cfgo[x]; 1456 } 1457 } 1458 break; // "first Dojo wins" 1459 } 1460 } 1461 } 1462 d.baseUrl = d.config.baseUrl; 1463 1464 // fill in the rendering support information in dojo.render.* 1465 var n = navigator; 1466 var dua = n.userAgent, 1467 dav = n.appVersion, 1468 tv = parseFloat(dav); 1469 1470 if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; } 1471 if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; } 1472 d.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : 0; 1473 d.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined; 1474 d.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined; 1475 d.isMac = dav.indexOf("Macintosh") >= 0; 1476 1477 // safari detection derived from: 1478 // http://developer.apple.com/internet/safari/faq.html#anchor2 1479 // http://developer.apple.com/internet/safari/uamatrix.html 1480 var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0); 1481 if(index && !dojo.isChrome){ 1482 // try to grab the explicit Safari version first. If we don't get 1483 // one, look for less than 419.3 as the indication that we're on something 1484 // "Safari 2-ish". 1485 d.isSafari = parseFloat(dav.split("Version/")[1]); 1486 if(!d.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){ 1487 d.isSafari = 2; 1488 } 1489 } 1490 1491 if(dua.indexOf("Gecko") >= 0 && !d.isKhtml && !d.isWebKit){ d.isMozilla = d.isMoz = tv; } 1492 if(d.isMoz){ 1493 //We really need to get away from this. Consider a sane isGecko approach for the future. 1494 d.isFF = parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1]) || undefined; 1495 } 1496 if(document.all && !d.isOpera){ 1497 d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined; 1498 //In cases where the page has an HTTP header or META tag with 1499 //X-UA-Compatible, then it is in emulation mode. 1500 //Make sure isIE reflects the desired version. 1501 //document.documentMode of 5 means quirks mode. 1502 //Only switch the value if documentMode's major version 1503 //is different from isIE's major version. 1504 var mode = document.documentMode; 1505 if(mode && mode != 5 && Math.floor(d.isIE) != mode){ 1506 d.isIE = mode; 1507 } 1508 } 1509 1510 //Workaround to get local file loads of dojo to work on IE 7 1511 //by forcing to not use native xhr. 1512 if(dojo.isIE && window.location.protocol === "file:"){ 1513 dojo.config.ieForceActiveXXhr=true; 1514 } 1515 1516 d.isQuirks = document.compatMode == "BackCompat"; 1517 1518 // TODO: is the HTML LANG attribute relevant? 1519 d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase(); 1520 1521 // These are in order of decreasing likelihood; this will change in time. 1522 d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0']; 1523 1524 d._xhrObj = function(){ 1525 // summary: 1526 // does the work of portably generating a new XMLHTTPRequest object. 1527 var http, last_e; 1528 if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){ 1529 try{ http = new XMLHttpRequest(); }catch(e){} 1530 } 1531 if(!http){ 1532 for(var i=0; i<3; ++i){ 1533 var progid = d._XMLHTTP_PROGIDS[i]; 1534 try{ 1535 http = new ActiveXObject(progid); 1536 }catch(e){ 1537 last_e = e; 1538 } 1539 1540 if(http){ 1541 d._XMLHTTP_PROGIDS = [progid]; // so faster next time 1542 break; 1543 } 1544 } 1545 } 1546 1547 if(!http){ 1548 throw new Error("XMLHTTP not available: "+last_e); 1549 } 1550 1551 return http; // XMLHTTPRequest instance 1552 } 1553 1554 d._isDocumentOk = function(http){ 1555 var stat = http.status || 0, 1556 lp = location.protocol; 1557 return (stat >= 200 && stat < 300) || // Boolean 1558 stat == 304 || // allow any 2XX response code 1559 stat == 1223 || // get it out of the cache 1560 // Internet Explorer mangled the status code 1561 // Internet Explorer mangled the status code OR we're Titanium/browser chrome/chrome extension requesting a local file 1562 (!stat && (lp == "file:" || lp == "chrome:" || lp == "chrome-extension:" || lp == "app:")); 1563 } 1564 1565 //See if base tag is in use. 1566 //This is to fix http://trac.dojotoolkit.org/ticket/3973, 1567 //but really, we need to find out how to get rid of the dojo._Url reference 1568 //below and still have DOH work with the dojo.i18n test following some other 1569 //test that uses the test frame to load a document (trac #2757). 1570 //Opera still has problems, but perhaps a larger issue of base tag support 1571 //with XHR requests (hasBase is true, but the request is still made to document 1572 //path, not base path). 1573 var owloc = window.location+""; 1574 var base = document.getElementsByTagName("base"); 1575 var hasBase = (base && base.length > 0); 1576 1577 d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){ 1578 // summary: Read the contents of the specified uri and return those contents. 1579 // uri: 1580 // A relative or absolute uri. If absolute, it still must be in 1581 // the same "domain" as we are. 1582 // fail_ok: 1583 // Default false. If fail_ok and loading fails, return null 1584 // instead of throwing. 1585 // returns: The response text. null is returned when there is a 1586 // failure and failure is okay (an exception otherwise) 1587 1588 // NOTE: must be declared before scope switches ie. this._xhrObj() 1589 var http = d._xhrObj(); 1590 1591 if(!hasBase && dojo._Url){ 1592 uri = (new dojo._Url(owloc, uri)).toString(); 1593 } 1594 1595 if(d.config.cacheBust){ 1596 //Make sure we have a string before string methods are used on uri 1597 uri += ""; 1598 uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,""); 1599 } 1600 1601 http.open('GET', uri, false); 1602 try{ 1603 http.send(null); 1604 if(!d._isDocumentOk(http)){ 1605 var err = Error("Unable to load "+uri+" status:"+ http.status); 1606 err.status = http.status; 1607 err.responseText = http.responseText; 1608 throw err; 1609 } 1610 }catch(e){ 1611 if(fail_ok){ return null; } // null 1612 // rethrow the exception 1613 throw e; 1614 } 1615 return http.responseText; // String 1616 } 1617 1618 1619 var _w = window; 1620 var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){ 1621 // summary: 1622 // non-destructively adds the specified function to the node's 1623 // evtName handler. 1624 // evtName: should be in the form "onclick" for "onclick" handlers. 1625 // Make sure you pass in the "on" part. 1626 var _a = _w.attachEvent || _w.addEventListener; 1627 evtName = _w.attachEvent ? evtName : evtName.substring(2); 1628 _a(evtName, function(){ 1629 fp.apply(_w, arguments); 1630 }, false); 1631 }; 1632 1633 1634 d._windowUnloaders = []; 1635 1636 d.windowUnloaded = function(){ 1637 // summary: 1638 // signal fired by impending window destruction. You may use 1639 // dojo.addOnWindowUnload() to register a listener for this 1640 // event. NOTE: if you wish to dojo.connect() to this method 1641 // to perform page/application cleanup, be aware that this 1642 // event WILL NOT fire if no handler has been registered with 1643 // dojo.addOnWindowUnload. This behavior started in Dojo 1.3. 1644 // Previous versions always triggered dojo.windowUnloaded. See 1645 // dojo.addOnWindowUnload for more info. 1646 var mll = d._windowUnloaders; 1647 while(mll.length){ 1648 (mll.pop())(); 1649 } 1650 d = null; 1651 }; 1652 1653 var _onWindowUnloadAttached = 0; 1654 d.addOnWindowUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){ 1655 // summary: 1656 // registers a function to be triggered when window.onunload 1657 // fires. 1658 // description: 1659 // The first time that addOnWindowUnload is called Dojo 1660 // will register a page listener to trigger your unload 1661 // handler with. Note that registering these handlers may 1662 // destory "fastback" page caching in browsers that support 1663 // it. Be careful trying to modify the DOM or access 1664 // JavaScript properties during this phase of page unloading: 1665 // they may not always be available. Consider 1666 // dojo.addOnUnload() if you need to modify the DOM or do 1667 // heavy JavaScript work since it fires at the eqivalent of 1668 // the page's "onbeforeunload" event. 1669 // example: 1670 // | dojo.addOnWindowUnload(functionPointer) 1671 // | dojo.addOnWindowUnload(object, "functionName"); 1672 // | dojo.addOnWindowUnload(object, function(){ /* ... */}); 1673 1674 d._onto(d._windowUnloaders, obj, functionName); 1675 if(!_onWindowUnloadAttached){ 1676 _onWindowUnloadAttached = 1; 1677 _handleNodeEvent("onunload", d.windowUnloaded); 1678 } 1679 }; 1680 1681 var _onUnloadAttached = 0; 1682 d.addOnUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){ 1683 // summary: 1684 // registers a function to be triggered when the page unloads. 1685 // description: 1686 // The first time that addOnUnload is called Dojo will 1687 // register a page listener to trigger your unload handler 1688 // with. 1689 // 1690 // In a browser enviroment, the functions will be triggered 1691 // during the window.onbeforeunload event. Be careful of doing 1692 // too much work in an unload handler. onbeforeunload can be 1693 // triggered if a link to download a file is clicked, or if 1694 // the link is a javascript: link. In these cases, the 1695 // onbeforeunload event fires, but the document is not 1696 // actually destroyed. So be careful about doing destructive 1697 // operations in a dojo.addOnUnload callback. 1698 // 1699 // Further note that calling dojo.addOnUnload will prevent 1700 // browsers from using a "fast back" cache to make page 1701 // loading via back button instantaneous. 1702 // example: 1703 // | dojo.addOnUnload(functionPointer) 1704 // | dojo.addOnUnload(object, "functionName") 1705 // | dojo.addOnUnload(object, function(){ /* ... */}); 1706 1707 d._onto(d._unloaders, obj, functionName); 1708 if(!_onUnloadAttached){ 1709 _onUnloadAttached = 1; 1710 _handleNodeEvent("onbeforeunload", dojo.unloaded); 1711 } 1712 }; 1713 1714 })(); 1715 1716 //START DOMContentLoaded 1717 dojo._initFired = false; 1718 dojo._loadInit = function(e){ 1719 if(dojo._scrollIntervalId){ 1720 clearInterval(dojo._scrollIntervalId); 1721 dojo._scrollIntervalId = 0; 1722 } 1723 1724 if(!dojo._initFired){ 1725 dojo._initFired = true; 1726 1727 //Help out IE to avoid memory leak. 1728 if(!dojo.config.afterOnLoad && window.detachEvent){ 1729 window.detachEvent("onload", dojo._loadInit); 1730 } 1731 1732 if(dojo._inFlightCount == 0){ 1733 dojo._modulesLoaded(); 1734 } 1735 } 1736 } 1737 1738 if(!dojo.config.afterOnLoad){ 1739 if(document.addEventListener){ 1740 //Standards. Hooray! Assumption here that if standards based, 1741 //it knows about DOMContentLoaded. It is OK if it does not, the fall through 1742 //to window onload should be good enough. 1743 document.addEventListener("DOMContentLoaded", dojo._loadInit, false); 1744 window.addEventListener("load", dojo._loadInit, false); 1745 }else if(window.attachEvent){ 1746 window.attachEvent("onload", dojo._loadInit); 1747 1748 //DOMContentLoaded approximation. Diego Perini found this MSDN article 1749 //that indicates doScroll is available after DOM ready, so do a setTimeout 1750 //to check when it is available. 1751 //http://msdn.microsoft.com/en-us/library/ms531426.aspx 1752 if(!dojo.config.skipIeDomLoaded && self === self.top){ 1753 dojo._scrollIntervalId = setInterval(function (){ 1754 try{ 1755 //When dojo is loaded into an iframe in an IE HTML Application 1756 //(HTA), such as in a selenium test, javascript in the iframe 1757 //can't see anything outside of it, so self===self.top is true, 1758 //but the iframe is not the top window and doScroll will be 1759 //available before document.body is set. Test document.body 1760 //before trying the doScroll trick 1761 if(document.body){ 1762 document.documentElement.doScroll("left"); 1763 dojo._loadInit(); 1764 } 1765 }catch (e){} 1766 }, 30); 1767 } 1768 } 1769 } 1770 1771 if(dojo.isIE){ 1772 try{ 1773 (function(){ 1774 document.namespaces.add("v", "urn:schemas-microsoft-com:vml"); 1775 var vmlElems = ["*", "group", "roundrect", "oval", "shape", "rect", "imagedata", "path", "textpath", "text"], 1776 i = 0, l = 1, s = document.createStyleSheet(); 1777 if(dojo.isIE >= 8){ 1778 i = 1; 1779 l = vmlElems.length; 1780 } 1781 for(; i < l; ++i){ 1782 s.addRule("v\\:" + vmlElems[i], "behavior:url(#default#VML); display:inline-block"); 1783 } 1784 })(); 1785 }catch(e){} 1786 } 1787 //END DOMContentLoaded 1788 1789 1790 /* 1791 OpenAjax.subscribe("OpenAjax", "onload", function(){ 1792 if(dojo._inFlightCount == 0){ 1793 dojo._modulesLoaded(); 1794 } 1795 }); 1796 1797 OpenAjax.subscribe("OpenAjax", "onunload", function(){ 1798 dojo.unloaded(); 1799 }); 1800 */ 1801 } //if (typeof window != 'undefined') 1802 1803 //Register any module paths set up in djConfig. Need to do this 1804 //in the hostenvs since hostenv_browser can read djConfig from a 1805 //script tag's attribute. 1806 (function(){ 1807 var mp = dojo.config["modulePaths"]; 1808 if(mp){ 1809 for(var param in mp){ 1810 dojo.registerModulePath(param, mp[param]); 1811 } 1812 } 1813 })(); 1814 1815 //Load debug code if necessary. 1816 if(dojo.config.isDebug){ 1817 dojo.require("dojo._firebug.firebug"); 1818 } 1819 1820 if(dojo.config.debugAtAllCosts){ 1821 // this breaks the new AMD based module loader. The XDomain won't be necessary 1822 // anyway if you switch to the asynchronous loader 1823 //dojo.config.useXDomain = true; 1824 //dojo.require("dojo._base._loader.loader_xd"); 1825 dojo.require("dojo._base._loader.loader_debug"); 1826 dojo.require("dojo.i18n"); 1827 } 1828 1829 1830 if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 1831 dojo._hasResource["dojo._base.lang"] = true; 1832 dojo.provide("dojo._base.lang"); 1833 1834 1835 (function(){ 1836 var d = dojo, opts = Object.prototype.toString; 1837 1838 // Crockford (ish) functions 1839 1840 dojo.isString = function(/*anything*/ it){ 1841 // summary: 1842 // Return true if it is a String 1843 return (typeof it == "string" || it instanceof String); // Boolean 1844 }; 1845 1846 dojo.isArray = function(/*anything*/ it){ 1847 // summary: 1848 // Return true if it is an Array. 1849 // Does not work on Arrays created in other windows. 1850 return it && (it instanceof Array || typeof it == "array"); // Boolean 1851 }; 1852 1853 dojo.isFunction = function(/*anything*/ it){ 1854 // summary: 1855 // Return true if it is a Function 1856 return opts.call(it) === "[object Function]"; 1857 }; 1858 1859 dojo.isObject = function(/*anything*/ it){ 1860 // summary: 1861 // Returns true if it is a JavaScript object (or an Array, a Function 1862 // or null) 1863 return it !== undefined && 1864 (it === null || typeof it == "object" || d.isArray(it) || d.isFunction(it)); // Boolean 1865 }; 1866 1867 dojo.isArrayLike = function(/*anything*/ it){ 1868 // summary: 1869 // similar to dojo.isArray() but more permissive 1870 // description: 1871 // Doesn't strongly test for "arrayness". Instead, settles for "isn't 1872 // a string or number and has a length property". Arguments objects 1873 // and DOM collections will return true when passed to 1874 // dojo.isArrayLike(), but will return false when passed to 1875 // dojo.isArray(). 1876 // returns: 1877 // If it walks like a duck and quacks like a duck, return `true` 1878 return it && it !== undefined && // Boolean 1879 // keep out built-in constructors (Number, String, ...) which have length 1880 // properties 1881 !d.isString(it) && !d.isFunction(it) && 1882 !(it.tagName && it.tagName.toLowerCase() == 'form') && 1883 (d.isArray(it) || isFinite(it.length)); 1884 }; 1885 1886 dojo.isAlien = function(/*anything*/ it){ 1887 // summary: 1888 // Returns true if it is a built-in function or some other kind of 1889 // oddball that *should* report as a function but doesn't 1890 return it && !d.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean 1891 }; 1892 1893 dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){ 1894 // summary: 1895 // Adds all properties and methods of props to constructor's 1896 // prototype, making them available to all instances created with 1897 // constructor. 1898 for(var i=1, l=arguments.length; i<l; i++){ 1899 d._mixin(constructor.prototype, arguments[i]); 1900 } 1901 return constructor; // Object 1902 }; 1903 1904 dojo._hitchArgs = function(scope, method /*,...*/){ 1905 var pre = d._toArray(arguments, 2); 1906 var named = d.isString(method); 1907 return function(){ 1908 // arrayify arguments 1909 var args = d._toArray(arguments); 1910 // locate our method 1911 var f = named ? (scope||d.global)[method] : method; 1912 // invoke with collected args 1913 return f && f.apply(scope || this, pre.concat(args)); // mixed 1914 }; // Function 1915 }; 1916 1917 dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){ 1918 // summary: 1919 // Returns a function that will only ever execute in the a given scope. 1920 // This allows for easy use of object member functions 1921 // in callbacks and other places in which the "this" keyword may 1922 // otherwise not reference the expected scope. 1923 // Any number of default positional arguments may be passed as parameters 1924 // beyond "method". 1925 // Each of these values will be used to "placehold" (similar to curry) 1926 // for the hitched function. 1927 // scope: 1928 // The scope to use when method executes. If method is a string, 1929 // scope is also the object containing method. 1930 // method: 1931 // A function to be hitched to scope, or the name of the method in 1932 // scope to be hitched. 1933 // example: 1934 // | dojo.hitch(foo, "bar")(); 1935 // runs foo.bar() in the scope of foo 1936 // example: 1937 // | dojo.hitch(foo, myFunction); 1938 // returns a function that runs myFunction in the scope of foo 1939 // example: 1940 // Expansion on the default positional arguments passed along from 1941 // hitch. Passed args are mixed first, additional args after. 1942 // | var foo = { bar: function(a, b, c){ console.log(a, b, c); } }; 1943 // | var fn = dojo.hitch(foo, "bar", 1, 2); 1944 // | fn(3); // logs "1, 2, 3" 1945 // example: 1946 // | var foo = { bar: 2 }; 1947 // | dojo.hitch(foo, function(){ this.bar = 10; })(); 1948 // execute an anonymous function in scope of foo 1949 1950 if(arguments.length > 2){ 1951 return d._hitchArgs.apply(d, arguments); // Function 1952 } 1953 if(!method){ 1954 method = scope; 1955 scope = null; 1956 } 1957 if(d.isString(method)){ 1958 scope = scope || d.global; 1959 if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); } 1960 return function(){ return scope[method].apply(scope, arguments || []); }; // Function 1961 } 1962 return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function 1963 }; 1964 1965 /*===== 1966 dojo.delegate = function(obj, props){ 1967 // summary: 1968 // Returns a new object which "looks" to obj for properties which it 1969 // does not have a value for. Optionally takes a bag of properties to 1970 // seed the returned object with initially. 1971 // description: 1972 // This is a small implementaton of the Boodman/Crockford delegation 1973 // pattern in JavaScript. An intermediate object constructor mediates 1974 // the prototype chain for the returned object, using it to delegate 1975 // down to obj for property lookup when object-local lookup fails. 1976 // This can be thought of similarly to ES4's "wrap", save that it does 1977 // not act on types but rather on pure objects. 1978 // obj: 1979 // The object to delegate to for properties not found directly on the 1980 // return object or in props. 1981 // props: 1982 // an object containing properties to assign to the returned object 1983 // returns: 1984 // an Object of anonymous type 1985 // example: 1986 // | var foo = { bar: "baz" }; 1987 // | var thinger = dojo.delegate(foo, { thud: "xyzzy"}); 1988 // | thinger.bar == "baz"; // delegated to foo 1989 // | foo.thud == undefined; // by definition 1990 // | thinger.thud == "xyzzy"; // mixed in from props 1991 // | foo.bar = "thonk"; 1992 // | thinger.bar == "thonk"; // still delegated to foo's bar 1993 } 1994 =====*/ 1995 1996 dojo.delegate = dojo._delegate = (function(){ 1997 // boodman/crockford delegation w/ cornford optimization 1998 function TMP(){} 1999 return function(obj, props){ 2000 TMP.prototype = obj; 2001 var tmp = new TMP(); 2002 TMP.prototype = null; 2003 if(props){ 2004 d._mixin(tmp, props); 2005 } 2006 return tmp; // Object 2007 }; 2008 })(); 2009 2010 /*===== 2011 dojo._toArray = function(obj, offset, startWith){ 2012 // summary: 2013 // Converts an array-like object (i.e. arguments, DOMCollection) to an 2014 // array. Returns a new Array with the elements of obj. 2015 // obj: Object 2016 // the object to "arrayify". We expect the object to have, at a 2017 // minimum, a length property which corresponds to integer-indexed 2018 // properties. 2019 // offset: Number? 2020 // the location in obj to start iterating from. Defaults to 0. 2021 // Optional. 2022 // startWith: Array? 2023 // An array to pack with the properties of obj. If provided, 2024 // properties in obj are appended at the end of startWith and 2025 // startWith is the returned array. 2026 } 2027 =====*/ 2028 2029 var efficient = function(obj, offset, startWith){ 2030 return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0)); 2031 }; 2032 2033 var slow = function(obj, offset, startWith){ 2034 var arr = startWith||[]; 2035 for(var x = offset || 0; x < obj.length; x++){ 2036 arr.push(obj[x]); 2037 } 2038 return arr; 2039 }; 2040 2041 dojo._toArray = 2042 d.isIE ? function(obj){ 2043 return ((obj.item) ? slow : efficient).apply(this, arguments); 2044 } : 2045 efficient; 2046 2047 dojo.partial = function(/*Function|String*/method /*, ...*/){ 2048 // summary: 2049 // similar to hitch() except that the scope object is left to be 2050 // whatever the execution context eventually becomes. 2051 // description: 2052 // Calling dojo.partial is the functional equivalent of calling: 2053 // | dojo.hitch(null, funcName, ...); 2054 var arr = [ null ]; 2055 return d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function 2056 }; 2057 2058 var extraNames = d._extraNames, extraLen = extraNames.length, empty = {}; 2059 2060 dojo.clone = function(/*anything*/ o){ 2061 // summary: 2062 // Clones objects (including DOM nodes) and all children. 2063 // Warning: do not clone cyclic structures. 2064 if(!o || typeof o != "object" || d.isFunction(o)){ 2065 // null, undefined, any non-object, or function 2066 return o; // anything 2067 } 2068 if(o.nodeType && "cloneNode" in o){ 2069 // DOM Node 2070 return o.cloneNode(true); // Node 2071 } 2072 if(o instanceof Date){ 2073 // Date 2074 return new Date(o.getTime()); // Date 2075 } 2076 if(o instanceof RegExp){ 2077 // RegExp 2078 return new RegExp(o); // RegExp 2079 } 2080 var r, i, l, s, name; 2081 if(d.isArray(o)){ 2082 // array 2083 r = []; 2084 for(i = 0, l = o.length; i < l; ++i){ 2085 if(i in o){ 2086 r.push(d.clone(o[i])); 2087 } 2088 } 2089 // we don't clone functions for performance reasons 2090 // }else if(d.isFunction(o)){ 2091 // // function 2092 // r = function(){ return o.apply(this, arguments); }; 2093 }else{ 2094 // generic objects 2095 r = o.constructor ? new o.constructor() : {}; 2096 } 2097 for(name in o){ 2098 // the "tobj" condition avoid copying properties in "source" 2099 // inherited from Object.prototype. For example, if target has a custom 2100 // toString() method, don't overwrite it with the toString() method 2101 // that source inherited from Object.prototype 2102 s = o[name]; 2103 if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){ 2104 r[name] = d.clone(s); 2105 } 2106 } 2107 // IE doesn't recognize some custom functions in for..in 2108 if(extraLen){ 2109 for(i = 0; i < extraLen; ++i){ 2110 name = extraNames[i]; 2111 s = o[name]; 2112 if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){ 2113 r[name] = s; // functions only, we don't clone them 2114 } 2115 } 2116 } 2117 return r; // Object 2118 }; 2119 2120 /*===== 2121 dojo.trim = function(str){ 2122 // summary: 2123 // Trims whitespace from both sides of the string 2124 // str: String 2125 // String to be trimmed 2126 // returns: String 2127 // Returns the trimmed string 2128 // description: 2129 // This version of trim() was selected for inclusion into the base due 2130 // to its compact size and relatively good performance 2131 // (see [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript) 2132 // Uses String.prototype.trim instead, if available. 2133 // The fastest but longest version of this function is located at 2134 // dojo.string.trim() 2135 return ""; // String 2136 } 2137 =====*/ 2138 2139 dojo.trim = String.prototype.trim ? 2140 function(str){ return str.trim(); } : 2141 function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; 2142 2143 /*===== 2144 dojo.replace = function(tmpl, map, pattern){ 2145 // summary: 2146 // Performs parameterized substitutions on a string. Throws an 2147 // exception if any parameter is unmatched. 2148 // tmpl: String 2149 // String to be used as a template. 2150 // map: Object|Function 2151 // If an object, it is used as a dictionary to look up substitutions. 2152 // If a function, it is called for every substitution with following 2153 // parameters: a whole match, a name, an offset, and the whole template 2154 // string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace 2155 // for more details). 2156 // pattern: RegEx? 2157 // Optional regular expression objects that overrides the default pattern. 2158 // Must be global and match one item. The default is: /\{([^\}]+)\}/g, 2159 // which matches patterns like that: "{xxx}", where "xxx" is any sequence 2160 // of characters, which doesn't include "}". 2161 // returns: String 2162 // Returns the substituted string. 2163 // example: 2164 // | // uses a dictionary for substitutions: 2165 // | dojo.replace("Hello, {name.first} {name.last} AKA {nick}!", 2166 // | { 2167 // | nick: "Bob", 2168 // | name: { 2169 // | first: "Robert", 2170 // | middle: "X", 2171 // | last: "Cringely" 2172 // | } 2173 // | }); 2174 // | // returns: Hello, Robert Cringely AKA Bob! 2175 // example: 2176 // | // uses an array for substitutions: 2177 // | dojo.replace("Hello, {0} {2}!", 2178 // | ["Robert", "X", "Cringely"]); 2179 // | // returns: Hello, Robert Cringely! 2180 // example: 2181 // | // uses a function for substitutions: 2182 // | function sum(a){ 2183 // | var t = 0; 2184 // | dojo.forEach(a, function(x){ t += x; }); 2185 // | return t; 2186 // | } 2187 // | dojo.replace( 2188 // | "{count} payments averaging {avg} USD per payment.", 2189 // | dojo.hitch( 2190 // | { payments: [11, 16, 12] }, 2191 // | function(_, key){ 2192 // | switch(key){ 2193 // | case "count": return this.payments.length; 2194 // | case "min": return Math.min.apply(Math, this.payments); 2195 // | case "max": return Math.max.apply(Math, this.payments); 2196 // | case "sum": return sum(this.payments); 2197 // | case "avg": return sum(this.payments) / this.payments.length; 2198 // | } 2199 // | } 2200 // | ) 2201 // | ); 2202 // | // prints: 3 payments averaging 13 USD per payment. 2203 // example: 2204 // | // uses an alternative PHP-like pattern for substitutions: 2205 // | dojo.replace("Hello, ${0} ${2}!", 2206 // | ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g); 2207 // | // returns: Hello, Robert Cringely! 2208 return ""; // String 2209 } 2210 =====*/ 2211 2212 var _pattern = /\{([^\}]+)\}/g; 2213 dojo.replace = function(tmpl, map, pattern){ 2214 return tmpl.replace(pattern || _pattern, d.isFunction(map) ? 2215 map : function(_, k){ return d.getObject(k, false, map); }); 2216 }; 2217 })(); 2218 2219 } 2220 2221 if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 2222 dojo._hasResource["dojo._base.array"] = true; 2223 dojo.provide("dojo._base.array"); 2224 2225 2226 2227 (function(){ 2228 var _getParts = function(arr, obj, cb){ 2229 return [ 2230 (typeof arr == "string") ? arr.split("") : arr, 2231 obj || dojo.global, 2232 // FIXME: cache the anonymous functions we create here? 2233 (typeof cb == "string") ? new Function("item", "index", "array", cb) : cb 2234 ]; 2235 }; 2236 2237 var everyOrSome = function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){ 2238 var _p = _getParts(arr, thisObject, callback); arr = _p[0]; 2239 for(var i=0,l=arr.length; i<l; ++i){ 2240 var result = !!_p[2].call(_p[1], arr[i], i, arr); 2241 if(every ^ result){ 2242 return result; // Boolean 2243 } 2244 } 2245 return every; // Boolean 2246 }; 2247 2248 dojo.mixin(dojo, { 2249 indexOf: function( /*Array*/ array, 2250 /*Object*/ value, 2251 /*Integer?*/ fromIndex, 2252 /*Boolean?*/ findLast){ 2253 // summary: 2254 // locates the first index of the provided value in the 2255 // passed array. If the value is not found, -1 is returned. 2256 // description: 2257 // This method corresponds to the JavaScript 1.6 Array.indexOf method, with one difference: when 2258 // run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript 2259 // 1.6's indexOf skips the holes in the sparse array. 2260 // For details on this method, see: 2261 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/indexOf 2262 2263 var step = 1, end = array.length || 0, i = 0; 2264 if(findLast){ 2265 i = end - 1; 2266 step = end = -1; 2267 } 2268 if(fromIndex != undefined){ i = fromIndex; } 2269 if((findLast && i > end) || i < end){ 2270 for(; i != end; i += step){ 2271 if(array[i] == value){ return i; } 2272 } 2273 } 2274 return -1; // Number 2275 }, 2276 2277 lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){ 2278 // summary: 2279 // locates the last index of the provided value in the passed 2280 // array. If the value is not found, -1 is returned. 2281 // description: 2282 // This method corresponds to the JavaScript 1.6 Array.lastIndexOf method, with one difference: when 2283 // run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript 2284 // 1.6's lastIndexOf skips the holes in the sparse array. 2285 // For details on this method, see: 2286 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/lastIndexOf 2287 return dojo.indexOf(array, value, fromIndex, true); // Number 2288 }, 2289 2290 forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){ 2291 // summary: 2292 // for every item in arr, callback is invoked. Return values are ignored. 2293 // If you want to break out of the loop, consider using dojo.every() or dojo.some(). 2294 // forEach does not allow breaking out of the loop over the items in arr. 2295 // arr: 2296 // the array to iterate over. If a string, operates on individual characters. 2297 // callback: 2298 // a function is invoked with three arguments: item, index, and array 2299 // thisObject: 2300 // may be used to scope the call to callback 2301 // description: 2302 // This function corresponds to the JavaScript 1.6 Array.forEach() method, with one difference: when 2303 // run over sparse arrays, this implemenation passes the "holes" in the sparse array to 2304 // the callback function with a value of undefined. JavaScript 1.6's forEach skips the holes in the sparse array. 2305 // For more details, see: 2306 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach 2307 // example: 2308 // | // log out all members of the array: 2309 // | dojo.forEach( 2310 // | [ "thinger", "blah", "howdy", 10 ], 2311 // | function(item){ 2312 // | console.log(item); 2313 // | } 2314 // | ); 2315 // example: 2316 // | // log out the members and their indexes 2317 // | dojo.forEach( 2318 // | [ "thinger", "blah", "howdy", 10 ], 2319 // | function(item, idx, arr){ 2320 // | console.log(item, "at index:", idx); 2321 // | } 2322 // | ); 2323 // example: 2324 // | // use a scoped object member as the callback 2325 // | 2326 // | var obj = { 2327 // | prefix: "logged via obj.callback:", 2328 // | callback: function(item){ 2329 // | console.log(this.prefix, item); 2330 // | } 2331 // | }; 2332 // | 2333 // | // specifying the scope function executes the callback in that scope 2334 // | dojo.forEach( 2335 // | [ "thinger", "blah", "howdy", 10 ], 2336 // | obj.callback, 2337 // | obj 2338 // | ); 2339 // | 2340 // | // alternately, we can accomplish the same thing with dojo.hitch() 2341 // | dojo.forEach( 2342 // | [ "thinger", "blah", "howdy", 10 ], 2343 // | dojo.hitch(obj, "callback") 2344 // | ); 2345 2346 // match the behavior of the built-in forEach WRT empty arrs 2347 if(!arr || !arr.length){ return; } 2348 2349 // FIXME: there are several ways of handilng thisObject. Is 2350 // dojo.global always the default context? 2351 var _p = _getParts(arr, thisObject, callback); arr = _p[0]; 2352 for(var i=0,l=arr.length; i<l; ++i){ 2353 _p[2].call(_p[1], arr[i], i, arr); 2354 } 2355 }, 2356 2357 every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){ 2358 // summary: 2359 // Determines whether or not every item in arr satisfies the 2360 // condition implemented by callback. 2361 // arr: 2362 // the array to iterate on. If a string, operates on individual characters. 2363 // callback: 2364 // a function is invoked with three arguments: item, index, 2365 // and array and returns true if the condition is met. 2366 // thisObject: 2367 // may be used to scope the call to callback 2368 // description: 2369 // This function corresponds to the JavaScript 1.6 Array.every() method, with one difference: when 2370 // run over sparse arrays, this implemenation passes the "holes" in the sparse array to 2371 // the callback function with a value of undefined. JavaScript 1.6's every skips the holes in the sparse array. 2372 // For more details, see: 2373 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/every 2374 // example: 2375 // | // returns false 2376 // | dojo.every([1, 2, 3, 4], function(item){ return item>1; }); 2377 // example: 2378 // | // returns true 2379 // | dojo.every([1, 2, 3, 4], function(item){ return item>0; }); 2380 return everyOrSome(true, arr, callback, thisObject); // Boolean 2381 }, 2382 2383 some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){ 2384 // summary: 2385 // Determines whether or not any item in arr satisfies the 2386 // condition implemented by callback. 2387 // arr: 2388 // the array to iterate over. If a string, operates on individual characters. 2389 // callback: 2390 // a function is invoked with three arguments: item, index, 2391 // and array and returns true if the condition is met. 2392 // thisObject: 2393 // may be used to scope the call to callback 2394 // description: 2395 // This function corresponds to the JavaScript 1.6 Array.some() method, with one difference: when 2396 // run over sparse arrays, this implemenation passes the "holes" in the sparse array to 2397 // the callback function with a value of undefined. JavaScript 1.6's some skips the holes in the sparse array. 2398 // For more details, see: 2399 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/some 2400 // example: 2401 // | // is true 2402 // | dojo.some([1, 2, 3, 4], function(item){ return item>1; }); 2403 // example: 2404 // | // is false 2405 // | dojo.some([1, 2, 3, 4], function(item){ return item<1; }); 2406 return everyOrSome(false, arr, callback, thisObject); // Boolean 2407 }, 2408 2409 map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){ 2410 // summary: 2411 // applies callback to each element of arr and returns 2412 // an Array with the results 2413 // arr: 2414 // the array to iterate on. If a string, operates on 2415 // individual characters. 2416 // callback: 2417 // a function is invoked with three arguments, (item, index, 2418 // array), and returns a value 2419 // thisObject: 2420 // may be used to scope the call to callback 2421 // description: 2422 // This function corresponds to the JavaScript 1.6 Array.map() method, with one difference: when 2423 // run over sparse arrays, this implemenation passes the "holes" in the sparse array to 2424 // the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array. 2425 // For more details, see: 2426 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map 2427 // example: 2428 // | // returns [2, 3, 4, 5] 2429 // | dojo.map([1, 2, 3, 4], function(item){ return item+1 }); 2430 2431 var _p = _getParts(arr, thisObject, callback); arr = _p[0]; 2432 var outArr = (arguments[3] ? (new arguments[3]()) : []); 2433 for(var i=0,l=arr.length; i<l; ++i){ 2434 outArr.push(_p[2].call(_p[1], arr[i], i, arr)); 2435 } 2436 return outArr; // Array 2437 }, 2438 2439 filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){ 2440 // summary: 2441 // Returns a new Array with those items from arr that match the 2442 // condition implemented by callback. 2443 // arr: 2444 // the array to iterate over. 2445 // callback: 2446 // a function that is invoked with three arguments (item, 2447 // index, array). The return of this function is expected to 2448 // be a boolean which determines whether the passed-in item 2449 // will be included in the returned array. 2450 // thisObject: 2451 // may be used to scope the call to callback 2452 // description: 2453 // This function corresponds to the JavaScript 1.6 Array.filter() method, with one difference: when 2454 // run over sparse arrays, this implemenation passes the "holes" in the sparse array to 2455 // the callback function with a value of undefined. JavaScript 1.6's filter skips the holes in the sparse array. 2456 // For more details, see: 2457 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter 2458 // example: 2459 // | // returns [2, 3, 4] 2460 // | dojo.filter([1, 2, 3, 4], function(item){ return item>1; }); 2461 2462 var _p = _getParts(arr, thisObject, callback); arr = _p[0]; 2463 var outArr = []; 2464 for(var i=0,l=arr.length; i<l; ++i){ 2465 if(_p[2].call(_p[1], arr[i], i, arr)){ 2466 outArr.push(arr[i]); 2467 } 2468 } 2469 return outArr; // Array 2470 } 2471 }); 2472 })(); 2473 /* 2474 */ 2475 2476 } 2477 2478 if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 2479 dojo._hasResource["dojo._base.declare"] = true; 2480 dojo.provide("dojo._base.declare"); 2481 2482 2483 2484 2485 (function(){ 2486 var d = dojo, mix = d._mixin, op = Object.prototype, opts = op.toString, 2487 xtor = new Function, counter = 0, cname = "constructor"; 2488 2489 function err(msg, cls){ throw new Error("declare" + (cls ? " " + cls : "") + ": " + msg); } 2490 2491 // C3 Method Resolution Order (see http://www.python.org/download/releases/2.3/mro/) 2492 function c3mro(bases, className){ 2493 var result = [], roots = [{cls: 0, refs: []}], nameMap = {}, clsCount = 1, 2494 l = bases.length, i = 0, j, lin, base, top, proto, rec, name, refs; 2495 2496 // build a list of bases naming them if needed 2497 for(; i < l; ++i){ 2498 base = bases[i]; 2499 if(!base){ 2500 err("mixin #" + i + " is unknown. Did you use dojo.require to pull it in?", className); 2501 }else if(opts.call(base) != "[object Function]"){ 2502 err("mixin #" + i + " is not a callable constructor.", className); 2503 } 2504 lin = base._meta ? base._meta.bases : [base]; 2505 top = 0; 2506 // add bases to the name map 2507 for(j = lin.length - 1; j >= 0; --j){ 2508 proto = lin[j].prototype; 2509 if(!proto.hasOwnProperty("declaredClass")){ 2510 proto.declaredClass = "uniqName_" + (counter++); 2511 } 2512 name = proto.declaredClass; 2513 if(!nameMap.hasOwnProperty(name)){ 2514 nameMap[name] = {count: 0, refs: [], cls: lin[j]}; 2515 ++clsCount; 2516 } 2517 rec = nameMap[name]; 2518 if(top && top !== rec){ 2519 rec.refs.push(top); 2520 ++top.count; 2521 } 2522 top = rec; 2523 } 2524 ++top.count; 2525 roots[0].refs.push(top); 2526 } 2527 2528 // remove classes without external references recursively 2529 while(roots.length){ 2530 top = roots.pop(); 2531 result.push(top.cls); 2532 --clsCount; 2533 // optimization: follow a single-linked chain 2534 while(refs = top.refs, refs.length == 1){ 2535 top = refs[0]; 2536 if(!top || --top.count){ 2537 // branch or end of chain => do not end to roots 2538 top = 0; 2539 break; 2540 } 2541 result.push(top.cls); 2542 --clsCount; 2543 } 2544 if(top){ 2545 // branch 2546 for(i = 0, l = refs.length; i < l; ++i){ 2547 top = refs[i]; 2548 if(!--top.count){ 2549 roots.push(top); 2550 } 2551 } 2552 } 2553 } 2554 if(clsCount){ 2555 err("can't build consistent linearization", className); 2556 } 2557 2558 // calculate the superclass offset 2559 base = bases[0]; 2560 result[0] = base ? 2561 base._meta && base === result[result.length - base._meta.bases.length] ? 2562 base._meta.bases.length : 1 : 0; 2563 2564 return result; 2565 } 2566 2567 function inherited(args, a, f){ 2568 var name, chains, bases, caller, meta, base, proto, opf, pos, 2569 cache = this._inherited = this._inherited || {}; 2570 2571 // crack arguments 2572 if(typeof args == "string"){ 2573 name = args; 2574 args = a; 2575 a = f; 2576 } 2577 f = 0; 2578 2579 caller = args.callee; 2580 name = name || caller.nom; 2581 if(!name){ 2582 err("can't deduce a name to call inherited()", this.declaredClass); 2583 } 2584 2585 meta = this.constructor._meta; 2586 bases = meta.bases; 2587 2588 pos = cache.p; 2589 if(name != cname){ 2590 // method 2591 if(cache.c !== caller){ 2592 // cache bust 2593 pos = 0; 2594 base = bases[0]; 2595 meta = base._meta; 2596 if(meta.hidden[name] !== caller){ 2597 // error detection 2598 chains = meta.chains; 2599 if(chains && typeof chains[name] == "string"){ 2600 err("calling chained method with inherited: " + name, this.declaredClass); 2601 } 2602 // find caller 2603 do{ 2604 meta = base._meta; 2605 proto = base.prototype; 2606 if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){ 2607 break; 2608 } 2609 }while(base = bases[++pos]); // intentional assignment 2610 pos = base ? pos : -1; 2611 } 2612 } 2613 // find next 2614 base = bases[++pos]; 2615 if(base){ 2616 proto = base.prototype; 2617 if(base._meta && proto.hasOwnProperty(name)){ 2618 f = proto[name]; 2619 }else{ 2620 opf = op[name]; 2621 do{ 2622 proto = base.prototype; 2623 f = proto[name]; 2624 if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){ 2625 break; 2626 } 2627 }while(base = bases[++pos]); // intentional assignment 2628 } 2629 } 2630 f = base && f || op[name]; 2631 }else{ 2632 // constructor 2633 if(cache.c !== caller){ 2634 // cache bust 2635 pos = 0; 2636 meta = bases[0]._meta; 2637 if(meta && meta.ctor !== caller){ 2638 // error detection 2639 chains = meta.chains; 2640 if(!chains || chains.constructor !== "manual"){ 2641 err("calling chained constructor with inherited", this.declaredClass); 2642 } 2643 // find caller 2644 while(base = bases[++pos]){ // intentional assignment 2645 meta = base._meta; 2646 if(meta && meta.ctor === caller){ 2647 break; 2648 } 2649 } 2650 pos = base ? pos : -1; 2651 } 2652 } 2653 // find next 2654 while(base = bases[++pos]){ // intentional assignment 2655 meta = base._meta; 2656 f = meta ? meta.ctor : base; 2657 if(f){ 2658 break; 2659 } 2660 } 2661 f = base && f; 2662 } 2663 2664 // cache the found super method 2665 cache.c = f; 2666 cache.p = pos; 2667 2668 // now we have the result 2669 if(f){ 2670 return a === true ? f : f.apply(this, a || args); 2671 } 2672 // intentionally if a super method was not found 2673 } 2674 2675 function getInherited(name, args){ 2676 if(typeof name == "string"){ 2677 return this.inherited(name, args, true); 2678 } 2679 return this.inherited(name, true); 2680 } 2681 2682 // emulation of "instanceof" 2683 function isInstanceOf(cls){ 2684 var bases = this.constructor._meta.bases; 2685 for(var i = 0, l = bases.length; i < l; ++i){ 2686 if(bases[i] === cls){ 2687 return true; 2688 } 2689 } 2690 return this instanceof cls; 2691 } 2692 2693 function mixOwn(target, source){ 2694 var name, i = 0, l = d._extraNames.length; 2695 // add props adding metadata for incoming functions skipping a constructor 2696 for(name in source){ 2697 if(name != cname && source.hasOwnProperty(name)){ 2698 target[name] = source[name]; 2699 } 2700 } 2701 // process unenumerable methods on IE 2702 for(; i < l; ++i){ 2703 name = d._extraNames[i]; 2704 if(name != cname && source.hasOwnProperty(name)){ 2705 target[name] = source[name]; 2706 } 2707 } 2708 } 2709 2710 // implementation of safe mixin function 2711 function safeMixin(target, source){ 2712 var name, t, i = 0, l = d._extraNames.length; 2713 // add props adding metadata for incoming functions skipping a constructor 2714 for(name in source){ 2715 t = source[name]; 2716 if((t !== op[name] || !(name in op)) && name != cname){ 2717 if(opts.call(t) == "[object Function]"){ 2718 // non-trivial function method => attach its name 2719 t.nom = name; 2720 } 2721 target[name] = t; 2722 } 2723 } 2724 // process unenumerable methods on IE 2725 for(; i < l; ++i){ 2726 name = d._extraNames[i]; 2727 t = source[name]; 2728 if((t !== op[name] || !(name in op)) && name != cname){ 2729 if(opts.call(t) == "[object Function]"){ 2730 // non-trivial function method => attach its name 2731 t.nom = name; 2732 } 2733 target[name] = t; 2734 } 2735 } 2736 return target; 2737 } 2738 2739 function extend(source){ 2740 safeMixin(this.prototype, source); 2741 return this; 2742 } 2743 2744 // chained constructor compatible with the legacy dojo.declare() 2745 function chainedConstructor(bases, ctorSpecial){ 2746 return function(){ 2747 var a = arguments, args = a, a0 = a[0], f, i, m, 2748 l = bases.length, preArgs; 2749 2750 if(!(this instanceof a.callee)){ 2751 // not called via new, so force it 2752 return applyNew(a); 2753 } 2754 2755 //this._inherited = {}; 2756 // perform the shaman's rituals of the original dojo.declare() 2757 // 1) call two types of the preamble 2758 if(ctorSpecial && (a0 && a0.preamble || this.preamble)){ 2759 // full blown ritual 2760 preArgs = new Array(bases.length); 2761 // prepare parameters 2762 preArgs[0] = a; 2763 for(i = 0;;){ 2764 // process the preamble of the 1st argument 2765 a0 = a[0]; 2766 if(a0){ 2767 f = a0.preamble; 2768 if(f){ 2769 a = f.apply(this, a) || a; 2770 } 2771 } 2772 // process the preamble of this class 2773 f = bases[i].prototype; 2774 f = f.hasOwnProperty("preamble") && f.preamble; 2775 if(f){ 2776 a = f.apply(this, a) || a; 2777 } 2778 // one peculiarity of the preamble: 2779 // it is called if it is not needed, 2780 // e.g., there is no constructor to call 2781 // let's watch for the last constructor 2782 // (see ticket #9795) 2783 if(++i == l){ 2784 break; 2785 } 2786 preArgs[i] = a; 2787 } 2788 } 2789 // 2) call all non-trivial constructors using prepared arguments 2790 for(i = l - 1; i >= 0; --i){ 2791 f = bases[i]; 2792 m = f._meta; 2793 f = m ? m.ctor : f; 2794 if(f){ 2795 f.apply(this, preArgs ? preArgs[i] : a); 2796 } 2797 } 2798 // 3) continue the original ritual: call the postscript 2799 f = this.postscript; 2800 if(f){ 2801 f.apply(this, args); 2802 } 2803 }; 2804 } 2805 2806 2807 // chained constructor compatible with the legacy dojo.declare() 2808 function singleConstructor(ctor, ctorSpecial){ 2809 return function(){ 2810 var a = arguments, t = a, a0 = a[0], f; 2811 2812 if(!(this instanceof a.callee)){ 2813 // not called via new, so force it 2814 return applyNew(a); 2815 } 2816 2817 //this._inherited = {}; 2818 // perform the shaman's rituals of the original dojo.declare() 2819 // 1) call two types of the preamble 2820 if(ctorSpecial){ 2821 // full blown ritual 2822 if(a0){ 2823 // process the preamble of the 1st argument 2824 f = a0.preamble; 2825 if(f){ 2826 t = f.apply(this, t) || t; 2827 } 2828 } 2829 f = this.preamble; 2830 if(f){ 2831 // process the preamble of this class 2832 f.apply(this, t); 2833 // one peculiarity of the preamble: 2834 // it is called even if it is not needed, 2835 // e.g., there is no constructor to call 2836 // let's watch for the last constructor 2837 // (see ticket #9795) 2838 } 2839 } 2840 // 2) call a constructor 2841 if(ctor){ 2842 ctor.apply(this, a); 2843 } 2844 // 3) continue the original ritual: call the postscript 2845 f = this.postscript; 2846 if(f){ 2847 f.apply(this, a); 2848 } 2849 }; 2850 } 2851 2852 // plain vanilla constructor (can use inherited() to call its base constructor) 2853 function simpleConstructor(bases){ 2854 return function(){ 2855 var a = arguments, i = 0, f, m; 2856 2857 if(!(this instanceof a.callee)){ 2858 // not called via new, so force it 2859 return applyNew(a); 2860 } 2861 2862 //this._inherited = {}; 2863 // perform the shaman's rituals of the original dojo.declare() 2864 // 1) do not call the preamble 2865 // 2) call the top constructor (it can use this.inherited()) 2866 for(; f = bases[i]; ++i){ // intentional assignment 2867 m = f._meta; 2868 f = m ? m.ctor : f; 2869 if(f){ 2870 f.apply(this, a); 2871 break; 2872 } 2873 } 2874 // 3) call the postscript 2875 f = this.postscript; 2876 if(f){ 2877 f.apply(this, a); 2878 } 2879 }; 2880 } 2881 2882 function chain(name, bases, reversed){ 2883 return function(){ 2884 var b, m, f, i = 0, step = 1; 2885 if(reversed){ 2886 i = bases.length - 1; 2887 step = -1; 2888 } 2889 for(; b = bases[i]; i += step){ // intentional assignment 2890 m = b._meta; 2891 f = (m ? m.hidden : b.prototype)[name]; 2892 if(f){ 2893 f.apply(this, arguments); 2894 } 2895 } 2896 }; 2897 } 2898 2899 // forceNew(ctor) 2900 // return a new object that inherits from ctor.prototype but 2901 // without actually running ctor on the object. 2902 function forceNew(ctor){ 2903 // create object with correct prototype using a do-nothing 2904 // constructor 2905 xtor.prototype = ctor.prototype; 2906 var t = new xtor; 2907 xtor.prototype = null; // clean up 2908 return t; 2909 } 2910 2911 // applyNew(args) 2912 // just like 'new ctor()' except that the constructor and its arguments come 2913 // from args, which must be an array or an arguments object 2914 function applyNew(args){ 2915 // create an object with ctor's prototype but without 2916 // calling ctor on it. 2917 var ctor = args.callee, t = forceNew(ctor); 2918 // execute the real constructor on the new object 2919 ctor.apply(t, args); 2920 return t; 2921 } 2922 2923 d.declare = function(className, superclass, props){ 2924 // crack parameters 2925 if(typeof className != "string"){ 2926 props = superclass; 2927 superclass = className; 2928 className = ""; 2929 } 2930 props = props || {}; 2931 2932 var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass; 2933 2934 // build a prototype 2935 if(opts.call(superclass) == "[object Array]"){ 2936 // C3 MRO 2937 bases = c3mro(superclass, className); 2938 t = bases[0]; 2939 mixins = bases.length - t; 2940 superclass = bases[mixins]; 2941 }else{ 2942 bases = [0]; 2943 if(superclass){ 2944 if(opts.call(superclass) == "[object Function]"){ 2945 t = superclass._meta; 2946 bases = bases.concat(t ? t.bases : superclass); 2947 }else{ 2948 err("base class is not a callable constructor.", className); 2949 } 2950 }else if(superclass !== null){ 2951 err("unknown base class. Did you use dojo.require to pull it in?", className); 2952 } 2953 } 2954 if(superclass){ 2955 for(i = mixins - 1;; --i){ 2956 proto = forceNew(superclass); 2957 if(!i){ 2958 // stop if nothing to add (the last base) 2959 break; 2960 } 2961 // mix in properties 2962 t = bases[i]; 2963 (t._meta ? mixOwn : mix)(proto, t.prototype); 2964 // chain in new constructor 2965 ctor = new Function; 2966 ctor.superclass = superclass; 2967 ctor.prototype = proto; 2968 superclass = proto.constructor = ctor; 2969 } 2970 }else{ 2971 proto = {}; 2972 } 2973 // add all properties 2974 safeMixin(proto, props); 2975 // add constructor 2976 t = props.constructor; 2977 if(t !== op.constructor){ 2978 t.nom = cname; 2979 proto.constructor = t; 2980 } 2981 2982 // collect chains and flags 2983 for(i = mixins - 1; i; --i){ // intentional assignment 2984 t = bases[i]._meta; 2985 if(t && t.chains){ 2986 chains = mix(chains || {}, t.chains); 2987 } 2988 } 2989 if(proto["-chains-"]){ 2990 chains = mix(chains || {}, proto["-chains-"]); 2991 } 2992 2993 // build ctor 2994 t = !chains || !chains.hasOwnProperty(cname); 2995 bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) : 2996 (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t)); 2997 2998 // add meta information to the constructor 2999 ctor._meta = {bases: bases, hidden: props, chains: chains, 3000 parents: parents, ctor: props.constructor}; 3001 ctor.superclass = superclass && superclass.prototype; 3002 ctor.extend = extend; 3003 ctor.prototype = proto; 3004 proto.constructor = ctor; 3005 3006 // add "standard" methods to the prototype 3007 proto.getInherited = getInherited; 3008 proto.inherited = inherited; 3009 proto.isInstanceOf = isInstanceOf; 3010 3011 // add name if specified 3012 if(className){ 3013 proto.declaredClass = className; 3014 d.setObject(className, ctor); 3015 } 3016 3017 // build chains and add them to the prototype 3018 if(chains){ 3019 for(name in chains){ 3020 if(proto[name] && typeof chains[name] == "string" && name != cname){ 3021 t = proto[name] = chain(name, bases, chains[name] === "after"); 3022 t.nom = name; 3023 } 3024 } 3025 } 3026 // chained methods do not return values 3027 // no need to chain "invisible" functions 3028 3029 return ctor; // Function 3030 }; 3031 3032 d.safeMixin = safeMixin; 3033 3034 /*===== 3035 dojo.declare = function(className, superclass, props){ 3036 // summary: 3037 // Create a feature-rich constructor from compact notation. 3038 // className: String?: 3039 // The optional name of the constructor (loosely, a "class") 3040 // stored in the "declaredClass" property in the created prototype. 3041 // It will be used as a global name for a created constructor. 3042 // superclass: Function|Function[]: 3043 // May be null, a Function, or an Array of Functions. This argument 3044 // specifies a list of bases (the left-most one is the most deepest 3045 // base). 3046 // props: Object: 3047 // An object whose properties are copied to the created prototype. 3048 // Add an instance-initialization function by making it a property 3049 // named "constructor". 3050 // returns: 3051 // New constructor function. 3052 // description: 3053 // Create a constructor using a compact notation for inheritance and 3054 // prototype extension. 3055 // 3056 // Mixin ancestors provide a type of multiple inheritance. 3057 // Prototypes of mixin ancestors are copied to the new class: 3058 // changes to mixin prototypes will not affect classes to which 3059 // they have been mixed in. 3060 // 3061 // Ancestors can be compound classes created by this version of 3062 // dojo.declare. In complex cases all base classes are going to be 3063 // linearized according to C3 MRO algorithm 3064 // (see http://www.python.org/download/releases/2.3/mro/ for more 3065 // details). 3066 // 3067 // "className" is cached in "declaredClass" property of the new class, 3068 // if it was supplied. The immediate super class will be cached in 3069 // "superclass" property of the new class. 3070 // 3071 // Methods in "props" will be copied and modified: "nom" property 3072 // (the declared name of the method) will be added to all copied 3073 // functions to help identify them for the internal machinery. Be 3074 // very careful, while reusing methods: if you use the same 3075 // function under different names, it can produce errors in some 3076 // cases. 3077 // 3078 // It is possible to use constructors created "manually" (without 3079 // dojo.declare) as bases. They will be called as usual during the 3080 // creation of an instance, their methods will be chained, and even 3081 // called by "this.inherited()". 3082 // 3083 // Special property "-chains-" governs how to chain methods. It is 3084 // a dictionary, which uses method names as keys, and hint strings 3085 // as values. If a hint string is "after", this method will be 3086 // called after methods of its base classes. If a hint string is 3087 // "before", this method will be called before methods of its base 3088 // classes. 3089 // 3090 // If "constructor" is not mentioned in "-chains-" property, it will 3091 // be chained using the legacy mode: using "after" chaining, 3092 // calling preamble() method before each constructor, if available, 3093 // and calling postscript() after all constructors were executed. 3094 // If the hint is "after", it is chained as a regular method, but 3095 // postscript() will be called after the chain of constructors. 3096 // "constructor" cannot be chained "before", but it allows 3097 // a special hint string: "manual", which means that constructors 3098 // are not going to be chained in any way, and programmer will call 3099 // them manually using this.inherited(). In the latter case 3100 // postscript() will be called after the construction. 3101 // 3102 // All chaining hints are "inherited" from base classes and 3103 // potentially can be overridden. Be very careful when overriding 3104 // hints! Make sure that all chained methods can work in a proposed 3105 // manner of chaining. 3106 // 3107 // Once a method was chained, it is impossible to unchain it. The 3108 // only exception is "constructor". You don't need to define a 3109 // method in order to supply a chaining hint. 3110 // 3111 // If a method is chained, it cannot use this.inherited() because 3112 // all other methods in the hierarchy will be called automatically. 3113 // 3114 // Usually constructors and initializers of any kind are chained 3115 // using "after" and destructors of any kind are chained as 3116 // "before". Note that chaining assumes that chained methods do not 3117 // return any value: any returned value will be discarded. 3118 // 3119 // example: 3120 // | dojo.declare("my.classes.bar", my.classes.foo, { 3121 // | // properties to be added to the class prototype 3122 // | someValue: 2, 3123 // | // initialization function 3124 // | constructor: function(){ 3125 // | this.myComplicatedObject = new ReallyComplicatedObject(); 3126 // | }, 3127 // | // other functions 3128 // | someMethod: function(){ 3129 // | doStuff(); 3130 // | } 3131 // | }); 3132 // 3133 // example: 3134 // | var MyBase = dojo.declare(null, { 3135 // | // constructor, properties, and methods go here 3136 // | // ... 3137 // | }); 3138 // | var MyClass1 = dojo.declare(MyBase, { 3139 // | // constructor, properties, and methods go here 3140 // | // ... 3141 // | }); 3142 // | var MyClass2 = dojo.declare(MyBase, { 3143 // | // constructor, properties, and methods go here 3144 // | // ... 3145 // | }); 3146 // | var MyDiamond = dojo.declare([MyClass1, MyClass2], { 3147 // | // constructor, properties, and methods go here 3148 // | // ... 3149 // | }); 3150 // 3151 // example: 3152 // | var F = function(){ console.log("raw constructor"); }; 3153 // | F.prototype.method = function(){ 3154 // | console.log("raw method"); 3155 // | }; 3156 // | var A = dojo.declare(F, { 3157 // | constructor: function(){ 3158 // | console.log("A.constructor"); 3159 // | }, 3160 // | method: function(){ 3161 // | console.log("before calling F.method..."); 3162 // | this.inherited(arguments); 3163 // | console.log("...back in A"); 3164 // | } 3165 // | }); 3166 // | new A().method(); 3167 // | // will print: 3168 // | // raw constructor 3169 // | // A.constructor 3170 // | // before calling F.method... 3171 // | // raw method 3172 // | // ...back in A 3173 // 3174 // example: 3175 // | var A = dojo.declare(null, { 3176 // | "-chains-": { 3177 // | destroy: "before" 3178 // | } 3179 // | }); 3180 // | var B = dojo.declare(A, { 3181 // | constructor: function(){ 3182 // | console.log("B.constructor"); 3183 // | }, 3184 // | destroy: function(){ 3185 // | console.log("B.destroy"); 3186 // | } 3187 // | }); 3188 // | var C = dojo.declare(B, { 3189 // | constructor: function(){ 3190 // | console.log("C.constructor"); 3191 // | }, 3192 // | destroy: function(){ 3193 // | console.log("C.destroy"); 3194 // | } 3195 // | }); 3196 // | new C().destroy(); 3197 // | // prints: 3198 // | // B.constructor 3199 // | // C.constructor 3200 // | // C.destroy 3201 // | // B.destroy 3202 // 3203 // example: 3204 // | var A = dojo.declare(null, { 3205 // | "-chains-": { 3206 // | constructor: "manual" 3207 // | } 3208 // | }); 3209 // | var B = dojo.declare(A, { 3210 // | constructor: function(){ 3211 // | // ... 3212 // | // call the base constructor with new parameters 3213 // | this.inherited(arguments, [1, 2, 3]); 3214 // | // ... 3215 // | } 3216 // | }); 3217 // 3218 // example: 3219 // | var A = dojo.declare(null, { 3220 // | "-chains-": { 3221 // | m1: "before" 3222 // | }, 3223 // | m1: function(){ 3224 // | console.log("A.m1"); 3225 // | }, 3226 // | m2: function(){ 3227 // | console.log("A.m2"); 3228 // | } 3229 // | }); 3230 // | var B = dojo.declare(A, { 3231 // | "-chains-": { 3232 // | m2: "after" 3233 // | }, 3234 // | m1: function(){ 3235 // | console.log("B.m1"); 3236 // | }, 3237 // | m2: function(){ 3238 // | console.log("B.m2"); 3239 // | } 3240 // | }); 3241 // | var x = new B(); 3242 // | x.m1(); 3243 // | // prints: 3244 // | // B.m1 3245 // | // A.m1 3246 // | x.m2(); 3247 // | // prints: 3248 // | // A.m2 3249 // | // B.m2 3250 return new Function(); // Function 3251 }; 3252 =====*/ 3253 3254 /*===== 3255 dojo.safeMixin = function(target, source){ 3256 // summary: 3257 // Mix in properties skipping a constructor and decorating functions 3258 // like it is done by dojo.declare. 3259 // target: Object 3260 // Target object to accept new properties. 3261 // source: Object 3262 // Source object for new properties. 3263 // description: 3264 // This function is used to mix in properties like dojo._mixin does, 3265 // but it skips a constructor property and decorates functions like 3266 // dojo.declare does. 3267 // 3268 // It is meant to be used with classes and objects produced with 3269 // dojo.declare. Functions mixed in with dojo.safeMixin can use 3270 // this.inherited() like normal methods. 3271 // 3272 // This function is used to implement extend() method of a constructor 3273 // produced with dojo.declare(). 3274 // 3275 // example: 3276 // | var A = dojo.declare(null, { 3277 // | m1: function(){ 3278 // | console.log("A.m1"); 3279 // | }, 3280 // | m2: function(){ 3281 // | console.log("A.m2"); 3282 // | } 3283 // | }); 3284 // | var B = dojo.declare(A, { 3285 // | m1: function(){ 3286 // | this.inherited(arguments); 3287 // | console.log("B.m1"); 3288 // | } 3289 // | }); 3290 // | B.extend({ 3291 // | m2: function(){ 3292 // | this.inherited(arguments); 3293 // | console.log("B.m2"); 3294 // | } 3295 // | }); 3296 // | var x = new B(); 3297 // | dojo.safeMixin(x, { 3298 // | m1: function(){ 3299 // | this.inherited(arguments); 3300 // | console.log("X.m1"); 3301 // | }, 3302 // | m2: function(){ 3303 // | this.inherited(arguments); 3304 // | console.log("X.m2"); 3305 // | } 3306 // | }); 3307 // | x.m2(); 3308 // | // prints: 3309 // | // A.m1 3310 // | // B.m1 3311 // | // X.m1 3312 }; 3313 =====*/ 3314 3315 /*===== 3316 Object.inherited = function(name, args, newArgs){ 3317 // summary: 3318 // Calls a super method. 3319 // name: String? 3320 // The optional method name. Should be the same as the caller's 3321 // name. Usually "name" is specified in complex dynamic cases, when 3322 // the calling method was dynamically added, undecorated by 3323 // dojo.declare, and it cannot be determined. 3324 // args: Arguments 3325 // The caller supply this argument, which should be the original 3326 // "arguments". 3327 // newArgs: Object? 3328 // If "true", the found function will be returned without 3329 // executing it. 3330 // If Array, it will be used to call a super method. Otherwise 3331 // "args" will be used. 3332 // returns: 3333 // Whatever is returned by a super method, or a super method itself, 3334 // if "true" was specified as newArgs. 3335 // description: 3336 // This method is used inside method of classes produced with 3337 // dojo.declare to call a super method (next in the chain). It is 3338 // used for manually controlled chaining. Consider using the regular 3339 // chaining, because it is faster. Use "this.inherited()" only in 3340 // complex cases. 3341 // 3342 // This method cannot me called from automatically chained 3343 // constructors including the case of a special (legacy) 3344 // constructor chaining. It cannot be called from chained methods. 3345 // 3346 // If "this.inherited()" cannot find the next-in-chain method, it 3347 // does nothing and returns "undefined". The last method in chain 3348 // can be a default method implemented in Object, which will be 3349 // called last. 3350 // 3351 // If "name" is specified, it is assumed that the method that 3352 // received "args" is the parent method for this call. It is looked 3353 // up in the chain list and if it is found the next-in-chain method 3354 // is called. If it is not found, the first-in-chain method is 3355 // called. 3356 // 3357 // If "name" is not specified, it will be derived from the calling 3358 // method (using a methoid property "nom"). 3359 // 3360 // example: 3361 // | var B = dojo.declare(A, { 3362 // | method1: function(a, b, c){ 3363 // | this.inherited(arguments); 3364 // | }, 3365 // | method2: function(a, b){ 3366 // | return this.inherited(arguments, [a + b]); 3367 // | } 3368 // | }); 3369 // | // next method is not in the chain list because it is added 3370 // | // manually after the class was created. 3371 // | B.prototype.method3 = function(){ 3372 // | console.log("This is a dynamically-added method."); 3373 // | this.inherited("method3", arguments); 3374 // | }; 3375 // example: 3376 // | var B = dojo.declare(A, { 3377 // | method: function(a, b){ 3378 // | var super = this.inherited(arguments, true); 3379 // | // ... 3380 // | if(!super){ 3381 // | console.log("there is no super method"); 3382 // | return 0; 3383 // | } 3384 // | return super.apply(this, arguments); 3385 // | } 3386 // | }); 3387 return {}; // Object 3388 } 3389 =====*/ 3390 3391 /*===== 3392 Object.getInherited = function(name, args){ 3393 // summary: 3394 // Returns a super method. 3395 // name: String? 3396 // The optional method name. Should be the same as the caller's 3397 // name. Usually "name" is specified in complex dynamic cases, when 3398 // the calling method was dynamically added, undecorated by 3399 // dojo.declare, and it cannot be determined. 3400 // args: Arguments 3401 // The caller supply this argument, which should be the original 3402 // "arguments". 3403 // returns: 3404 // Returns a super method (Function) or "undefined". 3405 // description: 3406 // This method is a convenience method for "this.inherited()". 3407 // It uses the same algorithm but instead of executing a super 3408 // method, it returns it, or "undefined" if not found. 3409 // 3410 // example: 3411 // | var B = dojo.declare(A, { 3412 // | method: function(a, b){ 3413 // | var super = this.getInherited(arguments); 3414 // | // ... 3415 // | if(!super){ 3416 // | console.log("there is no super method"); 3417 // | return 0; 3418 // | } 3419 // | return super.apply(this, arguments); 3420 // | } 3421 // | }); 3422 return {}; // Object 3423 } 3424 =====*/ 3425 3426 /*===== 3427 Object.isInstanceOf = function(cls){ 3428 // summary: 3429 // Checks the inheritance chain to see if it is inherited from this 3430 // class. 3431 // cls: Function 3432 // Class constructor. 3433 // returns: 3434 // "true", if this object is inherited from this class, "false" 3435 // otherwise. 3436 // description: 3437 // This method is used with instances of classes produced with 3438 // dojo.declare to determine of they support a certain interface or 3439 // not. It models "instanceof" operator. 3440 // 3441 // example: 3442 // | var A = dojo.declare(null, { 3443 // | // constructor, properties, and methods go here 3444 // | // ... 3445 // | }); 3446 // | var B = dojo.declare(null, { 3447 // | // constructor, properties, and methods go here 3448 // | // ... 3449 // | }); 3450 // | var C = dojo.declare([A, B], { 3451 // | // constructor, properties, and methods go here 3452 // | // ... 3453 // | }); 3454 // | var D = dojo.declare(A, { 3455 // | // constructor, properties, and methods go here 3456 // | // ... 3457 // | }); 3458 // | 3459 // | var a = new A(), b = new B(), c = new C(), d = new D(); 3460 // | 3461 // | console.log(a.isInstanceOf(A)); // true 3462 // | console.log(b.isInstanceOf(A)); // false 3463 // | console.log(c.isInstanceOf(A)); // true 3464 // | console.log(d.isInstanceOf(A)); // true 3465 // | 3466 // | console.log(a.isInstanceOf(B)); // false 3467 // | console.log(b.isInstanceOf(B)); // true 3468 // | console.log(c.isInstanceOf(B)); // true 3469 // | console.log(d.isInstanceOf(B)); // false 3470 // | 3471 // | console.log(a.isInstanceOf(C)); // false 3472 // | console.log(b.isInstanceOf(C)); // false 3473 // | console.log(c.isInstanceOf(C)); // true 3474 // | console.log(d.isInstanceOf(C)); // false 3475 // | 3476 // | console.log(a.isInstanceOf(D)); // false 3477 // | console.log(b.isInstanceOf(D)); // false 3478 // | console.log(c.isInstanceOf(D)); // false 3479 // | console.log(d.isInstanceOf(D)); // true 3480 return {}; // Object 3481 } 3482 =====*/ 3483 3484 /*===== 3485 Object.extend = function(source){ 3486 // summary: 3487 // Adds all properties and methods of source to constructor's 3488 // prototype, making them available to all instances created with 3489 // constructor. This method is specific to constructors created with 3490 // dojo.declare. 3491 // source: Object 3492 // Source object which properties are going to be copied to the 3493 // constructor's prototype. 3494 // description: 3495 // Adds source properties to the constructor's prototype. It can 3496 // override existing properties. 3497 // 3498 // This method is similar to dojo.extend function, but it is specific 3499 // to constructors produced by dojo.declare. It is implemented 3500 // using dojo.safeMixin, and it skips a constructor property, 3501 // and properly decorates copied functions. 3502 // 3503 // example: 3504 // | var A = dojo.declare(null, { 3505 // | m1: function(){}, 3506 // | s1: "Popokatepetl" 3507 // | }); 3508 // | A.extend({ 3509 // | m1: function(){}, 3510 // | m2: function(){}, 3511 // | f1: true, 3512 // | d1: 42 3513 // | }); 3514 }; 3515 =====*/ 3516 })(); 3517 3518 } 3519 3520 if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 3521 dojo._hasResource["dojo._base.connect"] = true; 3522 dojo.provide("dojo._base.connect"); 3523 3524 3525 3526 // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA 3527 3528 // low-level delegation machinery 3529 dojo._listener = { 3530 // create a dispatcher function 3531 getDispatcher: function(){ 3532 // following comments pulled out-of-line to prevent cloning them 3533 // in the returned function. 3534 // - indices (i) that are really in the array of listeners (ls) will 3535 // not be in Array.prototype. This is the 'sparse array' trick 3536 // that keeps us safe from libs that take liberties with built-in 3537 // objects 3538 // - listener is invoked with current scope (this) 3539 return function(){ 3540 var ap = Array.prototype, c = arguments.callee, ls = c._listeners, t = c.target, 3541 // return value comes from original target function 3542 r = t && t.apply(this, arguments), 3543 // make local copy of listener array so it is immutable during processing 3544 i, lls = [].concat(ls) 3545 ; 3546 3547 // invoke listeners after target function 3548 for(i in lls){ 3549 if(!(i in ap)){ 3550 lls[i].apply(this, arguments); 3551 } 3552 } 3553 // return value comes from original target function 3554 return r; 3555 }; 3556 }, 3557 // add a listener to an object 3558 add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){ 3559 // Whenever 'method' is invoked, 'listener' will have the same scope. 3560 // Trying to supporting a context object for the listener led to 3561 // complexity. 3562 // Non trivial to provide 'once' functionality here 3563 // because listener could be the result of a dojo.hitch call, 3564 // in which case two references to the same hitch target would not 3565 // be equivalent. 3566 source = source || dojo.global; 3567 // The source method is either null, a dispatcher, or some other function 3568 var f = source[method]; 3569 // Ensure a dispatcher 3570 if(!f || !f._listeners){ 3571 var d = dojo._listener.getDispatcher(); 3572 // original target function is special 3573 d.target = f; 3574 // dispatcher holds a list of listeners 3575 d._listeners = []; 3576 // redirect source to dispatcher 3577 f = source[method] = d; 3578 } 3579 // The contract is that a handle is returned that can 3580 // identify this listener for disconnect. 3581 // 3582 // The type of the handle is private. Here is it implemented as Integer. 3583 // DOM event code has this same contract but handle is Function 3584 // in non-IE browsers. 3585 // 3586 // We could have separate lists of before and after listeners. 3587 return f._listeners.push(listener); /*Handle*/ 3588 }, 3589 // remove a listener from an object 3590 remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){ 3591 var f = (source || dojo.global)[method]; 3592 // remember that handle is the index+1 (0 is not a valid handle) 3593 if(f && f._listeners && handle--){ 3594 delete f._listeners[handle]; 3595 } 3596 } 3597 }; 3598 3599 // Multiple delegation for arbitrary methods. 3600 3601 // This unit knows nothing about DOM, but we include DOM aware documentation 3602 // and dontFix argument here to help the autodocs. Actual DOM aware code is in 3603 // event.js. 3604 3605 dojo.connect = function(/*Object|null*/ obj, 3606 /*String*/ event, 3607 /*Object|null*/ context, 3608 /*String|Function*/ method, 3609 /*Boolean?*/ dontFix){ 3610 // summary: 3611 // `dojo.connect` is the core event handling and delegation method in 3612 // Dojo. It allows one function to "listen in" on the execution of 3613 // any other, triggering the second whenever the first is called. Many 3614 // listeners may be attached to a function, and source functions may 3615 // be either regular function calls or DOM events. 3616 // 3617 // description: 3618 // Connects listeners to actions, so that after event fires, a 3619 // listener is called with the same arguments passed to the original 3620 // function. 3621 // 3622 // Since `dojo.connect` allows the source of events to be either a 3623 // "regular" JavaScript function or a DOM event, it provides a uniform 3624 // interface for listening to all the types of events that an 3625 // application is likely to deal with though a single, unified 3626 // interface. DOM programmers may want to think of it as 3627 // "addEventListener for everything and anything". 3628 // 3629 // When setting up a connection, the `event` parameter must be a 3630 // string that is the name of the method/event to be listened for. If 3631 // `obj` is null, `dojo.global` is assumed, meaning that connections 3632 // to global methods are supported but also that you may inadvertently 3633 // connect to a global by passing an incorrect object name or invalid 3634 // reference. 3635 // 3636 // `dojo.connect` generally is forgiving. If you pass the name of a 3637 // function or method that does not yet exist on `obj`, connect will 3638 // not fail, but will instead set up a stub method. Similarly, null 3639 // arguments may simply be omitted such that fewer than 4 arguments 3640 // may be required to set up a connection See the examples for details. 3641 // 3642 // The return value is a handle that is needed to 3643 // remove this connection with `dojo.disconnect`. 3644 // 3645 // obj: 3646 // The source object for the event function. 3647 // Defaults to `dojo.global` if null. 3648 // If obj is a DOM node, the connection is delegated 3649 // to the DOM event manager (unless dontFix is true). 3650 // 3651 // event: 3652 // String name of the event function in obj. 3653 // I.e. identifies a property `obj[event]`. 3654 // 3655 // context: 3656 // The object that method will receive as "this". 3657 // 3658 // If context is null and method is a function, then method 3659 // inherits the context of event. 3660 // 3661 // If method is a string then context must be the source 3662 // object object for method (context[method]). If context is null, 3663 // dojo.global is used. 3664 // 3665 // method: 3666 // A function reference, or name of a function in context. 3667 // The function identified by method fires after event does. 3668 // method receives the same arguments as the event. 3669 // See context argument comments for information on method's scope. 3670 // 3671 // dontFix: 3672 // If obj is a DOM node, set dontFix to true to prevent delegation 3673 // of this connection to the DOM event manager. 3674 // 3675 // example: 3676 // When obj.onchange(), do ui.update(): 3677 // | dojo.connect(obj, "onchange", ui, "update"); 3678 // | dojo.connect(obj, "onchange", ui, ui.update); // same 3679 // 3680 // example: 3681 // Using return value for disconnect: 3682 // | var link = dojo.connect(obj, "onchange", ui, "update"); 3683 // | ... 3684 // | dojo.disconnect(link); 3685 // 3686 // example: 3687 // When onglobalevent executes, watcher.handler is invoked: 3688 // | dojo.connect(null, "onglobalevent", watcher, "handler"); 3689 // 3690 // example: 3691 // When ob.onCustomEvent executes, customEventHandler is invoked: 3692 // | dojo.connect(ob, "onCustomEvent", null, "customEventHandler"); 3693 // | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same 3694 // 3695 // example: 3696 // When ob.onCustomEvent executes, customEventHandler is invoked 3697 // with the same scope (this): 3698 // | dojo.connect(ob, "onCustomEvent", null, customEventHandler); 3699 // | dojo.connect(ob, "onCustomEvent", customEventHandler); // same 3700 // 3701 // example: 3702 // When globalEvent executes, globalHandler is invoked 3703 // with the same scope (this): 3704 // | dojo.connect(null, "globalEvent", null, globalHandler); 3705 // | dojo.connect("globalEvent", globalHandler); // same 3706 3707 // normalize arguments 3708 var a=arguments, args=[], i=0; 3709 // if a[0] is a String, obj was omitted 3710 args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]); 3711 // if the arg-after-next is a String or Function, context was NOT omitted 3712 var a1 = a[i+1]; 3713 args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]); 3714 // absorb any additional arguments 3715 for(var l=a.length; i<l; i++){ args.push(a[i]); } 3716 // do the actual work 3717 return dojo._connect.apply(this, args); /*Handle*/ 3718 } 3719 3720 // used by non-browser hostenvs. always overriden by event.js 3721 dojo._connect = function(obj, event, context, method){ 3722 var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method)); 3723 return [obj, event, h, l]; // Handle 3724 }; 3725 3726 dojo.disconnect = function(/*Handle*/ handle){ 3727 // summary: 3728 // Remove a link created by dojo.connect. 3729 // description: 3730 // Removes the connection between event and the method referenced by handle. 3731 // handle: 3732 // the return value of the dojo.connect call that created the connection. 3733 if(handle && handle[0] !== undefined){ 3734 dojo._disconnect.apply(this, handle); 3735 // let's not keep this reference 3736 delete handle[0]; 3737 } 3738 }; 3739 3740 dojo._disconnect = function(obj, event, handle, listener){ 3741 listener.remove(obj, event, handle); 3742 }; 3743 3744 // topic publish/subscribe 3745 3746 dojo._topics = {}; 3747 3748 dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){ 3749 // summary: 3750 // Attach a listener to a named topic. The listener function is invoked whenever the 3751 // named topic is published (see: dojo.publish). 3752 // Returns a handle which is needed to unsubscribe this listener. 3753 // context: 3754 // Scope in which method will be invoked, or null for default scope. 3755 // method: 3756 // The name of a function in context, or a function reference. This is the function that 3757 // is invoked when topic is published. 3758 // example: 3759 // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); }); 3760 // | dojo.publish("alerts", [ "read this", "hello world" ]); 3761 3762 // support for 2 argument invocation (omitting context) depends on hitch 3763 return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/ 3764 }; 3765 3766 dojo.unsubscribe = function(/*Handle*/ handle){ 3767 // summary: 3768 // Remove a topic listener. 3769 // handle: 3770 // The handle returned from a call to subscribe. 3771 // example: 3772 // | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); }; 3773 // | ... 3774 // | dojo.unsubscribe(alerter); 3775 if(handle){ 3776 dojo._listener.remove(dojo._topics, handle[0], handle[1]); 3777 } 3778 }; 3779 3780 dojo.publish = function(/*String*/ topic, /*Array*/ args){ 3781 // summary: 3782 // Invoke all listener method subscribed to topic. 3783 // topic: 3784 // The name of the topic to publish. 3785 // args: 3786 // An array of arguments. The arguments will be applied 3787 // to each topic subscriber (as first class parameters, via apply). 3788 // example: 3789 // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); }; 3790 // | dojo.publish("alerts", [ "read this", "hello world" ]); 3791 3792 // Note that args is an array, which is more efficient vs variable length 3793 // argument list. Ideally, var args would be implemented via Array 3794 // throughout the APIs. 3795 var f = dojo._topics[topic]; 3796 if(f){ 3797 f.apply(this, args||[]); 3798 } 3799 }; 3800 3801 dojo.connectPublisher = function( /*String*/ topic, 3802 /*Object|null*/ obj, 3803 /*String*/ event){ 3804 // summary: 3805 // Ensure that every time obj.event() is called, a message is published 3806 // on the topic. Returns a handle which can be passed to 3807 // dojo.disconnect() to disable subsequent automatic publication on 3808 // the topic. 3809 // topic: 3810 // The name of the topic to publish. 3811 // obj: 3812 // The source object for the event function. Defaults to dojo.global 3813 // if null. 3814 // event: 3815 // The name of the event function in obj. 3816 // I.e. identifies a property obj[event]. 3817 // example: 3818 // | dojo.connectPublisher("/ajax/start", dojo, "xhrGet"); 3819 var pf = function(){ dojo.publish(topic, arguments); } 3820 return event ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle 3821 }; 3822 3823 } 3824 3825 if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 3826 dojo._hasResource["dojo._base.Deferred"] = true; 3827 dojo.provide("dojo._base.Deferred"); 3828 3829 3830 3831 (function(){ 3832 var mutator = function(){}; 3833 var freeze = Object.freeze || function(){}; 3834 // A deferred provides an API for creating and resolving a promise. 3835 dojo.Deferred = function(/*Function?*/canceller){ 3836 // summary: 3837 // Deferreds provide a generic means for encapsulating an asynchronous 3838 // operation and notifying users of the completion and result of the operation. 3839 // description: 3840 // The dojo.Deferred API is based on the concept of promises that provide a 3841 // generic interface into the eventual completion of an asynchronous action. 3842 // The motivation for promises fundamentally is about creating a 3843 // separation of concerns that allows one to achieve the same type of 3844 // call patterns and logical data flow in asynchronous code as can be 3845 // achieved in synchronous code. Promises allows one 3846 // to be able to call a function purely with arguments needed for 3847 // execution, without conflating the call with concerns of whether it is 3848 // sync or async. One shouldn't need to alter a call's arguments if the 3849 // implementation switches from sync to async (or vice versa). By having 3850 // async functions return promises, the concerns of making the call are 3851 // separated from the concerns of asynchronous interaction (which are 3852 // handled by the promise). 3853 // 3854 // The dojo.Deferred is a type of promise that provides methods for fulfilling the 3855 // promise with a successful result or an error. The most important method for 3856 // working with Dojo's promises is the then() method, which follows the 3857 // CommonJS proposed promise API. An example of using a Dojo promise: 3858 // 3859 // | var resultingPromise = someAsyncOperation.then(function(result){ 3860 // | ... handle result ... 3861 // | }, 3862 // | function(error){ 3863 // | ... handle error ... 3864 // | }); 3865 // 3866 // The .then() call returns a new promise that represents the result of the 3867 // execution of the callback. The callbacks will never affect the original promises value. 3868 // 3869 // The dojo.Deferred instances also provide the following functions for backwards compatibility: 3870 // 3871 // * addCallback(handler) 3872 // * addErrback(handler) 3873 // * callback(result) 3874 // * errback(result) 3875 // 3876 // Callbacks are allowed to return promises themselves, so 3877 // you can build complicated sequences of events with ease. 3878 // 3879 // The creator of the Deferred may specify a canceller. The canceller 3880 // is a function that will be called if Deferred.cancel is called 3881 // before the Deferred fires. You can use this to implement clean 3882 // aborting of an XMLHttpRequest, etc. Note that cancel will fire the 3883 // deferred with a CancelledError (unless your canceller returns 3884 // another kind of error), so the errbacks should be prepared to 3885 // handle that error for cancellable Deferreds. 3886 // example: 3887 // | var deferred = new dojo.Deferred(); 3888 // | setTimeout(function(){ deferred.callback({success: true}); }, 1000); 3889 // | return deferred; 3890 // example: 3891 // Deferred objects are often used when making code asynchronous. It 3892 // may be easiest to write functions in a synchronous manner and then 3893 // split code using a deferred to trigger a response to a long-lived 3894 // operation. For example, instead of register a callback function to 3895 // denote when a rendering operation completes, the function can 3896 // simply return a deferred: 3897 // 3898 // | // callback style: 3899 // | function renderLotsOfData(data, callback){ 3900 // | var success = false 3901 // | try{ 3902 // | for(var x in data){ 3903 // | renderDataitem(data[x]); 3904 // | } 3905 // | success = true; 3906 // | }catch(e){ } 3907 // | if(callback){ 3908 // | callback(success); 3909 // | } 3910 // | } 3911 // 3912 // | // using callback style 3913 // | renderLotsOfData(someDataObj, function(success){ 3914 // | // handles success or failure 3915 // | if(!success){ 3916 // | promptUserToRecover(); 3917 // | } 3918 // | }); 3919 // | // NOTE: no way to add another callback here!! 3920 // example: 3921 // Using a Deferred doesn't simplify the sending code any, but it 3922 // provides a standard interface for callers and senders alike, 3923 // providing both with a simple way to service multiple callbacks for 3924 // an operation and freeing both sides from worrying about details 3925 // such as "did this get called already?". With Deferreds, new 3926 // callbacks can be added at any time. 3927 // 3928 // | // Deferred style: 3929 // | function renderLotsOfData(data){ 3930 // | var d = new dojo.Deferred(); 3931 // | try{ 3932 // | for(var x in data){ 3933 // | renderDataitem(data[x]); 3934 // | } 3935 // | d.callback(true); 3936 // | }catch(e){ 3937 // | d.errback(new Error("rendering failed")); 3938 // | } 3939 // | return d; 3940 // | } 3941 // 3942 // | // using Deferred style 3943 // | renderLotsOfData(someDataObj).then(null, function(){ 3944 // | promptUserToRecover(); 3945 // | }); 3946 // | // NOTE: addErrback and addCallback both return the Deferred 3947 // | // again, so we could chain adding callbacks or save the 3948 // | // deferred for later should we need to be notified again. 3949 // example: 3950 // In this example, renderLotsOfData is synchronous and so both 3951 // versions are pretty artificial. Putting the data display on a 3952 // timeout helps show why Deferreds rock: 3953 // 3954 // | // Deferred style and async func 3955 // | function renderLotsOfData(data){ 3956 // | var d = new dojo.Deferred(); 3957 // | setTimeout(function(){ 3958 // | try{ 3959 // | for(var x in data){ 3960 // | renderDataitem(data[x]); 3961 // | } 3962 // | d.callback(true); 3963 // | }catch(e){ 3964 // | d.errback(new Error("rendering failed")); 3965 // | } 3966 // | }, 100); 3967 // | return d; 3968 // | } 3969 // 3970 // | // using Deferred style 3971 // | renderLotsOfData(someDataObj).then(null, function(){ 3972 // | promptUserToRecover(); 3973 // | }); 3974 // 3975 // Note that the caller doesn't have to change his code at all to 3976 // handle the asynchronous case. 3977 var result, finished, isError, head, nextListener; 3978 var promise = (this.promise = {}); 3979 3980 function complete(value){ 3981 if(finished){ 3982 throw new Error("This deferred has already been resolved"); 3983 } 3984 result = value; 3985 finished = true; 3986 notify(); 3987 } 3988 function notify(){ 3989 var mutated; 3990 while(!mutated && nextListener){ 3991 var listener = nextListener; 3992 nextListener = nextListener.next; 3993 if((mutated = (listener.progress == mutator))){ // assignment and check 3994 finished = false; 3995 } 3996 var func = (isError ? listener.error : listener.resolved); 3997 if (func) { 3998 try { 3999 var newResult = func(result); 4000 if (newResult && typeof newResult.then === "function") { 4001 newResult.then(dojo.hitch(listener.deferred, "resolve"), dojo.hitch(listener.deferred, "reject")); 4002 continue; 4003 } 4004 var unchanged = mutated && newResult === undefined; 4005 if(mutated && !unchanged){ 4006 isError = newResult instanceof Error; 4007 } 4008 listener.deferred[unchanged && isError ? "reject" : "resolve"](unchanged ? result : newResult); 4009 } 4010 catch (e) { 4011 listener.deferred.reject(e); 4012 } 4013 }else { 4014 if(isError){ 4015 listener.deferred.reject(result); 4016 }else{ 4017 listener.deferred.resolve(result); 4018 } 4019 } 4020 } 4021 } 4022 // calling resolve will resolve the promise 4023 this.resolve = this.callback = function(value){ 4024 // summary: 4025 // Fulfills the Deferred instance successfully with the provide value 4026 this.fired = 0; 4027 this.results = [value, null]; 4028 complete(value); 4029 }; 4030 4031 4032 // calling error will indicate that the promise failed 4033 this.reject = this.errback = function(error){ 4034 // summary: 4035 // Fulfills the Deferred instance as an error with the provided error 4036 isError = true; 4037 this.fired = 1; 4038 complete(error); 4039 this.results = [null, error]; 4040 if(!error || error.log !== false){ 4041 (dojo.config.deferredOnError || function(x){ console.error(x); })(error); 4042 } 4043 }; 4044 // call progress to provide updates on the progress on the completion of the promise 4045 this.progress = function(update){ 4046 // summary 4047 // Send progress events to all listeners 4048 var listener = nextListener; 4049 while(listener){ 4050 var progress = listener.progress; 4051 progress && progress(update); 4052 listener = listener.next; 4053 } 4054 }; 4055 this.addCallbacks = function(/*Function?*/callback, /*Function?*/errback){ 4056 this.then(callback, errback, mutator); 4057 return this; 4058 }; 4059 // provide the implementation of the promise 4060 this.then = promise.then = function(/*Function?*/resolvedCallback, /*Function?*/errorCallback, /*Function?*/progressCallback){ 4061 // summary: 4062 // Adds a fulfilledHandler, errorHandler, and progressHandler to be called for 4063 // completion of a promise. The fulfilledHandler is called when the promise 4064 // is fulfilled. The errorHandler is called when a promise fails. The 4065 // progressHandler is called for progress events. All arguments are optional 4066 // and non-function values are ignored. The progressHandler is not only an 4067 // optional argument, but progress events are purely optional. Promise 4068 // providers are not required to ever create progress events. 4069 // 4070 // This function will return a new promise that is fulfilled when the given 4071 // fulfilledHandler or errorHandler callback is finished. This allows promise 4072 // operations to be chained together. The value returned from the callback 4073 // handler is the fulfillment value for the returned promise. If the callback 4074 // throws an error, the returned promise will be moved to failed state. 4075 // 4076 // example: 4077 // An example of using a CommonJS compliant promise: 4078 // | asyncComputeTheAnswerToEverything(). 4079 // | then(addTwo). 4080 // | then(printResult, onError); 4081 // | >44 4082 // 4083 var returnDeferred = progressCallback == mutator ? this : new dojo.Deferred(promise.cancel); 4084 var listener = { 4085 resolved: resolvedCallback, 4086 error: errorCallback, 4087 progress: progressCallback, 4088 deferred: returnDeferred 4089 }; 4090 if(nextListener){ 4091 head = head.next = listener; 4092 } 4093 else{ 4094 nextListener = head = listener; 4095 } 4096 if(finished){ 4097 notify(); 4098 } 4099 return returnDeferred.promise; 4100 }; 4101 var deferred = this; 4102 this.cancel = promise.cancel = function () { 4103 // summary: 4104 // Cancels the asynchronous operation 4105 if(!finished){ 4106 var error = canceller && canceller(deferred); 4107 if(!finished){ 4108 if (!(error instanceof Error)) { 4109 error = new Error(error); 4110 } 4111 error.log = false; 4112 deferred.reject(error); 4113 } 4114 } 4115 }; 4116 freeze(promise); 4117 }; 4118 dojo.extend(dojo.Deferred, { 4119 addCallback: function (/*Function*/callback) { 4120 return this.addCallbacks(dojo.hitch.apply(dojo, arguments)); 4121 }, 4122 4123 addErrback: function (/*Function*/errback) { 4124 return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments)); 4125 }, 4126 4127 addBoth: function (/*Function*/callback) { 4128 var enclosed = dojo.hitch.apply(dojo, arguments); 4129 return this.addCallbacks(enclosed, enclosed); 4130 }, 4131 fired: -1 4132 }); 4133 })(); 4134 dojo.when = function(promiseOrValue, /*Function?*/callback, /*Function?*/errback, /*Function?*/progressHandler){ 4135 // summary: 4136 // This provides normalization between normal synchronous values and 4137 // asynchronous promises, so you can interact with them in a common way 4138 // example: 4139 // | function printFirstAndList(items){ 4140 // | dojo.when(findFirst(items), console.log); 4141 // | dojo.when(findLast(items), console.log); 4142 // | } 4143 // | function findFirst(items){ 4144 // | return dojo.when(items, function(items){ 4145 // | return items[0]; 4146 // | }); 4147 // | } 4148 // | function findLast(items){ 4149 // | return dojo.when(items, function(items){ 4150 // | return items[items.length]; 4151 // | }); 4152 // | } 4153 // And now all three of his functions can be used sync or async. 4154 // | printFirstAndLast([1,2,3,4]) will work just as well as 4155 // | printFirstAndLast(dojo.xhrGet(...)); 4156 4157 if(promiseOrValue && typeof promiseOrValue.then === "function"){ 4158 return promiseOrValue.then(callback, errback, progressHandler); 4159 } 4160 return callback(promiseOrValue); 4161 }; 4162 4163 } 4164 4165 if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 4166 dojo._hasResource["dojo._base.json"] = true; 4167 dojo.provide("dojo._base.json"); 4168 4169 4170 dojo.fromJson = function(/*String*/ json){ 4171 // summary: 4172 // Parses a [JSON](http://json.org) string to return a JavaScript object. 4173 // description: 4174 // Throws for invalid JSON strings, but it does not use a strict JSON parser. It 4175 // delegates to eval(). The content passed to this method must therefore come 4176 // from a trusted source. 4177 // json: 4178 // a string literal of a JSON item, for instance: 4179 // `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'` 4180 4181 return eval("(" + json + ")"); // Object 4182 }; 4183 4184 dojo._escapeString = function(/*String*/str){ 4185 //summary: 4186 // Adds escape sequences for non-visual characters, double quote and 4187 // backslash and surrounds with double quotes to form a valid string 4188 // literal. 4189 return ('"' + str.replace(/(["\\])/g, '\\$1') + '"'). 4190 replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n"). 4191 replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string 4192 }; 4193 4194 dojo.toJsonIndentStr = "\t"; 4195 dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){ 4196 // summary: 4197 // Returns a [JSON](http://json.org) serialization of an object. 4198 // description: 4199 // Returns a [JSON](http://json.org) serialization of an object. 4200 // Note that this doesn't check for infinite recursion, so don't do that! 4201 // it: 4202 // an object to be serialized. Objects may define their own 4203 // serialization via a special "__json__" or "json" function 4204 // property. If a specialized serializer has been defined, it will 4205 // be used as a fallback. 4206 // prettyPrint: 4207 // if true, we indent objects and arrays to make the output prettier. 4208 // The variable `dojo.toJsonIndentStr` is used as the indent string -- 4209 // to use something other than the default (tab), change that variable 4210 // before calling dojo.toJson(). 4211 // _indentStr: 4212 // private variable for recursive calls when pretty printing, do not use. 4213 // example: 4214 // simple serialization of a trivial object 4215 // | var jsonStr = dojo.toJson({ howdy: "stranger!", isStrange: true }); 4216 // | doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr); 4217 // example: 4218 // a custom serializer for an objects of a particular class: 4219 // | dojo.declare("Furby", null, { 4220 // | furbies: "are strange", 4221 // | furbyCount: 10, 4222 // | __json__: function(){ 4223 // | }, 4224 // | }); 4225 4226 if(it === undefined){ 4227 return "undefined"; 4228 } 4229 var objtype = typeof it; 4230 if(objtype == "number" || objtype == "boolean"){ 4231 return it + ""; 4232 } 4233 if(it === null){ 4234 return "null"; 4235 } 4236 if(dojo.isString(it)){ 4237 return dojo._escapeString(it); 4238 } 4239 // recurse 4240 var recurse = arguments.callee; 4241 // short-circuit for objects that support "json" serialization 4242 // if they return "self" then just pass-through... 4243 var newObj; 4244 _indentStr = _indentStr || ""; 4245 var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : ""; 4246 var tf = it.__json__||it.json; 4247 if(dojo.isFunction(tf)){ 4248 newObj = tf.call(it); 4249 if(it !== newObj){ 4250 return recurse(newObj, prettyPrint, nextIndent); 4251 } 4252 } 4253 if(it.nodeType && it.cloneNode){ // isNode 4254 // we can't seriailize DOM nodes as regular objects because they have cycles 4255 // DOM nodes could be serialized with something like outerHTML, but 4256 // that can be provided by users in the form of .json or .__json__ function. 4257 throw new Error("Can't serialize DOM nodes"); 4258 } 4259 4260 var sep = prettyPrint ? " " : ""; 4261 var newLine = prettyPrint ? "\n" : ""; 4262 4263 // array 4264 if(dojo.isArray(it)){ 4265 var res = dojo.map(it, function(obj){ 4266 var val = recurse(obj, prettyPrint, nextIndent); 4267 if(typeof val != "string"){ 4268 val = "undefined"; 4269 } 4270 return newLine + nextIndent + val; 4271 }); 4272 return "[" + res.join("," + sep) + newLine + _indentStr + "]"; 4273 } 4274 /* 4275 // look in the registry 4276 try { 4277 window.o = it; 4278 newObj = dojo.json.jsonRegistry.match(it); 4279 return recurse(newObj, prettyPrint, nextIndent); 4280 }catch(e){ 4281 // console.log(e); 4282 } 4283 // it's a function with no adapter, skip it 4284 */ 4285 if(objtype == "function"){ 4286 return null; // null 4287 } 4288 // generic object code path 4289 var output = [], key; 4290 for(key in it){ 4291 var keyStr, val; 4292 if(typeof key == "number"){ 4293 keyStr = '"' + key + '"'; 4294 }else if(typeof key == "string"){ 4295 keyStr = dojo._escapeString(key); 4296 }else{ 4297 // skip non-string or number keys 4298 continue; 4299 } 4300 val = recurse(it[key], prettyPrint, nextIndent); 4301 if(typeof val != "string"){ 4302 // skip non-serializable values 4303 continue; 4304 } 4305 // FIXME: use += on Moz!! 4306 // MOW NOTE: using += is a pain because you have to account for the dangling comma... 4307 output.push(newLine + nextIndent + keyStr + ":" + sep + val); 4308 } 4309 return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String 4310 }; 4311 4312 } 4313 4314 if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 4315 dojo._hasResource["dojo._base.Color"] = true; 4316 dojo.provide("dojo._base.Color"); 4317 4318 4319 4320 4321 (function(){ 4322 4323 var d = dojo; 4324 4325 dojo.Color = function(/*Array|String|Object*/ color){ 4326 // summary: 4327 // Takes a named string, hex string, array of rgb or rgba values, 4328 // an object with r, g, b, and a properties, or another `dojo.Color` object 4329 // and creates a new Color instance to work from. 4330 // 4331 // example: 4332 // Work with a Color instance: 4333 // | var c = new dojo.Color(); 4334 // | c.setColor([0,0,0]); // black 4335 // | var hex = c.toHex(); // #000000 4336 // 4337 // example: 4338 // Work with a node's color: 4339 // | var color = dojo.style("someNode", "backgroundColor"); 4340 // | var n = new dojo.Color(color); 4341 // | // adjust the color some 4342 // | n.r *= .5; 4343 // | console.log(n.toString()); // rgb(128, 255, 255); 4344 if(color){ this.setColor(color); } 4345 }; 4346 4347 // FIXME: 4348 // there's got to be a more space-efficient way to encode or discover 4349 // these!! Use hex? 4350 dojo.Color.named = { 4351 black: [0,0,0], 4352 silver: [192,192,192], 4353 gray: [128,128,128], 4354 white: [255,255,255], 4355 maroon: [128,0,0], 4356 red: [255,0,0], 4357 purple: [128,0,128], 4358 fuchsia: [255,0,255], 4359 green: [0,128,0], 4360 lime: [0,255,0], 4361 olive: [128,128,0], 4362 yellow: [255,255,0], 4363 navy: [0,0,128], 4364 blue: [0,0,255], 4365 teal: [0,128,128], 4366 aqua: [0,255,255], 4367 transparent: d.config.transparentColor || [255,255,255] 4368 }; 4369 4370 dojo.extend(dojo.Color, { 4371 r: 255, g: 255, b: 255, a: 1, 4372 _set: function(r, g, b, a){ 4373 var t = this; t.r = r; t.g = g; t.b = b; t.a = a; 4374 }, 4375 setColor: function(/*Array|String|Object*/ color){ 4376 // summary: 4377 // Takes a named string, hex string, array of rgb or rgba values, 4378 // an object with r, g, b, and a properties, or another `dojo.Color` object 4379 // and sets this color instance to that value. 4380 // 4381 // example: 4382 // | var c = new dojo.Color(); // no color 4383 // | c.setColor("#ededed"); // greyish 4384 if(d.isString(color)){ 4385 d.colorFromString(color, this); 4386 }else if(d.isArray(color)){ 4387 d.colorFromArray(color, this); 4388 }else{ 4389 this._set(color.r, color.g, color.b, color.a); 4390 if(!(color instanceof d.Color)){ this.sanitize(); } 4391 } 4392 return this; // dojo.Color 4393 }, 4394 sanitize: function(){ 4395 // summary: 4396 // Ensures the object has correct attributes 4397 // description: 4398 // the default implementation does nothing, include dojo.colors to 4399 // augment it with real checks 4400 return this; // dojo.Color 4401 }, 4402 toRgb: function(){ 4403 // summary: 4404 // Returns 3 component array of rgb values 4405 // example: 4406 // | var c = new dojo.Color("#000000"); 4407 // | console.log(c.toRgb()); // [0,0,0] 4408 var t = this; 4409 return [t.r, t.g, t.b]; // Array 4410 }, 4411 toRgba: function(){ 4412 // summary: 4413 // Returns a 4 component array of rgba values from the color 4414 // represented by this object. 4415 var t = this; 4416 return [t.r, t.g, t.b, t.a]; // Array 4417 }, 4418 toHex: function(){ 4419 // summary: 4420 // Returns a CSS color string in hexadecimal representation 4421 // example: 4422 // | console.log(new dojo.Color([0,0,0]).toHex()); // #000000 4423 var arr = d.map(["r", "g", "b"], function(x){ 4424 var s = this[x].toString(16); 4425 return s.length < 2 ? "0" + s : s; 4426 }, this); 4427 return "#" + arr.join(""); // String 4428 }, 4429 toCss: function(/*Boolean?*/ includeAlpha){ 4430 // summary: 4431 // Returns a css color string in rgb(a) representation 4432 // example: 4433 // | var c = new dojo.Color("#FFF").toCss(); 4434 // | console.log(c); // rgb('255','255','255') 4435 var t = this, rgb = t.r + ", " + t.g + ", " + t.b; 4436 return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String 4437 }, 4438 toString: function(){ 4439 // summary: 4440 // Returns a visual representation of the color 4441 return this.toCss(true); // String 4442 } 4443 }); 4444 4445 dojo.blendColors = function( 4446 /*dojo.Color*/ start, 4447 /*dojo.Color*/ end, 4448 /*Number*/ weight, 4449 /*dojo.Color?*/ obj 4450 ){ 4451 // summary: 4452 // Blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend, 4453 // can reuse a previously allocated dojo.Color object for the result 4454 var t = obj || new d.Color(); 4455 d.forEach(["r", "g", "b", "a"], function(x){ 4456 t[x] = start[x] + (end[x] - start[x]) * weight; 4457 if(x != "a"){ t[x] = Math.round(t[x]); } 4458 }); 4459 return t.sanitize(); // dojo.Color 4460 }; 4461 4462 dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){ 4463 // summary: 4464 // Returns a `dojo.Color` instance from a string of the form 4465 // "rgb(...)" or "rgba(...)". Optionally accepts a `dojo.Color` 4466 // object to update with the parsed value and return instead of 4467 // creating a new object. 4468 // returns: 4469 // A dojo.Color object. If obj is passed, it will be the return value. 4470 var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/); 4471 return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color 4472 }; 4473 4474 dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){ 4475 // summary: 4476 // Converts a hex string with a '#' prefix to a color object. 4477 // Supports 12-bit #rgb shorthand. Optionally accepts a 4478 // `dojo.Color` object to update with the parsed value. 4479 // 4480 // returns: 4481 // A dojo.Color object. If obj is passed, it will be the return value. 4482 // 4483 // example: 4484 // | var thing = dojo.colorFromHex("#ededed"); // grey, longhand 4485 // 4486 // example: 4487 // | var thing = dojo.colorFromHex("#000"); // black, shorthand 4488 var t = obj || new d.Color(), 4489 bits = (color.length == 4) ? 4 : 8, 4490 mask = (1 << bits) - 1; 4491 color = Number("0x" + color.substr(1)); 4492 if(isNaN(color)){ 4493 return null; // dojo.Color 4494 } 4495 d.forEach(["b", "g", "r"], function(x){ 4496 var c = color & mask; 4497 color >>= bits; 4498 t[x] = bits == 4 ? 17 * c : c; 4499 }); 4500 t.a = 1; 4501 return t; // dojo.Color 4502 }; 4503 4504 dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){ 4505 // summary: 4506 // Builds a `dojo.Color` from a 3 or 4 element array, mapping each 4507 // element in sequence to the rgb(a) values of the color. 4508 // example: 4509 // | var myColor = dojo.colorFromArray([237,237,237,0.5]); // grey, 50% alpha 4510 // returns: 4511 // A dojo.Color object. If obj is passed, it will be the return value. 4512 var t = obj || new d.Color(); 4513 t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3])); 4514 if(isNaN(t.a)){ t.a = 1; } 4515 return t.sanitize(); // dojo.Color 4516 }; 4517 4518 dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){ 4519 // summary: 4520 // Parses `str` for a color value. Accepts hex, rgb, and rgba 4521 // style color values. 4522 // description: 4523 // Acceptable input values for str may include arrays of any form 4524 // accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or 4525 // rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10, 4526 // 10, 50)" 4527 // returns: 4528 // A dojo.Color object. If obj is passed, it will be the return value. 4529 var a = d.Color.named[str]; 4530 return a && d.colorFromArray(a, obj) || d.colorFromRgb(str, obj) || d.colorFromHex(str, obj); 4531 }; 4532 })(); 4533 4534 } 4535 4536 if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 4537 dojo._hasResource["dojo._base.window"] = true; 4538 dojo.provide("dojo._base.window"); 4539 4540 4541 /*===== 4542 dojo.doc = { 4543 // summary: 4544 // Alias for the current document. 'dojo.doc' can be modified 4545 // for temporary context shifting. Also see dojo.withDoc(). 4546 // description: 4547 // Refer to dojo.doc rather 4548 // than referring to 'window.document' to ensure your code runs 4549 // correctly in managed contexts. 4550 // example: 4551 // | n.appendChild(dojo.doc.createElement('div')); 4552 } 4553 =====*/ 4554 dojo.doc = window["document"] || null; 4555 4556 dojo.body = function(){ 4557 // summary: 4558 // Return the body element of the document 4559 // return the body object associated with dojo.doc 4560 // example: 4561 // | dojo.body().appendChild(dojo.doc.createElement('div')); 4562 4563 // Note: document.body is not defined for a strict xhtml document 4564 // Would like to memoize this, but dojo.doc can change vi dojo.withDoc(). 4565 return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node 4566 }; 4567 4568 dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){ 4569 // summary: 4570 // changes the behavior of many core Dojo functions that deal with 4571 // namespace and DOM lookup, changing them to work in a new global 4572 // context (e.g., an iframe). The varibles dojo.global and dojo.doc 4573 // are modified as a result of calling this function and the result of 4574 // `dojo.body()` likewise differs. 4575 dojo.global = globalObject; 4576 dojo.doc = globalDocument; 4577 }; 4578 4579 dojo.withGlobal = function( /*Object*/globalObject, 4580 /*Function*/callback, 4581 /*Object?*/thisObject, 4582 /*Array?*/cbArguments){ 4583 // summary: 4584 // Invoke callback with globalObject as dojo.global and 4585 // globalObject.document as dojo.doc. 4586 // description: 4587 // Invoke callback with globalObject as dojo.global and 4588 // globalObject.document as dojo.doc. If provided, globalObject 4589 // will be executed in the context of object thisObject 4590 // When callback() returns or throws an error, the dojo.global 4591 // and dojo.doc will be restored to its previous state. 4592 4593 var oldGlob = dojo.global; 4594 try{ 4595 dojo.global = globalObject; 4596 return dojo.withDoc.call(null, globalObject.document, callback, thisObject, cbArguments); 4597 }finally{ 4598 dojo.global = oldGlob; 4599 } 4600 }; 4601 4602 dojo.withDoc = function( /*DocumentElement*/documentObject, 4603 /*Function*/callback, 4604 /*Object?*/thisObject, 4605 /*Array?*/cbArguments){ 4606 // summary: 4607 // Invoke callback with documentObject as dojo.doc. 4608 // description: 4609 // Invoke callback with documentObject as dojo.doc. If provided, 4610 // callback will be executed in the context of object thisObject 4611 // When callback() returns or throws an error, the dojo.doc will 4612 // be restored to its previous state. 4613 4614 var oldDoc = dojo.doc, 4615 oldLtr = dojo._bodyLtr, 4616 oldQ = dojo.isQuirks; 4617 4618 try{ 4619 dojo.doc = documentObject; 4620 delete dojo._bodyLtr; // uncache 4621 dojo.isQuirks = dojo.doc.compatMode == "BackCompat"; // no need to check for QuirksMode which was Opera 7 only 4622 4623 if(thisObject && typeof callback == "string"){ 4624 callback = thisObject[callback]; 4625 } 4626 4627 return callback.apply(thisObject, cbArguments || []); 4628 }finally{ 4629 dojo.doc = oldDoc; 4630 delete dojo._bodyLtr; // in case it was undefined originally, and set to true/false by the alternate document 4631 if(oldLtr !== undefined){ dojo._bodyLtr = oldLtr; } 4632 dojo.isQuirks = oldQ; 4633 } 4634 }; 4635 4636 } 4637 4638 if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 4639 dojo._hasResource["dojo._base.event"] = true; 4640 dojo.provide("dojo._base.event"); 4641 4642 4643 4644 // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA 4645 4646 (function(){ 4647 // DOM event listener machinery 4648 var del = (dojo._event_listener = { 4649 add: function(/*DOMNode*/ node, /*String*/ name, /*Function*/ fp){ 4650 if(!node){return;} 4651 name = del._normalizeEventName(name); 4652 fp = del._fixCallback(name, fp); 4653 if( 4654 !dojo.isIE && 4655 (name == "mouseenter" || name == "mouseleave") 4656 ){ 4657 var ofp = fp; 4658 name = (name == "mouseenter") ? "mouseover" : "mouseout"; 4659 fp = function(e){ 4660 if(!dojo.isDescendant(e.relatedTarget, node)){ 4661 // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable. 4662 return ofp.call(this, e); 4663 } 4664 } 4665 } 4666 node.addEventListener(name, fp, false); 4667 return fp; /*Handle*/ 4668 }, 4669 remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){ 4670 // summary: 4671 // clobbers the listener from the node 4672 // node: 4673 // DOM node to attach the event to 4674 // event: 4675 // the name of the handler to remove the function from 4676 // handle: 4677 // the handle returned from add 4678 if(node){ 4679 event = del._normalizeEventName(event); 4680 if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){ 4681 event = (event == "mouseenter") ? "mouseover" : "mouseout"; 4682 } 4683 4684 node.removeEventListener(event, handle, false); 4685 } 4686 }, 4687 _normalizeEventName: function(/*String*/ name){ 4688 // Generally, name should be lower case, unless it is special 4689 // somehow (e.g. a Mozilla DOM event). 4690 // Remove 'on'. 4691 return name.slice(0,2) =="on" ? name.slice(2) : name; 4692 }, 4693 _fixCallback: function(/*String*/ name, fp){ 4694 // By default, we only invoke _fixEvent for 'keypress' 4695 // If code is added to _fixEvent for other events, we have 4696 // to revisit this optimization. 4697 // This also applies to _fixEvent overrides for Safari and Opera 4698 // below. 4699 return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); }; 4700 }, 4701 _fixEvent: function(evt, sender){ 4702 // _fixCallback only attaches us to keypress. 4703 // Switch on evt.type anyway because we might 4704 // be called directly from dojo.fixEvent. 4705 switch(evt.type){ 4706 case "keypress": 4707 del._setKeyChar(evt); 4708 break; 4709 } 4710 return evt; 4711 }, 4712 _setKeyChar: function(evt){ 4713 evt.keyChar = evt.charCode >= 32 ? String.fromCharCode(evt.charCode) : ''; 4714 evt.charOrCode = evt.keyChar || evt.keyCode; 4715 }, 4716 // For IE and Safari: some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE 4717 // we map those virtual key codes to ascii here 4718 // not valid for all (non-US) keyboards, so maybe we shouldn't bother 4719 _punctMap: { 4720 106:42, 4721 111:47, 4722 186:59, 4723 187:43, 4724 188:44, 4725 189:45, 4726 190:46, 4727 191:47, 4728 192:96, 4729 219:91, 4730 220:92, 4731 221:93, 4732 222:39 4733 } 4734 }); 4735 4736 // DOM events 4737 4738 dojo.fixEvent = function(/*Event*/ evt, /*DOMNode*/ sender){ 4739 // summary: 4740 // normalizes properties on the event object including event 4741 // bubbling methods, keystroke normalization, and x/y positions 4742 // evt: Event 4743 // native event object 4744 // sender: DOMNode 4745 // node to treat as "currentTarget" 4746 return del._fixEvent(evt, sender); 4747 }; 4748 4749 dojo.stopEvent = function(/*Event*/ evt){ 4750 // summary: 4751 // prevents propagation and clobbers the default action of the 4752 // passed event 4753 // evt: Event 4754 // The event object. If omitted, window.event is used on IE. 4755 evt.preventDefault(); 4756 evt.stopPropagation(); 4757 // NOTE: below, this method is overridden for IE 4758 }; 4759 4760 // the default listener to use on dontFix nodes, overriden for IE 4761 var node_listener = dojo._listener; 4762 4763 // Unify connect and event listeners 4764 dojo._connect = function(obj, event, context, method, dontFix){ 4765 // FIXME: need a more strict test 4766 var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener); 4767 // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node 4768 // we need the third option to provide leak prevention on broken browsers (IE) 4769 var lid = isNode ? (dontFix ? 2 : 1) : 0, l = [dojo._listener, del, node_listener][lid]; 4770 // create a listener 4771 var h = l.add(obj, event, dojo.hitch(context, method)); 4772 // formerly, the disconnect package contained "l" directly, but if client code 4773 // leaks the disconnect package (by connecting it to a node), referencing "l" 4774 // compounds the problem. 4775 // instead we return a listener id, which requires custom _disconnect below. 4776 // return disconnect package 4777 return [ obj, event, h, lid ]; 4778 }; 4779 4780 dojo._disconnect = function(obj, event, handle, listener){ 4781 ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle); 4782 }; 4783 4784 // Constants 4785 4786 // Public: client code should test 4787 // keyCode against these named constants, as the 4788 // actual codes can vary by browser. 4789 dojo.keys = { 4790 // summary: 4791 // Definitions for common key values 4792 BACKSPACE: 8, 4793 TAB: 9, 4794 CLEAR: 12, 4795 ENTER: 13, 4796 SHIFT: 16, 4797 CTRL: 17, 4798 ALT: 18, 4799 META: dojo.isSafari ? 91 : 224, // the apple key on macs 4800 PAUSE: 19, 4801 CAPS_LOCK: 20, 4802 ESCAPE: 27, 4803 SPACE: 32, 4804 PAGE_UP: 33, 4805 PAGE_DOWN: 34, 4806 END: 35, 4807 HOME: 36, 4808 LEFT_ARROW: 37, 4809 UP_ARROW: 38, 4810 RIGHT_ARROW: 39, 4811 DOWN_ARROW: 40, 4812 INSERT: 45, 4813 DELETE: 46, 4814 HELP: 47, 4815 LEFT_WINDOW: 91, 4816 RIGHT_WINDOW: 92, 4817 SELECT: 93, 4818 NUMPAD_0: 96, 4819 NUMPAD_1: 97, 4820 NUMPAD_2: 98, 4821 NUMPAD_3: 99, 4822 NUMPAD_4: 100, 4823 NUMPAD_5: 101, 4824 NUMPAD_6: 102, 4825 NUMPAD_7: 103, 4826 NUMPAD_8: 104, 4827 NUMPAD_9: 105, 4828 NUMPAD_MULTIPLY: 106, 4829 NUMPAD_PLUS: 107, 4830 NUMPAD_ENTER: 108, 4831 NUMPAD_MINUS: 109, 4832 NUMPAD_PERIOD: 110, 4833 NUMPAD_DIVIDE: 111, 4834 F1: 112, 4835 F2: 113, 4836 F3: 114, 4837 F4: 115, 4838 F5: 116, 4839 F6: 117, 4840 F7: 118, 4841 F8: 119, 4842 F9: 120, 4843 F10: 121, 4844 F11: 122, 4845 F12: 123, 4846 F13: 124, 4847 F14: 125, 4848 F15: 126, 4849 NUM_LOCK: 144, 4850 SCROLL_LOCK: 145, 4851 // virtual key mapping 4852 copyKey: dojo.isMac && !dojo.isAIR ? (dojo.isSafari ? 91 : 224 ) : 17 4853 }; 4854 4855 var evtCopyKey = dojo.isMac ? "metaKey" : "ctrlKey"; 4856 4857 dojo.isCopyKey = function(e){ 4858 // summary: 4859 // Checks an event for the copy key (meta on Mac, and ctrl anywhere else) 4860 // e: Event 4861 // Event object to examine 4862 return e[evtCopyKey]; // Boolean 4863 }; 4864 4865 // Public: decoding mouse buttons from events 4866 4867 /*===== 4868 dojo.mouseButtons = { 4869 // LEFT: Number 4870 // Numeric value of the left mouse button for the platform. 4871 LEFT: 0, 4872 // MIDDLE: Number 4873 // Numeric value of the middle mouse button for the platform. 4874 MIDDLE: 1, 4875 // RIGHT: Number 4876 // Numeric value of the right mouse button for the platform. 4877 RIGHT: 2, 4878 4879 isButton: function(e, button){ 4880 // summary: 4881 // Checks an event object for a pressed button 4882 // e: Event 4883 // Event object to examine 4884 // button: Number 4885 // The button value (example: dojo.mouseButton.LEFT) 4886 return e.button == button; // Boolean 4887 }, 4888 isLeft: function(e){ 4889 // summary: 4890 // Checks an event object for the pressed left button 4891 // e: Event 4892 // Event object to examine 4893 return e.button == 0; // Boolean 4894 }, 4895 isMiddle: function(e){ 4896 // summary: 4897 // Checks an event object for the pressed middle button 4898 // e: Event 4899 // Event object to examine 4900 return e.button == 1; // Boolean 4901 }, 4902 isRight: function(e){ 4903 // summary: 4904 // Checks an event object for the pressed right button 4905 // e: Event 4906 // Event object to examine 4907 return e.button == 2; // Boolean 4908 } 4909 }; 4910 =====*/ 4911 4912 if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){ 4913 dojo.mouseButtons = { 4914 LEFT: 1, 4915 MIDDLE: 4, 4916 RIGHT: 2, 4917 // helper functions 4918 isButton: function(e, button){ return e.button & button; }, 4919 isLeft: function(e){ return e.button & 1; }, 4920 isMiddle: function(e){ return e.button & 4; }, 4921 isRight: function(e){ return e.button & 2; } 4922 }; 4923 }else{ 4924 dojo.mouseButtons = { 4925 LEFT: 0, 4926 MIDDLE: 1, 4927 RIGHT: 2, 4928 // helper functions 4929 isButton: function(e, button){ return e.button == button; }, 4930 isLeft: function(e){ return e.button == 0; }, 4931 isMiddle: function(e){ return e.button == 1; }, 4932 isRight: function(e){ return e.button == 2; } 4933 }; 4934 } 4935 4936 // IE event normalization 4937 if(dojo.isIE){ 4938 var _trySetKeyCode = function(e, code){ 4939 try{ 4940 // squelch errors when keyCode is read-only 4941 // (e.g. if keyCode is ctrl or shift) 4942 return (e.keyCode = code); 4943 }catch(e){ 4944 return 0; 4945 } 4946 }; 4947 4948 // by default, use the standard listener 4949 var iel = dojo._listener; 4950 var listenersName = (dojo._ieListenersName = "_" + dojo._scopeName + "_listeners"); 4951 // dispatcher tracking property 4952 if(!dojo.config._allow_leaks){ 4953 // custom listener that handles leak protection for DOM events 4954 node_listener = iel = dojo._ie_listener = { 4955 // support handler indirection: event handler functions are 4956 // referenced here. Event dispatchers hold only indices. 4957 handlers: [], 4958 // add a listener to an object 4959 add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){ 4960 source = source || dojo.global; 4961 var f = source[method]; 4962 if(!f||!f[listenersName]){ 4963 var d = dojo._getIeDispatcher(); 4964 // original target function is special 4965 d.target = f && (ieh.push(f) - 1); 4966 // dispatcher holds a list of indices into handlers table 4967 d[listenersName] = []; 4968 // redirect source to dispatcher 4969 f = source[method] = d; 4970 } 4971 return f[listenersName].push(ieh.push(listener) - 1) ; /*Handle*/ 4972 }, 4973 // remove a listener from an object 4974 remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){ 4975 var f = (source||dojo.global)[method], l = f && f[listenersName]; 4976 if(f && l && handle--){ 4977 delete ieh[l[handle]]; 4978 delete l[handle]; 4979 } 4980 } 4981 }; 4982 // alias used above 4983 var ieh = iel.handlers; 4984 } 4985 4986 dojo.mixin(del, { 4987 add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){ 4988 if(!node){return;} // undefined 4989 event = del._normalizeEventName(event); 4990 if(event=="onkeypress"){ 4991 // we need to listen to onkeydown to synthesize 4992 // keypress events that otherwise won't fire 4993 // on IE 4994 var kd = node.onkeydown; 4995 if(!kd || !kd[listenersName] || !kd._stealthKeydownHandle){ 4996 var h = del.add(node, "onkeydown", del._stealthKeyDown); 4997 kd = node.onkeydown; 4998 kd._stealthKeydownHandle = h; 4999 kd._stealthKeydownRefs = 1; 5000 }else{ 5001 kd._stealthKeydownRefs++; 5002 } 5003 } 5004 return iel.add(node, event, del._fixCallback(fp)); 5005 }, 5006 remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){ 5007 event = del._normalizeEventName(event); 5008 iel.remove(node, event, handle); 5009 if(event=="onkeypress"){ 5010 var kd = node.onkeydown; 5011 if(--kd._stealthKeydownRefs <= 0){ 5012 iel.remove(node, "onkeydown", kd._stealthKeydownHandle); 5013 delete kd._stealthKeydownHandle; 5014 } 5015 } 5016 }, 5017 _normalizeEventName: function(/*String*/ eventName){ 5018 // Generally, eventName should be lower case, unless it is 5019 // special somehow (e.g. a Mozilla event) 5020 // ensure 'on' 5021 return eventName.slice(0,2) != "on" ? "on" + eventName : eventName; 5022 }, 5023 _nop: function(){}, 5024 _fixEvent: function(/*Event*/ evt, /*DOMNode*/ sender){ 5025 // summary: 5026 // normalizes properties on the event object including event 5027 // bubbling methods, keystroke normalization, and x/y positions 5028 // evt: 5029 // native event object 5030 // sender: 5031 // node to treat as "currentTarget" 5032 if(!evt){ 5033 var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window; 5034 evt = w.event; 5035 } 5036 if(!evt){return(evt);} 5037 evt.target = evt.srcElement; 5038 evt.currentTarget = (sender || evt.srcElement); 5039 evt.layerX = evt.offsetX; 5040 evt.layerY = evt.offsetY; 5041 // FIXME: scroll position query is duped from dojo.html to 5042 // avoid dependency on that entire module. Now that HTML is in 5043 // Base, we should convert back to something similar there. 5044 var se = evt.srcElement, doc = (se && se.ownerDocument) || document; 5045 // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used 5046 // here rather than document.body 5047 var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement; 5048 var offset = dojo._getIeDocumentElementOffset(); 5049 evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x; 5050 evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y; 5051 if(evt.type == "mouseover"){ 5052 evt.relatedTarget = evt.fromElement; 5053 } 5054 if(evt.type == "mouseout"){ 5055 evt.relatedTarget = evt.toElement; 5056 } 5057 if (dojo.isIE < 9 || dojo.isQuirks) { 5058 evt.stopPropagation = del._stopPropagation; 5059 evt.preventDefault = del._preventDefault; 5060 } 5061 return del._fixKeys(evt); 5062 }, 5063 _fixKeys: function(evt){ 5064 switch(evt.type){ 5065 case "keypress": 5066 var c = ("charCode" in evt ? evt.charCode : evt.keyCode); 5067 if (c==10){ 5068 // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla 5069 c=0; 5070 evt.keyCode = 13; 5071 }else if(c==13||c==27){ 5072 c=0; // Mozilla considers ENTER and ESC non-printable 5073 }else if(c==3){ 5074 c=99; // Mozilla maps CTRL-BREAK to CTRL-c 5075 } 5076 // Mozilla sets keyCode to 0 when there is a charCode 5077 // but that stops the event on IE. 5078 evt.charCode = c; 5079 del._setKeyChar(evt); 5080 break; 5081 } 5082 return evt; 5083 }, 5084 _stealthKeyDown: function(evt){ 5085 // IE doesn't fire keypress for most non-printable characters. 5086 // other browsers do, we simulate it here. 5087 var kp = evt.currentTarget.onkeypress; 5088 // only works if kp exists and is a dispatcher 5089 if(!kp || !kp[listenersName]){ return; } 5090 // munge key/charCode 5091 var k=evt.keyCode; 5092 // These are Windows Virtual Key Codes 5093 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp 5094 var unprintable = (k!=13 || (dojo.isIE >= 9 && !dojo.isQuirks)) && k!=32 && k!=27 && (k<48||k>90) && (k<96||k>111) && (k<186||k>192) && (k<219||k>222); 5095 5096 // synthesize keypress for most unprintables and CTRL-keys 5097 if(unprintable||evt.ctrlKey){ 5098 var c = unprintable ? 0 : k; 5099 if(evt.ctrlKey){ 5100 if(k==3 || k==13){ 5101 return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively 5102 }else if(c>95 && c<106){ 5103 c -= 48; // map CTRL-[numpad 0-9] to ASCII 5104 }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ 5105 c += 32; // map CTRL-[A-Z] to lowercase 5106 }else{ 5107 c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII 5108 } 5109 } 5110 // simulate a keypress event 5111 var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c}); 5112 kp.call(evt.currentTarget, faux); 5113 if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){ 5114 evt.cancelBubble = faux.cancelBubble; 5115 } 5116 evt.returnValue = faux.returnValue; 5117 _trySetKeyCode(evt, faux.keyCode); 5118 } 5119 }, 5120 // Called in Event scope 5121 _stopPropagation: function(){ 5122 this.cancelBubble = true; 5123 }, 5124 _preventDefault: function(){ 5125 // Setting keyCode to 0 is the only way to prevent certain keypresses (namely 5126 // ctrl-combinations that correspond to menu accelerator keys). 5127 // Otoh, it prevents upstream listeners from getting this information 5128 // Try to split the difference here by clobbering keyCode only for ctrl 5129 // combinations. If you still need to access the key upstream, bubbledKeyCode is 5130 // provided as a workaround. 5131 this.bubbledKeyCode = this.keyCode; 5132 if(this.ctrlKey){_trySetKeyCode(this, 0);} 5133 this.returnValue = false; 5134 } 5135 }); 5136 5137 // override stopEvent for IE 5138 dojo.stopEvent = (dojo.isIE < 9 || dojo.isQuirks) ? function(evt){ 5139 evt = evt || window.event; 5140 del._stopPropagation.call(evt); 5141 del._preventDefault.call(evt); 5142 } : dojo.stopEvent; 5143 } 5144 5145 del._synthesizeEvent = function(evt, props){ 5146 var faux = dojo.mixin({}, evt, props); 5147 del._setKeyChar(faux); 5148 // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault); 5149 // but it throws an error when preventDefault is invoked on Safari 5150 // does Event.preventDefault not support "apply" on Safari? 5151 faux.preventDefault = function(){ evt.preventDefault(); }; 5152 faux.stopPropagation = function(){ evt.stopPropagation(); }; 5153 return faux; 5154 }; 5155 5156 // Opera event normalization 5157 if(dojo.isOpera){ 5158 dojo.mixin(del, { 5159 _fixEvent: function(evt, sender){ 5160 switch(evt.type){ 5161 case "keypress": 5162 var c = evt.which; 5163 if(c==3){ 5164 c=99; // Mozilla maps CTRL-BREAK to CTRL-c 5165 } 5166 // can't trap some keys at all, like INSERT and DELETE 5167 // there is no differentiating info between DELETE and ".", or INSERT and "-" 5168 c = c<41 && !evt.shiftKey ? 0 : c; 5169 if(evt.ctrlKey && !evt.shiftKey && c>=65 && c<=90){ 5170 // lowercase CTRL-[A-Z] keys 5171 c += 32; 5172 } 5173 return del._synthesizeEvent(evt, { charCode: c }); 5174 } 5175 return evt; 5176 } 5177 }); 5178 } 5179 5180 // Webkit event normalization 5181 if(dojo.isWebKit){ 5182 del._add = del.add; 5183 del._remove = del.remove; 5184 5185 dojo.mixin(del, { 5186 add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){ 5187 if(!node){return;} // undefined 5188 var handle = del._add(node, event, fp); 5189 if(del._normalizeEventName(event) == "keypress"){ 5190 // we need to listen to onkeydown to synthesize 5191 // keypress events that otherwise won't fire 5192 // in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html 5193 handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){ 5194 //A variation on the IE _stealthKeydown function 5195 //Synthesize an onkeypress event, but only for unprintable characters. 5196 var k=evt.keyCode; 5197 // These are Windows Virtual Key Codes 5198 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp 5199 var unprintable = k!=13 && k!=32 && (k<48 || k>90) && (k<96 || k>111) && (k<186 || k>192) && (k<219 || k>222); 5200 // synthesize keypress for most unprintables and CTRL-keys 5201 if(unprintable || evt.ctrlKey){ 5202 var c = unprintable ? 0 : k; 5203 if(evt.ctrlKey){ 5204 if(k==3 || k==13){ 5205 return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively 5206 }else if(c>95 && c<106){ 5207 c -= 48; // map CTRL-[numpad 0-9] to ASCII 5208 }else if(!evt.shiftKey && c>=65 && c<=90){ 5209 c += 32; // map CTRL-[A-Z] to lowercase 5210 }else{ 5211 c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII 5212 } 5213 } 5214 // simulate a keypress event 5215 var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c}); 5216 fp.call(evt.currentTarget, faux); 5217 } 5218 }); 5219 } 5220 return handle; /*Handle*/ 5221 }, 5222 5223 remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){ 5224 if(node){ 5225 if(handle._stealthKeyDownHandle){ 5226 del._remove(node, "keydown", handle._stealthKeyDownHandle); 5227 } 5228 del._remove(node, event, handle); 5229 } 5230 }, 5231 _fixEvent: function(evt, sender){ 5232 switch(evt.type){ 5233 case "keypress": 5234 if(evt.faux){ return evt; } 5235 var c = evt.charCode; 5236 c = c>=32 ? c : 0; 5237 return del._synthesizeEvent(evt, {charCode: c, faux: true}); 5238 } 5239 return evt; 5240 } 5241 }); 5242 } 5243 })(); 5244 5245 if(dojo.isIE){ 5246 // keep this out of the closure 5247 // closing over 'iel' or 'ieh' b0rks leak prevention 5248 // ls[i] is an index into the master handler array 5249 dojo._ieDispatcher = function(args, sender){ 5250 var ap = Array.prototype, 5251 h = dojo._ie_listener.handlers, 5252 c = args.callee, 5253 ls = c[dojo._ieListenersName], 5254 t = h[c.target]; 5255 // return value comes from original target function 5256 var r = t && t.apply(sender, args); 5257 // make local copy of listener array so it's immutable during processing 5258 var lls = [].concat(ls); 5259 // invoke listeners after target function 5260 for(var i in lls){ 5261 var f = h[lls[i]]; 5262 if(!(i in ap) && f){ 5263 f.apply(sender, args); 5264 } 5265 } 5266 return r; 5267 }; 5268 dojo._getIeDispatcher = function(){ 5269 // ensure the returned function closes over nothing ("new Function" apparently doesn't close) 5270 return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function 5271 }; 5272 // keep this out of the closure to reduce RAM allocation 5273 dojo._event_listener._fixCallback = function(fp){ 5274 var f = dojo._event_listener._fixEvent; 5275 return function(e){ return fp.call(this, f(e, this)); }; 5276 }; 5277 } 5278 5279 } 5280 5281 if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 5282 dojo._hasResource["dojo._base.html"] = true; 5283 dojo.provide("dojo._base.html"); 5284 5285 5286 5287 // FIXME: need to add unit tests for all the semi-public methods 5288 5289 try{ 5290 document.execCommand("BackgroundImageCache", false, true); 5291 }catch(e){ 5292 // sane browsers don't have cache "issues" 5293 } 5294 5295 // ============================= 5296 // DOM Functions 5297 // ============================= 5298 5299 /*===== 5300 dojo.byId = function(id, doc){ 5301 // summary: 5302 // Returns DOM node with matching `id` attribute or `null` 5303 // if not found. If `id` is a DomNode, this function is a no-op. 5304 // 5305 // id: String|DOMNode 5306 // A string to match an HTML id attribute or a reference to a DOM Node 5307 // 5308 // doc: Document? 5309 // Document to work in. Defaults to the current value of 5310 // dojo.doc. Can be used to retrieve 5311 // node references from other documents. 5312 // 5313 // example: 5314 // Look up a node by ID: 5315 // | var n = dojo.byId("foo"); 5316 // 5317 // example: 5318 // Check if a node exists, and use it. 5319 // | var n = dojo.byId("bar"); 5320 // | if(n){ doStuff() ... } 5321 // 5322 // example: 5323 // Allow string or DomNode references to be passed to a custom function: 5324 // | var foo = function(nodeOrId){ 5325 // | nodeOrId = dojo.byId(nodeOrId); 5326 // | // ... more stuff 5327 // | } 5328 =====*/ 5329 5330 if(dojo.isIE){ 5331 dojo.byId = function(id, doc){ 5332 if(typeof id != "string"){ 5333 return id; 5334 } 5335 var _d = doc || dojo.doc, te = _d.getElementById(id); 5336 // attributes.id.value is better than just id in case the 5337 // user has a name=id inside a form 5338 if(te && (te.attributes.id.value == id || te.id == id)){ 5339 return te; 5340 }else{ 5341 var eles = _d.all[id]; 5342 if(!eles || eles.nodeName){ 5343 eles = [eles]; 5344 } 5345 // if more than 1, choose first with the correct id 5346 var i=0; 5347 while((te=eles[i++])){ 5348 if((te.attributes && te.attributes.id && te.attributes.id.value == id) 5349 || te.id == id){ 5350 return te; 5351 } 5352 } 5353 } 5354 }; 5355 }else{ 5356 dojo.byId = function(id, doc){ 5357 // inline'd type check. 5358 // be sure to return null per documentation, to match IE branch. 5359 return ((typeof id == "string") ? (doc || dojo.doc).getElementById(id) : id) || null; // DomNode 5360 }; 5361 } 5362 /*===== 5363 }; 5364 =====*/ 5365 5366 (function(){ 5367 var d = dojo; 5368 var byId = d.byId; 5369 5370 var _destroyContainer = null, 5371 _destroyDoc; 5372 d.addOnWindowUnload(function(){ 5373 _destroyContainer = null; //prevent IE leak 5374 }); 5375 5376 /*===== 5377 dojo._destroyElement = function(node){ 5378 // summary: 5379 // Existing alias for `dojo.destroy`. Deprecated, will be removed 5380 // in 2.0 5381 } 5382 =====*/ 5383 dojo._destroyElement = dojo.destroy = function(/*String|DomNode*/node){ 5384 // summary: 5385 // Removes a node from its parent, clobbering it and all of its 5386 // children. 5387 // 5388 // description: 5389 // Removes a node from its parent, clobbering it and all of its 5390 // children. Function only works with DomNodes, and returns nothing. 5391 // 5392 // node: 5393 // A String ID or DomNode reference of the element to be destroyed 5394 // 5395 // example: 5396 // Destroy a node byId: 5397 // | dojo.destroy("someId"); 5398 // 5399 // example: 5400 // Destroy all nodes in a list by reference: 5401 // | dojo.query(".someNode").forEach(dojo.destroy); 5402 5403 node = byId(node); 5404 try{ 5405 var doc = node.ownerDocument; 5406 // cannot use _destroyContainer.ownerDocument since this can throw an exception on IE 5407 if(!_destroyContainer || _destroyDoc != doc){ 5408 _destroyContainer = doc.createElement("div"); 5409 _destroyDoc = doc; 5410 } 5411 _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); 5412 // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature 5413 _destroyContainer.innerHTML = ""; 5414 }catch(e){ 5415 /* squelch */ 5416 } 5417 }; 5418 5419 dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ 5420 // summary: 5421 // Returns true if node is a descendant of ancestor 5422 // node: string id or node reference to test 5423 // ancestor: string id or node reference of potential parent to test against 5424 // 5425 // example: 5426 // Test is node id="bar" is a descendant of node id="foo" 5427 // | if(dojo.isDescendant("bar", "foo")){ ... } 5428 try{ 5429 node = byId(node); 5430 ancestor = byId(ancestor); 5431 while(node){ 5432 if(node == ancestor){ 5433 return true; // Boolean 5434 } 5435 node = node.parentNode; 5436 } 5437 }catch(e){ /* squelch, return false */ } 5438 return false; // Boolean 5439 }; 5440 5441 dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){ 5442 // summary: 5443 // Enable or disable selection on a node 5444 // node: 5445 // id or reference to node 5446 // selectable: 5447 // state to put the node in. false indicates unselectable, true 5448 // allows selection. 5449 // example: 5450 // Make the node id="bar" unselectable 5451 // | dojo.setSelectable("bar"); 5452 // example: 5453 // Make the node id="bar" selectable 5454 // | dojo.setSelectable("bar", true); 5455 node = byId(node); 5456 if(d.isMozilla){ 5457 node.style.MozUserSelect = selectable ? "" : "none"; 5458 }else if(d.isKhtml || d.isWebKit){ 5459 node.style.KhtmlUserSelect = selectable ? "auto" : "none"; 5460 }else if(d.isIE){ 5461 var v = (node.unselectable = selectable ? "" : "on"); 5462 d.query("*", node).forEach("item.unselectable = '"+v+"'"); 5463 } 5464 //FIXME: else? Opera? 5465 }; 5466 5467 var _insertBefore = function(/*DomNode*/node, /*DomNode*/ref){ 5468 var parent = ref.parentNode; 5469 if(parent){ 5470 parent.insertBefore(node, ref); 5471 } 5472 }; 5473 5474 var _insertAfter = function(/*DomNode*/node, /*DomNode*/ref){ 5475 // summary: 5476 // Try to insert node after ref 5477 var parent = ref.parentNode; 5478 if(parent){ 5479 if(parent.lastChild == ref){ 5480 parent.appendChild(node); 5481 }else{ 5482 parent.insertBefore(node, ref.nextSibling); 5483 } 5484 } 5485 }; 5486 5487 dojo.place = function(node, refNode, position){ 5488 // summary: 5489 // Attempt to insert node into the DOM, choosing from various positioning options. 5490 // Returns the first argument resolved to a DOM node. 5491 // 5492 // node: String|DomNode 5493 // id or node reference, or HTML fragment starting with "<" to place relative to refNode 5494 // 5495 // refNode: String|DomNode 5496 // id or node reference to use as basis for placement 5497 // 5498 // position: String|Number? 5499 // string noting the position of node relative to refNode or a 5500 // number indicating the location in the childNodes collection of refNode. 5501 // Accepted string values are: 5502 // | * before 5503 // | * after 5504 // | * replace 5505 // | * only 5506 // | * first 5507 // | * last 5508 // "first" and "last" indicate positions as children of refNode, "replace" replaces refNode, 5509 // "only" replaces all children. position defaults to "last" if not specified 5510 // 5511 // returns: DomNode 5512 // Returned values is the first argument resolved to a DOM node. 5513 // 5514 // .place() is also a method of `dojo.NodeList`, allowing `dojo.query` node lookups. 5515 // 5516 // example: 5517 // Place a node by string id as the last child of another node by string id: 5518 // | dojo.place("someNode", "anotherNode"); 5519 // 5520 // example: 5521 // Place a node by string id before another node by string id 5522 // | dojo.place("someNode", "anotherNode", "before"); 5523 // 5524 // example: 5525 // Create a Node, and place it in the body element (last child): 5526 // | dojo.place("<div></div>", dojo.body()); 5527 // 5528 // example: 5529 // Put a new LI as the first child of a list by id: 5530 // | dojo.place("<li></li>", "someUl", "first"); 5531 5532 refNode = byId(refNode); 5533 if(typeof node == "string"){ // inline'd type check 5534 node = /^\s*</.test(node) ? d._toDom(node, refNode.ownerDocument) : byId(node); 5535 } 5536 if(typeof position == "number"){ // inline'd type check 5537 var cn = refNode.childNodes; 5538 if(!cn.length || cn.length <= position){ 5539 refNode.appendChild(node); 5540 }else{ 5541 _insertBefore(node, cn[position < 0 ? 0 : position]); 5542 } 5543 }else{ 5544 switch(position){ 5545 case "before": 5546 _insertBefore(node, refNode); 5547 break; 5548 case "after": 5549 _insertAfter(node, refNode); 5550 break; 5551 case "replace": 5552 refNode.parentNode.replaceChild(node, refNode); 5553 break; 5554 case "only": 5555 d.empty(refNode); 5556 refNode.appendChild(node); 5557 break; 5558 case "first": 5559 if(refNode.firstChild){ 5560 _insertBefore(node, refNode.firstChild); 5561 break; 5562 } 5563 // else fallthrough... 5564 default: // aka: last 5565 refNode.appendChild(node); 5566 } 5567 } 5568 return node; // DomNode 5569 }; 5570 5571 // Box functions will assume this model. 5572 // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode. 5573 // Can be set to change behavior of box setters. 5574 5575 // can be either: 5576 // "border-box" 5577 // "content-box" (default) 5578 dojo.boxModel = "content-box"; 5579 5580 // We punt per-node box mode testing completely. 5581 // If anybody cares, we can provide an additional (optional) unit 5582 // that overrides existing code to include per-node box sensitivity. 5583 5584 // Opera documentation claims that Opera 9 uses border-box in BackCompat mode. 5585 // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box. 5586 // IIRC, earlier versions of Opera did in fact use border-box. 5587 // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault. 5588 5589 if(d.isIE /*|| dojo.isOpera*/){ 5590 // client code may have to adjust if compatMode varies across iframes 5591 d.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box"; 5592 } 5593 5594 // ============================= 5595 // Style Functions 5596 // ============================= 5597 5598 // getComputedStyle drives most of the style code. 5599 // Wherever possible, reuse the returned object. 5600 // 5601 // API functions below that need to access computed styles accept an 5602 // optional computedStyle parameter. 5603 // If this parameter is omitted, the functions will call getComputedStyle themselves. 5604 // This way, calling code can access computedStyle once, and then pass the reference to 5605 // multiple API functions. 5606 5607 /*===== 5608 dojo.getComputedStyle = function(node){ 5609 // summary: 5610 // Returns a "computed style" object. 5611 // 5612 // description: 5613 // Gets a "computed style" object which can be used to gather 5614 // information about the current state of the rendered node. 5615 // 5616 // Note that this may behave differently on different browsers. 5617 // Values may have different formats and value encodings across 5618 // browsers. 5619 // 5620 // Note also that this method is expensive. Wherever possible, 5621 // reuse the returned object. 5622 // 5623 // Use the dojo.style() method for more consistent (pixelized) 5624 // return values. 5625 // 5626 // node: DOMNode 5627 // A reference to a DOM node. Does NOT support taking an 5628 // ID string for speed reasons. 5629 // example: 5630 // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth; 5631 // 5632 // example: 5633 // Reusing the returned object, avoiding multiple lookups: 5634 // | var cs = dojo.getComputedStyle(dojo.byId("someNode")); 5635 // | var w = cs.width, h = cs.height; 5636 return; // CSS2Properties 5637 } 5638 =====*/ 5639 5640 // Although we normally eschew argument validation at this 5641 // level, here we test argument 'node' for (duck)type, 5642 // by testing nodeType, ecause 'document' is the 'parentNode' of 'body' 5643 // it is frequently sent to this function even 5644 // though it is not Element. 5645 var gcs; 5646 if(d.isWebKit){ 5647 gcs = function(/*DomNode*/node){ 5648 var s; 5649 if(node.nodeType == 1){ 5650 var dv = node.ownerDocument.defaultView; 5651 s = dv.getComputedStyle(node, null); 5652 if(!s && node.style){ 5653 node.style.display = ""; 5654 s = dv.getComputedStyle(node, null); 5655 } 5656 } 5657 return s || {}; 5658 }; 5659 }else if(d.isIE){ 5660 gcs = function(node){ 5661 // IE (as of 7) doesn't expose Element like sane browsers 5662 return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {}; 5663 }; 5664 }else{ 5665 gcs = function(node){ 5666 return node.nodeType == 1 ? 5667 node.ownerDocument.defaultView.getComputedStyle(node, null) : {}; 5668 }; 5669 } 5670 dojo.getComputedStyle = gcs; 5671 5672 if(!d.isIE){ 5673 d._toPixelValue = function(element, value){ 5674 // style values can be floats, client code may want 5675 // to round for integer pixels. 5676 return parseFloat(value) || 0; 5677 }; 5678 }else{ 5679 d._toPixelValue = function(element, avalue){ 5680 if(!avalue){ return 0; } 5681 // on IE7, medium is usually 4 pixels 5682 if(avalue == "medium"){ return 4; } 5683 // style values can be floats, client code may 5684 // want to round this value for integer pixels. 5685 if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); } 5686 with(element){ 5687 var sLeft = style.left; 5688 var rsLeft = runtimeStyle.left; 5689 runtimeStyle.left = currentStyle.left; 5690 try{ 5691 // 'avalue' may be incompatible with style.left, which can cause IE to throw 5692 // this has been observed for border widths using "thin", "medium", "thick" constants 5693 // those particular constants could be trapped by a lookup 5694 // but perhaps there are more 5695 style.left = avalue; 5696 avalue = style.pixelLeft; 5697 }catch(e){ 5698 avalue = 0; 5699 } 5700 style.left = sLeft; 5701 runtimeStyle.left = rsLeft; 5702 } 5703 return avalue; 5704 }; 5705 } 5706 var px = d._toPixelValue; 5707 5708 // FIXME: there opacity quirks on FF that we haven't ported over. Hrm. 5709 /*===== 5710 dojo._getOpacity = function(node){ 5711 // summary: 5712 // Returns the current opacity of the passed node as a 5713 // floating-point value between 0 and 1. 5714 // node: DomNode 5715 // a reference to a DOM node. Does NOT support taking an 5716 // ID string for speed reasons. 5717 // returns: Number between 0 and 1 5718 return; // Number 5719 } 5720 =====*/ 5721 5722 var astr = "DXImageTransform.Microsoft.Alpha"; 5723 var af = function(n, f){ 5724 try{ 5725 return n.filters.item(astr); 5726 }catch(e){ 5727 return f ? {} : null; 5728 } 5729 }; 5730 5731 dojo._getOpacity = 5732 d.isIE < 9 ? function(node){ 5733 try{ 5734 return af(node).Opacity / 100; // Number 5735 }catch(e){ 5736 return 1; // Number 5737 } 5738 } : 5739 function(node){ 5740 return gcs(node).opacity; 5741 }; 5742 5743 /*===== 5744 dojo._setOpacity = function(node, opacity){ 5745 // summary: 5746 // set the opacity of the passed node portably. Returns the 5747 // new opacity of the node. 5748 // node: DOMNode 5749 // a reference to a DOM node. Does NOT support taking an 5750 // ID string for performance reasons. 5751 // opacity: Number 5752 // A Number between 0 and 1. 0 specifies transparent. 5753 // returns: Number between 0 and 1 5754 return; // Number 5755 } 5756 =====*/ 5757 5758 dojo._setOpacity = 5759 d.isIE < 9 ? function(/*DomNode*/node, /*Number*/opacity){ 5760 var ov = opacity * 100, opaque = opacity == 1; 5761 node.style.zoom = opaque ? "" : 1; 5762 5763 if(!af(node)){ 5764 if(opaque){ 5765 return opacity; 5766 } 5767 node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; 5768 }else{ 5769 af(node, 1).Opacity = ov; 5770 } 5771 5772 // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661), 5773 //but still update the opacity value so we can get a correct reading if it is read later. 5774 af(node, 1).Enabled = !opaque; 5775 5776 if(node.nodeName.toLowerCase() == "tr"){ 5777 d.query("> td", node).forEach(function(i){ 5778 d._setOpacity(i, opacity); 5779 }); 5780 } 5781 return opacity; 5782 } : 5783 function(node, opacity){ 5784 return node.style.opacity = opacity; 5785 }; 5786 5787 var _pixelNamesCache = { 5788 left: true, top: true 5789 }; 5790 var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border 5791 var _toStyleValue = function(node, type, value){ 5792 type = type.toLowerCase(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile! 5793 if(d.isIE){ 5794 if(value == "auto"){ 5795 if(type == "height"){ return node.offsetHeight; } 5796 if(type == "width"){ return node.offsetWidth; } 5797 } 5798 if(type == "fontweight"){ 5799 switch(value){ 5800 case 700: return "bold"; 5801 case 400: 5802 default: return "normal"; 5803 } 5804 } 5805 } 5806 if(!(type in _pixelNamesCache)){ 5807 _pixelNamesCache[type] = _pixelRegExp.test(type); 5808 } 5809 return _pixelNamesCache[type] ? px(node, value) : value; 5810 }; 5811 5812 var _floatStyle = d.isIE ? "styleFloat" : "cssFloat", 5813 _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle } 5814 ; 5815 5816 // public API 5817 5818 dojo.style = function( /*DomNode|String*/ node, 5819 /*String?|Object?*/ style, 5820 /*String?*/ value){ 5821 // summary: 5822 // Accesses styles on a node. If 2 arguments are 5823 // passed, acts as a getter. If 3 arguments are passed, acts 5824 // as a setter. 5825 // description: 5826 // Getting the style value uses the computed style for the node, so the value 5827 // will be a calculated value, not just the immediate node.style value. 5828 // Also when getting values, use specific style names, 5829 // like "borderBottomWidth" instead of "border" since compound values like 5830 // "border" are not necessarily reflected as expected. 5831 // If you want to get node dimensions, use `dojo.marginBox()`, 5832 // `dojo.contentBox()` or `dojo.position()`. 5833 // node: 5834 // id or reference to node to get/set style for 5835 // style: 5836 // the style property to set in DOM-accessor format 5837 // ("borderWidth", not "border-width") or an object with key/value 5838 // pairs suitable for setting each property. 5839 // value: 5840 // If passed, sets value on the node for style, handling 5841 // cross-browser concerns. When setting a pixel value, 5842 // be sure to include "px" in the value. For instance, top: "200px". 5843 // Otherwise, in some cases, some browsers will not apply the style. 5844 // example: 5845 // Passing only an ID or node returns the computed style object of 5846 // the node: 5847 // | dojo.style("thinger"); 5848 // example: 5849 // Passing a node and a style property returns the current 5850 // normalized, computed value for that property: 5851 // | dojo.style("thinger", "opacity"); // 1 by default 5852 // 5853 // example: 5854 // Passing a node, a style property, and a value changes the 5855 // current display of the node and returns the new computed value 5856 // | dojo.style("thinger", "opacity", 0.5); // == 0.5 5857 // 5858 // example: 5859 // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node: 5860 // | dojo.style("thinger", { 5861 // | "opacity": 0.5, 5862 // | "border": "3px solid black", 5863 // | "height": "300px" 5864 // | }); 5865 // 5866 // example: 5867 // When the CSS style property is hyphenated, the JavaScript property is camelCased. 5868 // font-size becomes fontSize, and so on. 5869 // | dojo.style("thinger",{ 5870 // | fontSize:"14pt", 5871 // | letterSpacing:"1.2em" 5872 // | }); 5873 // 5874 // example: 5875 // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling 5876 // dojo.style() on every element of the list. See: `dojo.query()` and `dojo.NodeList()` 5877 // | dojo.query(".someClassName").style("visibility","hidden"); 5878 // | // or 5879 // | dojo.query("#baz > div").style({ 5880 // | opacity:0.75, 5881 // | fontSize:"13pt" 5882 // | }); 5883 5884 var n = byId(node), args = arguments.length, op = (style == "opacity"); 5885 style = _floatAliases[style] || style; 5886 if(args == 3){ 5887 return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/ 5888 } 5889 if(args == 2 && op){ 5890 return d._getOpacity(n); 5891 } 5892 var s = gcs(n); 5893 if(args == 2 && typeof style != "string"){ // inline'd type check 5894 for(var x in style){ 5895 d.style(node, x, style[x]); 5896 } 5897 return s; 5898 } 5899 return (args == 1) ? s : _toStyleValue(n, style, s[style] || n.style[style]); /* CSS2Properties||String||Number */ 5900 }; 5901 5902 // ============================= 5903 // Box Functions 5904 // ============================= 5905 5906 dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){ 5907 // summary: 5908 // Returns object with special values specifically useful for node 5909 // fitting. 5910 // description: 5911 // Returns an object with `w`, `h`, `l`, `t` properties: 5912 // | l/t = left/top padding (respectively) 5913 // | w = the total of the left and right padding 5914 // | h = the total of the top and bottom padding 5915 // If 'node' has position, l/t forms the origin for child nodes. 5916 // The w/h are used for calculating boxes. 5917 // Normally application code will not need to invoke this 5918 // directly, and will use the ...box... functions instead. 5919 var 5920 s = computedStyle||gcs(n), 5921 l = px(n, s.paddingLeft), 5922 t = px(n, s.paddingTop); 5923 return { 5924 l: l, 5925 t: t, 5926 w: l+px(n, s.paddingRight), 5927 h: t+px(n, s.paddingBottom) 5928 }; 5929 }; 5930 5931 dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){ 5932 // summary: 5933 // returns an object with properties useful for noting the border 5934 // dimensions. 5935 // description: 5936 // * l/t = the sum of left/top border (respectively) 5937 // * w = the sum of the left and right border 5938 // * h = the sum of the top and bottom border 5939 // 5940 // The w/h are used for calculating boxes. 5941 // Normally application code will not need to invoke this 5942 // directly, and will use the ...box... functions instead. 5943 var 5944 ne = "none", 5945 s = computedStyle||gcs(n), 5946 bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0), 5947 bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0); 5948 return { 5949 l: bl, 5950 t: bt, 5951 w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0), 5952 h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0) 5953 }; 5954 }; 5955 5956 dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){ 5957 // summary: 5958 // Returns object with properties useful for box fitting with 5959 // regards to padding. 5960 // description: 5961 // * l/t = the sum of left/top padding and left/top border (respectively) 5962 // * w = the sum of the left and right padding and border 5963 // * h = the sum of the top and bottom padding and border 5964 // 5965 // The w/h are used for calculating boxes. 5966 // Normally application code will not need to invoke this 5967 // directly, and will use the ...box... functions instead. 5968 var 5969 s = computedStyle||gcs(n), 5970 p = d._getPadExtents(n, s), 5971 b = d._getBorderExtents(n, s); 5972 return { 5973 l: p.l + b.l, 5974 t: p.t + b.t, 5975 w: p.w + b.w, 5976 h: p.h + b.h 5977 }; 5978 }; 5979 5980 dojo._getMarginExtents = function(n, computedStyle){ 5981 // summary: 5982 // returns object with properties useful for box fitting with 5983 // regards to box margins (i.e., the outer-box). 5984 // 5985 // * l/t = marginLeft, marginTop, respectively 5986 // * w = total width, margin inclusive 5987 // * h = total height, margin inclusive 5988 // 5989 // The w/h are used for calculating boxes. 5990 // Normally application code will not need to invoke this 5991 // directly, and will use the ...box... functions instead. 5992 var 5993 s = computedStyle||gcs(n), 5994 l = px(n, s.marginLeft), 5995 t = px(n, s.marginTop), 5996 r = px(n, s.marginRight), 5997 b = px(n, s.marginBottom); 5998 if(d.isWebKit && (s.position != "absolute")){ 5999 // FIXME: Safari's version of the computed right margin 6000 // is the space between our right edge and the right edge 6001 // of our offsetParent. 6002 // What we are looking for is the actual margin value as 6003 // determined by CSS. 6004 // Hack solution is to assume left/right margins are the same. 6005 r = l; 6006 } 6007 return { 6008 l: l, 6009 t: t, 6010 w: l+r, 6011 h: t+b 6012 }; 6013 }; 6014 6015 // Box getters work in any box context because offsetWidth/clientWidth 6016 // are invariant wrt box context 6017 // 6018 // They do *not* work for display: inline objects that have padding styles 6019 // because the user agent ignores padding (it's bogus styling in any case) 6020 // 6021 // Be careful with IMGs because they are inline or block depending on 6022 // browser and browser mode. 6023 6024 // Although it would be easier to read, there are not separate versions of 6025 // _getMarginBox for each browser because: 6026 // 1. the branching is not expensive 6027 // 2. factoring the shared code wastes cycles (function call overhead) 6028 // 3. duplicating the shared code wastes bytes 6029 6030 dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){ 6031 // summary: 6032 // returns an object that encodes the width, height, left and top 6033 // positions of the node's margin box. 6034 var s = computedStyle || gcs(node), me = d._getMarginExtents(node, s); 6035 var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode; 6036 if(d.isMoz){ 6037 // Mozilla: 6038 // If offsetParent has a computed overflow != visible, the offsetLeft is decreased 6039 // by the parent's border. 6040 // We don't want to compute the parent's style, so instead we examine node's 6041 // computed left/top which is more stable. 6042 var sl = parseFloat(s.left), st = parseFloat(s.top); 6043 if(!isNaN(sl) && !isNaN(st)){ 6044 l = sl, t = st; 6045 }else{ 6046 // If child's computed left/top are not parseable as a number (e.g. "auto"), we 6047 // have no choice but to examine the parent's computed style. 6048 if(p && p.style){ 6049 var pcs = gcs(p); 6050 if(pcs.overflow != "visible"){ 6051 var be = d._getBorderExtents(p, pcs); 6052 l += be.l, t += be.t; 6053 } 6054 } 6055 } 6056 }else if(d.isOpera || (d.isIE > 7 && !d.isQuirks)){ 6057 // On Opera and IE 8, offsetLeft/Top includes the parent's border 6058 if(p){ 6059 be = d._getBorderExtents(p); 6060 l -= be.l; 6061 t -= be.t; 6062 } 6063 } 6064 return { 6065 l: l, 6066 t: t, 6067 w: node.offsetWidth + me.w, 6068 h: node.offsetHeight + me.h 6069 }; 6070 } 6071 6072 dojo._getMarginSize = function(/*DomNode*/node, /*Object*/computedStyle){ 6073 // summary: 6074 // returns an object that encodes the width and height of 6075 // the node's margin box 6076 node = byId(node); 6077 var me = d._getMarginExtents(node, computedStyle || gcs(node)); 6078 6079 var size = node.getBoundingClientRect(); 6080 return { 6081 w: (size.right - size.left) + me.w, 6082 h: (size.bottom - size.top) + me.h 6083 } 6084 } 6085 6086 dojo._getContentBox = function(node, computedStyle){ 6087 // summary: 6088 // Returns an object that encodes the width, height, left and top 6089 // positions of the node's content box, irrespective of the 6090 // current box model. 6091 6092 // clientWidth/Height are important since the automatically account for scrollbars 6093 // fallback to offsetWidth/Height for special cases (see #3378) 6094 var s = computedStyle || gcs(node), 6095 pe = d._getPadExtents(node, s), 6096 be = d._getBorderExtents(node, s), 6097 w = node.clientWidth, 6098 h 6099 ; 6100 if(!w){ 6101 w = node.offsetWidth, h = node.offsetHeight; 6102 }else{ 6103 h = node.clientHeight, be.w = be.h = 0; 6104 } 6105 // On Opera, offsetLeft includes the parent's border 6106 if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; 6107 return { 6108 l: pe.l, 6109 t: pe.t, 6110 w: w - pe.w - be.w, 6111 h: h - pe.h - be.h 6112 }; 6113 }; 6114 6115 dojo._getBorderBox = function(node, computedStyle){ 6116 var s = computedStyle || gcs(node), 6117 pe = d._getPadExtents(node, s), 6118 cb = d._getContentBox(node, s) 6119 ; 6120 return { 6121 l: cb.l - pe.l, 6122 t: cb.t - pe.t, 6123 w: cb.w + pe.w, 6124 h: cb.h + pe.h 6125 }; 6126 }; 6127 6128 // Box setters depend on box context because interpretation of width/height styles 6129 // vary wrt box context. 6130 // 6131 // The value of dojo.boxModel is used to determine box context. 6132 // dojo.boxModel can be set directly to change behavior. 6133 // 6134 // Beware of display: inline objects that have padding styles 6135 // because the user agent ignores padding (it's a bogus setup anyway) 6136 // 6137 // Be careful with IMGs because they are inline or block depending on 6138 // browser and browser mode. 6139 // 6140 // Elements other than DIV may have special quirks, like built-in 6141 // margins or padding, or values not detectable via computedStyle. 6142 // In particular, margins on TABLE do not seems to appear 6143 // at all in computedStyle on Mozilla. 6144 6145 dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){ 6146 // summary: 6147 // sets width/height/left/top in the current (native) box-model 6148 // dimentions. Uses the unit passed in u. 6149 // node: 6150 // DOM Node reference. Id string not supported for performance 6151 // reasons. 6152 // l: 6153 // left offset from parent. 6154 // t: 6155 // top offset from parent. 6156 // w: 6157 // width in current box model. 6158 // h: 6159 // width in current box model. 6160 // u: 6161 // unit measure to use for other measures. Defaults to "px". 6162 u = u || "px"; 6163 var s = node.style; 6164 if(!isNaN(l)){ s.left = l + u; } 6165 if(!isNaN(t)){ s.top = t + u; } 6166 if(w >= 0){ s.width = w + u; } 6167 if(h >= 0){ s.height = h + u; } 6168 }; 6169 6170 dojo._isButtonTag = function(/*DomNode*/node) { 6171 // summary: 6172 // True if the node is BUTTON or INPUT.type="button". 6173 return node.tagName == "BUTTON" 6174 || node.tagName=="INPUT" && (node.getAttribute("type")||'').toUpperCase() == "BUTTON"; // boolean 6175 }; 6176 6177 dojo._usesBorderBox = function(/*DomNode*/node){ 6178 // summary: 6179 // True if the node uses border-box layout. 6180 6181 // We could test the computed style of node to see if a particular box 6182 // has been specified, but there are details and we choose not to bother. 6183 6184 // TABLE and BUTTON (and INPUT type=button) are always border-box by default. 6185 // If you have assigned a different box to either one via CSS then 6186 // box functions will break. 6187 6188 var n = node.tagName; 6189 return d.boxModel=="border-box" || n=="TABLE" || d._isButtonTag(node); // boolean 6190 }; 6191 6192 dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){ 6193 // summary: 6194 // Sets the size of the node's contents, irrespective of margins, 6195 // padding, or borders. 6196 if(d._usesBorderBox(node)){ 6197 var pb = d._getPadBorderExtents(node, computedStyle); 6198 if(widthPx >= 0){ widthPx += pb.w; } 6199 if(heightPx >= 0){ heightPx += pb.h; } 6200 } 6201 d._setBox(node, NaN, NaN, widthPx, heightPx); 6202 }; 6203 6204 dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx, 6205 /*Number?*/widthPx, /*Number?*/heightPx, 6206 /*Object*/computedStyle){ 6207 // summary: 6208 // sets the size of the node's margin box and placement 6209 // (left/top), irrespective of box model. Think of it as a 6210 // passthrough to dojo._setBox that handles box-model vagaries for 6211 // you. 6212 6213 var s = computedStyle || gcs(node), 6214 // Some elements have special padding, margin, and box-model settings. 6215 // To use box functions you may need to set padding, margin explicitly. 6216 // Controlling box-model is harder, in a pinch you might set dojo.boxModel. 6217 bb = d._usesBorderBox(node), 6218 pb = bb ? _nilExtents : d._getPadBorderExtents(node, s) 6219 ; 6220 if(d.isWebKit){ 6221 // on Safari (3.1.2), button nodes with no explicit size have a default margin 6222 // setting an explicit size eliminates the margin. 6223 // We have to swizzle the width to get correct margin reading. 6224 if(d._isButtonTag(node)){ 6225 var ns = node.style; 6226 if(widthPx >= 0 && !ns.width) { ns.width = "4px"; } 6227 if(heightPx >= 0 && !ns.height) { ns.height = "4px"; } 6228 } 6229 } 6230 var mb = d._getMarginExtents(node, s); 6231 if(widthPx >= 0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); } 6232 if(heightPx >= 0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); } 6233 d._setBox(node, leftPx, topPx, widthPx, heightPx); 6234 }; 6235 6236 var _nilExtents = { l:0, t:0, w:0, h:0 }; 6237 6238 // public API 6239 6240 dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){ 6241 // summary: 6242 // Getter/setter for the margin-box of node. 6243 // description: 6244 // Getter/setter for the margin-box of node. 6245 // Returns an object in the expected format of box (regardless 6246 // if box is passed). The object might look like: 6247 // `{ l: 50, t: 200, w: 300: h: 150 }` 6248 // for a node offset from its parent 50px to the left, 200px from 6249 // the top with a margin width of 300px and a margin-height of 6250 // 150px. 6251 // node: 6252 // id or reference to DOM Node to get/set box for 6253 // box: 6254 // If passed, denotes that dojo.marginBox() should 6255 // update/set the margin box for node. Box is an object in the 6256 // above format. All properties are optional if passed. 6257 // example: 6258 // Retrieve the marginbox of a passed node 6259 // | var box = dojo.marginBox("someNodeId"); 6260 // | console.dir(box); 6261 // 6262 // example: 6263 // Set a node's marginbox to the size of another node 6264 // | var box = dojo.marginBox("someNodeId"); 6265 // | dojo.marginBox("someOtherNode", box); 6266 6267 var n = byId(node), s = gcs(n), b = box; 6268 return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object 6269 }; 6270 6271 dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){ 6272 // summary: 6273 // Getter/setter for the content-box of node. 6274 // description: 6275 // Returns an object in the expected format of box (regardless if box is passed). 6276 // The object might look like: 6277 // `{ l: 50, t: 200, w: 300: h: 150 }` 6278 // for a node offset from its parent 50px to the left, 200px from 6279 // the top with a content width of 300px and a content-height of 6280 // 150px. Note that the content box may have a much larger border 6281 // or margin box, depending on the box model currently in use and 6282 // CSS values set/inherited for node. 6283 // While the getter will return top and left values, the 6284 // setter only accepts setting the width and height. 6285 // node: 6286 // id or reference to DOM Node to get/set box for 6287 // box: 6288 // If passed, denotes that dojo.contentBox() should 6289 // update/set the content box for node. Box is an object in the 6290 // above format, but only w (width) and h (height) are supported. 6291 // All properties are optional if passed. 6292 var n = byId(node), s = gcs(n), b = box; 6293 return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object 6294 }; 6295 6296 // ============================= 6297 // Positioning 6298 // ============================= 6299 6300 var _sumAncestorProperties = function(node, prop){ 6301 if(!(node = (node||0).parentNode)){return 0;} 6302 var val, retVal = 0, _b = d.body(); 6303 while(node && node.style){ 6304 if(gcs(node).position == "fixed"){ 6305 return 0; 6306 } 6307 val = node[prop]; 6308 if(val){ 6309 retVal += val - 0; 6310 // opera and khtml #body & #html has the same values, we only 6311 // need one value 6312 if(node == _b){ break; } 6313 } 6314 node = node.parentNode; 6315 } 6316 return retVal; // integer 6317 }; 6318 6319 dojo._docScroll = function(){ 6320 var n = d.global; 6321 return "pageXOffset" in n 6322 ? { x:n.pageXOffset, y:n.pageYOffset } 6323 : (n = d.isQuirks? d.doc.body : d.doc.documentElement, { x:d._fixIeBiDiScrollLeft(n.scrollLeft || 0), y:n.scrollTop || 0 }); 6324 }; 6325 6326 dojo._isBodyLtr = function(){ 6327 return "_bodyLtr" in d? d._bodyLtr : 6328 d._bodyLtr = (d.body().dir || d.doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean 6329 }; 6330 6331 dojo._getIeDocumentElementOffset = function(){ 6332 // summary: 6333 // returns the offset in x and y from the document body to the 6334 // visual edge of the page 6335 // description: 6336 // The following values in IE contain an offset: 6337 // | event.clientX 6338 // | event.clientY 6339 // | node.getBoundingClientRect().left 6340 // | node.getBoundingClientRect().top 6341 // But other position related values do not contain this offset, 6342 // such as node.offsetLeft, node.offsetTop, node.style.left and 6343 // node.style.top. The offset is always (2, 2) in LTR direction. 6344 // When the body is in RTL direction, the offset counts the width 6345 // of left scroll bar's width. This function computes the actual 6346 // offset. 6347 6348 //NOTE: assumes we're being called in an IE browser 6349 6350 var de = d.doc.documentElement; // only deal with HTML element here, _abs handles body/quirks 6351 6352 if(d.isIE < 8){ 6353 var r = de.getBoundingClientRect(); // works well for IE6+ 6354 //console.debug('rect left,top = ' + r.left+','+r.top + ', html client left/top = ' + de.clientLeft+','+de.clientTop + ', rtl = ' + (!d._isBodyLtr()) + ', quirks = ' + d.isQuirks); 6355 var l = r.left, 6356 t = r.top; 6357 if(d.isIE < 7){ 6358 l += de.clientLeft; // scrollbar size in strict/RTL, or, 6359 t += de.clientTop; // HTML border size in strict 6360 } 6361 return { 6362 x: l < 0? 0 : l, // FRAME element border size can lead to inaccurate negative values 6363 y: t < 0? 0 : t 6364 }; 6365 }else{ 6366 return { 6367 x: 0, 6368 y: 0 6369 }; 6370 } 6371 6372 }; 6373 6374 dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){ 6375 // In RTL direction, scrollLeft should be a negative value, but IE 6376 // returns a positive one. All codes using documentElement.scrollLeft 6377 // must call this function to fix this error, otherwise the position 6378 // will offset to right when there is a horizontal scrollbar. 6379 6380 var ie = d.isIE; 6381 if(ie && !d._isBodyLtr()){ 6382 var qk = d.isQuirks, 6383 de = qk ? d.doc.body : d.doc.documentElement; 6384 if(ie == 6 && !qk && d.global.frameElement && de.scrollHeight > de.clientHeight){ 6385 scrollLeft += de.clientLeft; // workaround ie6+strict+rtl+iframe+vertical-scrollbar bug where clientWidth is too small by clientLeft pixels 6386 } 6387 return (ie < 8 || qk) ? (scrollLeft + de.clientWidth - de.scrollWidth) : -scrollLeft; // Integer 6388 } 6389 return scrollLeft; // Integer 6390 }; 6391 6392 // FIXME: need a setter for coords or a moveTo!! 6393 dojo._abs = dojo.position = function(/*DomNode*/node, /*Boolean?*/includeScroll){ 6394 // summary: 6395 // Gets the position and size of the passed element relative to 6396 // the viewport (if includeScroll==false), or relative to the 6397 // document root (if includeScroll==true). 6398 // 6399 // description: 6400 // Returns an object of the form: 6401 // { x: 100, y: 300, w: 20, h: 15 } 6402 // If includeScroll==true, the x and y values will include any 6403 // document offsets that may affect the position relative to the 6404 // viewport. 6405 // Uses the border-box model (inclusive of border and padding but 6406 // not margin). Does not act as a setter. 6407 6408 node = byId(node); 6409 var db = d.body(), 6410 dh = db.parentNode, 6411 ret = node.getBoundingClientRect(); 6412 ret = { x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top }; 6413 if(d.isIE){ 6414 // On IE there's a 2px offset that we need to adjust for, see _getIeDocumentElementOffset() 6415 var offset = d._getIeDocumentElementOffset(); 6416 6417 // fixes the position in IE, quirks mode 6418 ret.x -= offset.x + (d.isQuirks ? db.clientLeft+db.offsetLeft : 0); 6419 ret.y -= offset.y + (d.isQuirks ? db.clientTop+db.offsetTop : 0); 6420 }else if(d.isFF == 3){ 6421 // In FF3 you have to subtract the document element margins. 6422 // Fixed in FF3.5 though. 6423 var cs = gcs(dh); 6424 ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth); 6425 ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth); 6426 } 6427 // account for document scrolling 6428 if(includeScroll){ 6429 var scroll = d._docScroll(); 6430 ret.x += scroll.x; 6431 ret.y += scroll.y; 6432 } 6433 6434 return ret; // Object 6435 }; 6436 6437 dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){ 6438 // summary: 6439 // Deprecated: Use position() for border-box x/y/w/h 6440 // or marginBox() for margin-box w/h/l/t. 6441 // Returns an object representing a node's size and position. 6442 // 6443 // description: 6444 // Returns an object that measures margin-box (w)idth/(h)eight 6445 // and absolute position x/y of the border-box. Also returned 6446 // is computed (l)eft and (t)op values in pixels from the 6447 // node's offsetParent as returned from marginBox(). 6448 // Return value will be in the form: 6449 //| { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 } 6450 // Does not act as a setter. If includeScroll is passed, the x and 6451 // y params are affected as one would expect in dojo.position(). 6452 var n = byId(node), s = gcs(n), mb = d._getMarginBox(n, s); 6453 var abs = d.position(n, includeScroll); 6454 mb.x = abs.x; 6455 mb.y = abs.y; 6456 return mb; 6457 }; 6458 6459 // ============================= 6460 // Element attribute Functions 6461 // ============================= 6462 6463 // dojo.attr() should conform to http://www.w3.org/TR/DOM-Level-2-Core/ 6464 6465 var _propNames = { 6466 // properties renamed to avoid clashes with reserved words 6467 "class": "className", 6468 "for": "htmlFor", 6469 // properties written as camelCase 6470 tabindex: "tabIndex", 6471 readonly: "readOnly", 6472 colspan: "colSpan", 6473 frameborder: "frameBorder", 6474 rowspan: "rowSpan", 6475 valuetype: "valueType" 6476 }, 6477 _attrNames = { 6478 // original attribute names 6479 classname: "class", 6480 htmlfor: "for", 6481 // for IE 6482 tabindex: "tabIndex", 6483 readonly: "readOnly" 6484 }, 6485 _forcePropNames = { 6486 innerHTML: 1, 6487 className: 1, 6488 htmlFor: d.isIE, 6489 value: 1 6490 }; 6491 6492 var _fixAttrName = function(/*String*/ name){ 6493 return _attrNames[name.toLowerCase()] || name; 6494 }; 6495 6496 var _hasAttr = function(node, name){ 6497 var attr = node.getAttributeNode && node.getAttributeNode(name); 6498 return attr && attr.specified; // Boolean 6499 }; 6500 6501 // There is a difference in the presence of certain properties and their default values 6502 // between browsers. For example, on IE "disabled" is present on all elements, 6503 // but it is value is "false"; "tabIndex" of <div> returns 0 by default on IE, yet other browsers 6504 // can return -1. 6505 6506 dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){ 6507 // summary: 6508 // Returns true if the requested attribute is specified on the 6509 // given element, and false otherwise. 6510 // node: 6511 // id or reference to the element to check 6512 // name: 6513 // the name of the attribute 6514 // returns: 6515 // true if the requested attribute is specified on the 6516 // given element, and false otherwise 6517 var lc = name.toLowerCase(); 6518 return _forcePropNames[_propNames[lc] || name] || _hasAttr(byId(node), _attrNames[lc] || name); // Boolean 6519 }; 6520 6521 var _evtHdlrMap = {}, _ctr = 0, 6522 _attrId = dojo._scopeName + "attrid", 6523 // the next dictionary lists elements with read-only innerHTML on IE 6524 _roInnerHtml = {col: 1, colgroup: 1, 6525 // frameset: 1, head: 1, html: 1, style: 1, 6526 table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1}; 6527 6528 dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){ 6529 // summary: 6530 // Gets or sets an attribute on an HTML element. 6531 // description: 6532 // Handles normalized getting and setting of attributes on DOM 6533 // Nodes. If 2 arguments are passed, and a the second argumnt is a 6534 // string, acts as a getter. 6535 // 6536 // If a third argument is passed, or if the second argument is a 6537 // map of attributes, acts as a setter. 6538 // 6539 // When passing functions as values, note that they will not be 6540 // directly assigned to slots on the node, but rather the default 6541 // behavior will be removed and the new behavior will be added 6542 // using `dojo.connect()`, meaning that event handler properties 6543 // will be normalized and that some caveats with regards to 6544 // non-standard behaviors for onsubmit apply. Namely that you 6545 // should cancel form submission using `dojo.stopEvent()` on the 6546 // passed event object instead of returning a boolean value from 6547 // the handler itself. 6548 // node: 6549 // id or reference to the element to get or set the attribute on 6550 // name: 6551 // the name of the attribute to get or set. 6552 // value: 6553 // The value to set for the attribute 6554 // returns: 6555 // when used as a getter, the value of the requested attribute 6556 // or null if that attribute does not have a specified or 6557 // default value; 6558 // 6559 // when used as a setter, the DOM node 6560 // 6561 // example: 6562 // | // get the current value of the "foo" attribute on a node 6563 // | dojo.attr(dojo.byId("nodeId"), "foo"); 6564 // | // or we can just pass the id: 6565 // | dojo.attr("nodeId", "foo"); 6566 // 6567 // example: 6568 // | // use attr() to set the tab index 6569 // | dojo.attr("nodeId", "tabIndex", 3); 6570 // | 6571 // 6572 // example: 6573 // Set multiple values at once, including event handlers: 6574 // | dojo.attr("formId", { 6575 // | "foo": "bar", 6576 // | "tabIndex": -1, 6577 // | "method": "POST", 6578 // | "onsubmit": function(e){ 6579 // | // stop submitting the form. Note that the IE behavior 6580 // | // of returning true or false will have no effect here 6581 // | // since our handler is connect()ed to the built-in 6582 // | // onsubmit behavior and so we need to use 6583 // | // dojo.stopEvent() to ensure that the submission 6584 // | // doesn't proceed. 6585 // | dojo.stopEvent(e); 6586 // | 6587 // | // submit the form with Ajax 6588 // | dojo.xhrPost({ form: "formId" }); 6589 // | } 6590 // | }); 6591 // 6592 // example: 6593 // Style is s special case: Only set with an object hash of styles 6594 // | dojo.attr("someNode",{ 6595 // | id:"bar", 6596 // | style:{ 6597 // | width:"200px", height:"100px", color:"#000" 6598 // | } 6599 // | }); 6600 // 6601 // example: 6602 // Again, only set style as an object hash of styles: 6603 // | var obj = { color:"#fff", backgroundColor:"#000" }; 6604 // | dojo.attr("someNode", "style", obj); 6605 // | 6606 // | // though shorter to use `dojo.style()` in this case: 6607 // | dojo.style("someNode", obj); 6608 6609 node = byId(node); 6610 var args = arguments.length, prop; 6611 if(args == 2 && typeof name != "string"){ // inline'd type check 6612 // the object form of setter: the 2nd argument is a dictionary 6613 for(var x in name){ 6614 d.attr(node, x, name[x]); 6615 } 6616 return node; // DomNode 6617 } 6618 var lc = name.toLowerCase(), 6619 propName = _propNames[lc] || name, 6620 forceProp = _forcePropNames[propName], 6621 attrName = _attrNames[lc] || name; 6622 if(args == 3){ 6623 // setter 6624 do{ 6625 if(propName == "style" && typeof value != "string"){ // inline'd type check 6626 // special case: setting a style 6627 d.style(node, value); 6628 break; 6629 } 6630 if(propName == "innerHTML"){ 6631 // special case: assigning HTML 6632 if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){ 6633 d.empty(node); 6634 node.appendChild(d._toDom(value, node.ownerDocument)); 6635 }else{ 6636 node[propName] = value; 6637 } 6638 break; 6639 } 6640 if(d.isFunction(value)){ 6641 // special case: assigning an event handler 6642 // clobber if we can 6643 var attrId = d.attr(node, _attrId); 6644 if(!attrId){ 6645 attrId = _ctr++; 6646 d.attr(node, _attrId, attrId); 6647 } 6648 if(!_evtHdlrMap[attrId]){ 6649 _evtHdlrMap[attrId] = {}; 6650 } 6651 var h = _evtHdlrMap[attrId][propName]; 6652 if(h){ 6653 d.disconnect(h); 6654 }else{ 6655 try{ 6656 delete node[propName]; 6657 }catch(e){} 6658 } 6659 // ensure that event objects are normalized, etc. 6660 _evtHdlrMap[attrId][propName] = d.connect(node, propName, value); 6661 break; 6662 } 6663 if(forceProp || typeof value == "boolean"){ 6664 // special case: forcing assignment to the property 6665 // special case: setting boolean to a property instead of attribute 6666 node[propName] = value; 6667 break; 6668 } 6669 // node's attribute 6670 node.setAttribute(attrName, value); 6671 }while(false); 6672 return node; // DomNode 6673 } 6674 // getter 6675 // should we access this attribute via a property or 6676 // via getAttribute()? 6677 value = node[propName]; 6678 if(forceProp && typeof value != "undefined"){ 6679 // node's property 6680 return value; // Anything 6681 } 6682 if(propName != "href" && (typeof value == "boolean" || d.isFunction(value))){ 6683 // node's property 6684 return value; // Anything 6685 } 6686 // node's attribute 6687 // we need _hasAttr() here to guard against IE returning a default value 6688 return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything 6689 }; 6690 6691 dojo.removeAttr = function(/*DomNode|String*/ node, /*String*/ name){ 6692 // summary: 6693 // Removes an attribute from an HTML element. 6694 // node: 6695 // id or reference to the element to remove the attribute from 6696 // name: 6697 // the name of the attribute to remove 6698 byId(node).removeAttribute(_fixAttrName(name)); 6699 }; 6700 6701 dojo.getNodeProp = function(/*DomNode|String*/ node, /*String*/ name){ 6702 // summary: 6703 // Returns an effective value of a property or an attribute. 6704 // node: 6705 // id or reference to the element to remove the attribute from 6706 // name: 6707 // the name of the attribute 6708 node = byId(node); 6709 var lc = name.toLowerCase(), 6710 propName = _propNames[lc] || name; 6711 if((propName in node) && propName != "href"){ 6712 // node's property 6713 return node[propName]; // Anything 6714 } 6715 // node's attribute 6716 var attrName = _attrNames[lc] || name; 6717 return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything 6718 }; 6719 6720 dojo.create = function(tag, attrs, refNode, pos){ 6721 // summary: 6722 // Create an element, allowing for optional attribute decoration 6723 // and placement. 6724 // 6725 // description: 6726 // A DOM Element creation function. A shorthand method for creating a node or 6727 // a fragment, and allowing for a convenient optional attribute setting step, 6728 // as well as an optional DOM placement reference. 6729 //| 6730 // Attributes are set by passing the optional object through `dojo.attr`. 6731 // See `dojo.attr` for noted caveats and nuances, and API if applicable. 6732 //| 6733 // Placement is done via `dojo.place`, assuming the new node to be the action 6734 // node, passing along the optional reference node and position. 6735 // 6736 // tag: String|DomNode 6737 // A string of the element to create (eg: "div", "a", "p", "li", "script", "br"), 6738 // or an existing DOM node to process. 6739 // 6740 // attrs: Object 6741 // An object-hash of attributes to set on the newly created node. 6742 // Can be null, if you don't want to set any attributes/styles. 6743 // See: `dojo.attr` for a description of available attributes. 6744 // 6745 // refNode: String?|DomNode? 6746 // Optional reference node. Used by `dojo.place` to place the newly created 6747 // node somewhere in the dom relative to refNode. Can be a DomNode reference 6748 // or String ID of a node. 6749 // 6750 // pos: String? 6751 // Optional positional reference. Defaults to "last" by way of `dojo.place`, 6752 // though can be set to "first","after","before","last", "replace" or "only" 6753 // to further control the placement of the new node relative to the refNode. 6754 // 'refNode' is required if a 'pos' is specified. 6755 // 6756 // returns: DomNode 6757 // 6758 // example: 6759 // Create a DIV: 6760 // | var n = dojo.create("div"); 6761 // 6762 // example: 6763 // Create a DIV with content: 6764 // | var n = dojo.create("div", { innerHTML:"<p>hi</p>" }); 6765 // 6766 // example: 6767 // Place a new DIV in the BODY, with no attributes set 6768 // | var n = dojo.create("div", null, dojo.body()); 6769 // 6770 // example: 6771 // Create an UL, and populate it with LI's. Place the list as the first-child of a 6772 // node with id="someId": 6773 // | var ul = dojo.create("ul", null, "someId", "first"); 6774 // | var items = ["one", "two", "three", "four"]; 6775 // | dojo.forEach(items, function(data){ 6776 // | dojo.create("li", { innerHTML: data }, ul); 6777 // | }); 6778 // 6779 // example: 6780 // Create an anchor, with an href. Place in BODY: 6781 // | dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body()); 6782 // 6783 // example: 6784 // Create a `dojo.NodeList()` from a new element (for syntatic sugar): 6785 // | dojo.query(dojo.create('div')) 6786 // | .addClass("newDiv") 6787 // | .onclick(function(e){ console.log('clicked', e.target) }) 6788 // | .place("#someNode"); // redundant, but cleaner. 6789 6790 var doc = d.doc; 6791 if(refNode){ 6792 refNode = byId(refNode); 6793 doc = refNode.ownerDocument; 6794 } 6795 if(typeof tag == "string"){ // inline'd type check 6796 tag = doc.createElement(tag); 6797 } 6798 if(attrs){ d.attr(tag, attrs); } 6799 if(refNode){ d.place(tag, refNode, pos); } 6800 return tag; // DomNode 6801 }; 6802 6803 /*===== 6804 dojo.empty = function(node){ 6805 // summary: 6806 // safely removes all children of the node. 6807 // node: DOMNode|String 6808 // a reference to a DOM node or an id. 6809 // example: 6810 // Destroy node's children byId: 6811 // | dojo.empty("someId"); 6812 // 6813 // example: 6814 // Destroy all nodes' children in a list by reference: 6815 // | dojo.query(".someNode").forEach(dojo.empty); 6816 } 6817 =====*/ 6818 6819 d.empty = 6820 d.isIE ? function(node){ 6821 node = byId(node); 6822 for(var c; c = node.lastChild;){ // intentional assignment 6823 d.destroy(c); 6824 } 6825 } : 6826 function(node){ 6827 byId(node).innerHTML = ""; 6828 }; 6829 6830 /*===== 6831 dojo._toDom = function(frag, doc){ 6832 // summary: 6833 // instantiates an HTML fragment returning the corresponding DOM. 6834 // frag: String 6835 // the HTML fragment 6836 // doc: DocumentNode? 6837 // optional document to use when creating DOM nodes, defaults to 6838 // dojo.doc if not specified. 6839 // returns: DocumentFragment 6840 // 6841 // example: 6842 // Create a table row: 6843 // | var tr = dojo._toDom("<tr><td>First!</td></tr>"); 6844 } 6845 =====*/ 6846 6847 // support stuff for dojo._toDom 6848 var tagWrap = { 6849 option: ["select"], 6850 tbody: ["table"], 6851 thead: ["table"], 6852 tfoot: ["table"], 6853 tr: ["table", "tbody"], 6854 td: ["table", "tbody", "tr"], 6855 th: ["table", "thead", "tr"], 6856 legend: ["fieldset"], 6857 caption: ["table"], 6858 colgroup: ["table"], 6859 col: ["table", "colgroup"], 6860 li: ["ul"] 6861 }, 6862 reTag = /<\s*([\w\:]+)/, 6863 masterNode = {}, masterNum = 0, 6864 masterName = "__" + d._scopeName + "ToDomId"; 6865 6866 // generate start/end tag strings to use 6867 // for the injection for each special tag wrap case. 6868 for(var param in tagWrap){ 6869 if(tagWrap.hasOwnProperty(param)){ 6870 var tw = tagWrap[param]; 6871 tw.pre = param == "option" ? '<select multiple="multiple">' : "<" + tw.join("><") + ">"; 6872 tw.post = "</" + tw.reverse().join("></") + ">"; 6873 // the last line is destructive: it reverses the array, 6874 // but we don't care at this point 6875 } 6876 } 6877 6878 d._toDom = function(frag, doc){ 6879 // summary: 6880 // converts HTML string into DOM nodes. 6881 6882 doc = doc || d.doc; 6883 var masterId = doc[masterName]; 6884 if(!masterId){ 6885 doc[masterName] = masterId = ++masterNum + ""; 6886 masterNode[masterId] = doc.createElement("div"); 6887 } 6888 6889 // make sure the frag is a string. 6890 frag += ""; 6891 6892 // find the starting tag, and get node wrapper 6893 var match = frag.match(reTag), 6894 tag = match ? match[1].toLowerCase() : "", 6895 master = masterNode[masterId], 6896 wrap, i, fc, df; 6897 if(match && tagWrap[tag]){ 6898 wrap = tagWrap[tag]; 6899 master.innerHTML = wrap.pre + frag + wrap.post; 6900 for(i = wrap.length; i; --i){ 6901 master = master.firstChild; 6902 } 6903 }else{ 6904 master.innerHTML = frag; 6905 } 6906 6907 // one node shortcut => return the node itself 6908 if(master.childNodes.length == 1){ 6909 return master.removeChild(master.firstChild); // DOMNode 6910 } 6911 6912 // return multiple nodes as a document fragment 6913 df = doc.createDocumentFragment(); 6914 while(fc = master.firstChild){ // intentional assignment 6915 df.appendChild(fc); 6916 } 6917 return df; // DOMNode 6918 }; 6919 6920 // ============================= 6921 // (CSS) Class Functions 6922 // ============================= 6923 var _className = "className"; 6924 6925 dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){ 6926 // summary: 6927 // Returns whether or not the specified classes are a portion of the 6928 // class list currently applied to the node. 6929 // 6930 // node: 6931 // String ID or DomNode reference to check the class for. 6932 // 6933 // classStr: 6934 // A string class name to look for. 6935 // 6936 // example: 6937 // Do something if a node with id="someNode" has class="aSillyClassName" present 6938 // | if(dojo.hasClass("someNode","aSillyClassName")){ ... } 6939 6940 return ((" "+ byId(node)[_className] +" ").indexOf(" " + classStr + " ") >= 0); // Boolean 6941 }; 6942 6943 var spaces = /\s+/, a1 = [""], 6944 fakeNode = {}, 6945 str2array = function(s){ 6946 if(typeof s == "string" || s instanceof String){ 6947 if(s.indexOf(" ") < 0){ 6948 a1[0] = s; 6949 return a1; 6950 }else{ 6951 return s.split(spaces); 6952 } 6953 } 6954 // assumed to be an array 6955 return s || ""; 6956 }; 6957 6958 dojo.addClass = function(/*DomNode|String*/node, /*String|Array*/classStr){ 6959 // summary: 6960 // Adds the specified classes to the end of the class list on the 6961 // passed node. Will not re-apply duplicate classes. 6962 // 6963 // node: 6964 // String ID or DomNode reference to add a class string too 6965 // 6966 // classStr: 6967 // A String class name to add, or several space-separated class names, 6968 // or an array of class names. 6969 // 6970 // example: 6971 // Add a class to some node: 6972 // | dojo.addClass("someNode", "anewClass"); 6973 // 6974 // example: 6975 // Add two classes at once: 6976 // | dojo.addClass("someNode", "firstClass secondClass"); 6977 // 6978 // example: 6979 // Add two classes at once (using array): 6980 // | dojo.addClass("someNode", ["firstClass", "secondClass"]); 6981 // 6982 // example: 6983 // Available in `dojo.NodeList` for multiple additions 6984 // | dojo.query("ul > li").addClass("firstLevel"); 6985 6986 node = byId(node); 6987 classStr = str2array(classStr); 6988 var cls = node[_className], oldLen; 6989 cls = cls ? " " + cls + " " : " "; 6990 oldLen = cls.length; 6991 for(var i = 0, len = classStr.length, c; i < len; ++i){ 6992 c = classStr[i]; 6993 if(c && cls.indexOf(" " + c + " ") < 0){ 6994 cls += c + " "; 6995 } 6996 } 6997 if(oldLen < cls.length){ 6998 node[_className] = cls.substr(1, cls.length - 2); 6999 } 7000 }; 7001 7002 dojo.removeClass = function(/*DomNode|String*/node, /*String|Array?*/classStr){ 7003 // summary: 7004 // Removes the specified classes from node. No `dojo.hasClass` 7005 // check is required. 7006 // 7007 // node: 7008 // String ID or DomNode reference to remove the class from. 7009 // 7010 // classStr: 7011 // An optional String class name to remove, or several space-separated 7012 // class names, or an array of class names. If omitted, all class names 7013 // will be deleted. 7014 // 7015 // example: 7016 // Remove a class from some node: 7017 // | dojo.removeClass("someNode", "firstClass"); 7018 // 7019 // example: 7020 // Remove two classes from some node: 7021 // | dojo.removeClass("someNode", "firstClass secondClass"); 7022 // 7023 // example: 7024 // Remove two classes from some node (using array): 7025 // | dojo.removeClass("someNode", ["firstClass", "secondClass"]); 7026 // 7027 // example: 7028 // Remove all classes from some node: 7029 // | dojo.removeClass("someNode"); 7030 // 7031 // example: 7032 // Available in `dojo.NodeList()` for multiple removal 7033 // | dojo.query(".foo").removeClass("foo"); 7034 7035 node = byId(node); 7036 var cls; 7037 if(classStr !== undefined){ 7038 classStr = str2array(classStr); 7039 cls = " " + node[_className] + " "; 7040 for(var i = 0, len = classStr.length; i < len; ++i){ 7041 cls = cls.replace(" " + classStr[i] + " ", " "); 7042 } 7043 cls = d.trim(cls); 7044 }else{ 7045 cls = ""; 7046 } 7047 if(node[_className] != cls){ node[_className] = cls; } 7048 }; 7049 7050 dojo.replaceClass = function(/*DomNode|String*/node, /*String|Array*/addClassStr, /*String|Array?*/removeClassStr){ 7051 // summary: 7052 // Replaces one or more classes on a node if not present. 7053 // Operates more quickly than calling dojo.removeClass and dojo.addClass 7054 // node: 7055 // String ID or DomNode reference to remove the class from. 7056 // addClassStr: 7057 // A String class name to add, or several space-separated class names, 7058 // or an array of class names. 7059 // removeClassStr: 7060 // A String class name to remove, or several space-separated class names, 7061 // or an array of class names. 7062 // 7063 // example: 7064 // | dojo.replaceClass("someNode", "add1 add2", "remove1 remove2"); 7065 // 7066 // example: 7067 // Replace all classes with addMe 7068 // | dojo.replaceClass("someNode", "addMe"); 7069 // 7070 // example: 7071 // Available in `dojo.NodeList()` for multiple toggles 7072 // | dojo.query(".findMe").replaceClass("addMe", "removeMe"); 7073 7074 node = byId(node); 7075 fakeNode.className = node.className; 7076 dojo.removeClass(fakeNode, removeClassStr); 7077 dojo.addClass(fakeNode, addClassStr); 7078 if(node.className !== fakeNode.className){ 7079 node.className = fakeNode.className; 7080 } 7081 }; 7082 7083 dojo.toggleClass = function(/*DomNode|String*/node, /*String|Array*/classStr, /*Boolean?*/condition){ 7084 // summary: 7085 // Adds a class to node if not present, or removes if present. 7086 // Pass a boolean condition if you want to explicitly add or remove. 7087 // condition: 7088 // If passed, true means to add the class, false means to remove. 7089 // 7090 // example: 7091 // | dojo.toggleClass("someNode", "hovered"); 7092 // 7093 // example: 7094 // Forcefully add a class 7095 // | dojo.toggleClass("someNode", "hovered", true); 7096 // 7097 // example: 7098 // Available in `dojo.NodeList()` for multiple toggles 7099 // | dojo.query(".toggleMe").toggleClass("toggleMe"); 7100 7101 if(condition === undefined){ 7102 condition = !d.hasClass(node, classStr); 7103 } 7104 d[condition ? "addClass" : "removeClass"](node, classStr); 7105 }; 7106 7107 })(); 7108 7109 } 7110 7111 if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 7112 dojo._hasResource["dojo._base.NodeList"] = true; 7113 dojo.provide("dojo._base.NodeList"); 7114 7115 7116 7117 7118 7119 7120 (function(){ 7121 7122 var d = dojo; 7123 7124 var ap = Array.prototype, aps = ap.slice, apc = ap.concat; 7125 7126 var tnl = function(/*Array*/ a, /*dojo.NodeList?*/ parent, /*Function?*/ NodeListCtor){ 7127 // summary: 7128 // decorate an array to make it look like a `dojo.NodeList`. 7129 // a: 7130 // Array of nodes to decorate. 7131 // parent: 7132 // An optional parent NodeList that generated the current 7133 // list of nodes. Used to call _stash() so the parent NodeList 7134 // can be accessed via end() later. 7135 // NodeListCtor: 7136 // An optional constructor function to use for any 7137 // new NodeList calls. This allows a certain chain of 7138 // NodeList calls to use a different object than dojo.NodeList. 7139 if(!a.sort){ 7140 // make sure it's a real array before we pass it on to be wrapped 7141 a = aps.call(a, 0); 7142 } 7143 var ctor = NodeListCtor || this._NodeListCtor || d._NodeListCtor; 7144 a.constructor = ctor; 7145 dojo._mixin(a, ctor.prototype); 7146 a._NodeListCtor = ctor; 7147 return parent ? a._stash(parent) : a; 7148 }; 7149 7150 var loopBody = function(f, a, o){ 7151 a = [0].concat(aps.call(a, 0)); 7152 o = o || d.global; 7153 return function(node){ 7154 a[0] = node; 7155 return f.apply(o, a); 7156 }; 7157 }; 7158 7159 // adapters 7160 7161 var adaptAsForEach = function(f, o){ 7162 // summary: 7163 // adapts a single node function to be used in the forEach-type 7164 // actions. The initial object is returned from the specialized 7165 // function. 7166 // f: Function 7167 // a function to adapt 7168 // o: Object? 7169 // an optional context for f 7170 return function(){ 7171 this.forEach(loopBody(f, arguments, o)); 7172 return this; // Object 7173 }; 7174 }; 7175 7176 var adaptAsMap = function(f, o){ 7177 // summary: 7178 // adapts a single node function to be used in the map-type 7179 // actions. The return is a new array of values, as via `dojo.map` 7180 // f: Function 7181 // a function to adapt 7182 // o: Object? 7183 // an optional context for f 7184 return function(){ 7185 return this.map(loopBody(f, arguments, o)); 7186 }; 7187 }; 7188 7189 var adaptAsFilter = function(f, o){ 7190 // summary: 7191 // adapts a single node function to be used in the filter-type actions 7192 // f: Function 7193 // a function to adapt 7194 // o: Object? 7195 // an optional context for f 7196 return function(){ 7197 return this.filter(loopBody(f, arguments, o)); 7198 }; 7199 }; 7200 7201 var adaptWithCondition = function(f, g, o){ 7202 // summary: 7203 // adapts a single node function to be used in the map-type 7204 // actions, behaves like forEach() or map() depending on arguments 7205 // f: Function 7206 // a function to adapt 7207 // g: Function 7208 // a condition function, if true runs as map(), otherwise runs as forEach() 7209 // o: Object? 7210 // an optional context for f and g 7211 return function(){ 7212 var a = arguments, body = loopBody(f, a, o); 7213 if(g.call(o || d.global, a)){ 7214 return this.map(body); // self 7215 } 7216 this.forEach(body); 7217 return this; // self 7218 }; 7219 }; 7220 7221 var magicGuard = function(a){ 7222 // summary: 7223 // the guard function for dojo.attr() and dojo.style() 7224 return a.length == 1 && (typeof a[0] == "string"); // inline'd type check 7225 }; 7226 7227 var orphan = function(node){ 7228 // summary: 7229 // function to orphan nodes 7230 var p = node.parentNode; 7231 if(p){ 7232 p.removeChild(node); 7233 } 7234 }; 7235 // FIXME: should we move orphan() to dojo.html? 7236 7237 dojo.NodeList = function(){ 7238 // summary: 7239 // dojo.NodeList is an of Array subclass which adds syntactic 7240 // sugar for chaining, common iteration operations, animation, and 7241 // node manipulation. NodeLists are most often returned as the 7242 // result of dojo.query() calls. 7243 // description: 7244 // dojo.NodeList instances provide many utilities that reflect 7245 // core Dojo APIs for Array iteration and manipulation, DOM 7246 // manipulation, and event handling. Instead of needing to dig up 7247 // functions in the dojo.* namespace, NodeLists generally make the 7248 // full power of Dojo available for DOM manipulation tasks in a 7249 // simple, chainable way. 7250 // example: 7251 // create a node list from a node 7252 // | new dojo.NodeList(dojo.byId("foo")); 7253 // example: 7254 // get a NodeList from a CSS query and iterate on it 7255 // | var l = dojo.query(".thinger"); 7256 // | l.forEach(function(node, index, nodeList){ 7257 // | console.log(index, node.innerHTML); 7258 // | }); 7259 // example: 7260 // use native and Dojo-provided array methods to manipulate a 7261 // NodeList without needing to use dojo.* functions explicitly: 7262 // | var l = dojo.query(".thinger"); 7263 // | // since NodeLists are real arrays, they have a length 7264 // | // property that is both readable and writable and 7265 // | // push/pop/shift/unshift methods 7266 // | console.log(l.length); 7267 // | l.push(dojo.create("span")); 7268 // | 7269 // | // dojo's normalized array methods work too: 7270 // | console.log( l.indexOf(dojo.byId("foo")) ); 7271 // | // ...including the special "function as string" shorthand 7272 // | console.log( l.every("item.nodeType == 1") ); 7273 // | 7274 // | // NodeLists can be [..] indexed, or you can use the at() 7275 // | // function to get specific items wrapped in a new NodeList: 7276 // | var node = l[3]; // the 4th element 7277 // | var newList = l.at(1, 3); // the 2nd and 4th elements 7278 // example: 7279 // the style functions you expect are all there too: 7280 // | // style() as a getter... 7281 // | var borders = dojo.query(".thinger").style("border"); 7282 // | // ...and as a setter: 7283 // | dojo.query(".thinger").style("border", "1px solid black"); 7284 // | // class manipulation 7285 // | dojo.query("li:nth-child(even)").addClass("even"); 7286 // | // even getting the coordinates of all the items 7287 // | var coords = dojo.query(".thinger").coords(); 7288 // example: 7289 // DOM manipulation functions from the dojo.* namespace area also 7290 // available: 7291 // | // remove all of the elements in the list from their 7292 // | // parents (akin to "deleting" them from the document) 7293 // | dojo.query(".thinger").orphan(); 7294 // | // place all elements in the list at the front of #foo 7295 // | dojo.query(".thinger").place("foo", "first"); 7296 // example: 7297 // Event handling couldn't be easier. `dojo.connect` is mapped in, 7298 // and shortcut handlers are provided for most DOM events: 7299 // | // like dojo.connect(), but with implicit scope 7300 // | dojo.query("li").connect("onclick", console, "log"); 7301 // | 7302 // | // many common event handlers are already available directly: 7303 // | dojo.query("li").onclick(console, "log"); 7304 // | var toggleHovered = dojo.hitch(dojo, "toggleClass", "hovered"); 7305 // | dojo.query("p") 7306 // | .onmouseenter(toggleHovered) 7307 // | .onmouseleave(toggleHovered); 7308 // example: 7309 // chainability is a key advantage of NodeLists: 7310 // | dojo.query(".thinger") 7311 // | .onclick(function(e){ /* ... */ }) 7312 // | .at(1, 3, 8) // get a subset 7313 // | .style("padding", "5px") 7314 // | .forEach(console.log); 7315 7316 return tnl(Array.apply(null, arguments)); 7317 }; 7318 7319 //Allow things that new up a NodeList to use a delegated or alternate NodeList implementation. 7320 d._NodeListCtor = d.NodeList; 7321 7322 var nl = d.NodeList, nlp = nl.prototype; 7323 7324 // expose adapters and the wrapper as private functions 7325 7326 nl._wrap = nlp._wrap = tnl; 7327 nl._adaptAsMap = adaptAsMap; 7328 nl._adaptAsForEach = adaptAsForEach; 7329 nl._adaptAsFilter = adaptAsFilter; 7330 nl._adaptWithCondition = adaptWithCondition; 7331 7332 // mass assignment 7333 7334 // add array redirectors 7335 d.forEach(["slice", "splice"], function(name){ 7336 var f = ap[name]; 7337 //Use a copy of the this array via this.slice() to allow .end() to work right in the splice case. 7338 // CANNOT apply ._stash()/end() to splice since it currently modifies 7339 // the existing this array -- it would break backward compatibility if we copy the array before 7340 // the splice so that we can use .end(). So only doing the stash option to this._wrap for slice. 7341 nlp[name] = function(){ return this._wrap(f.apply(this, arguments), name == "slice" ? this : null); }; 7342 }); 7343 // concat should be here but some browsers with native NodeList have problems with it 7344 7345 // add array.js redirectors 7346 d.forEach(["indexOf", "lastIndexOf", "every", "some"], function(name){ 7347 var f = d[name]; 7348 nlp[name] = function(){ return f.apply(d, [this].concat(aps.call(arguments, 0))); }; 7349 }); 7350 7351 // add conditional methods 7352 d.forEach(["attr", "style"], function(name){ 7353 nlp[name] = adaptWithCondition(d[name], magicGuard); 7354 }); 7355 7356 // add forEach actions 7357 d.forEach(["connect", "addClass", "removeClass", "replaceClass", "toggleClass", "empty", "removeAttr"], function(name){ 7358 nlp[name] = adaptAsForEach(d[name]); 7359 }); 7360 7361 dojo.extend(dojo.NodeList, { 7362 _normalize: function(/*String||Element||Object||NodeList*/content, /*DOMNode?*/refNode){ 7363 // summary: 7364 // normalizes data to an array of items to insert. 7365 // description: 7366 // If content is an object, it can have special properties "template" and 7367 // "parse". If "template" is defined, then the template value is run through 7368 // dojo.string.substitute (if dojo.string.substitute has been dojo.required elsewhere), 7369 // or if templateFunc is a function on the content, that function will be used to 7370 // transform the template into a final string to be used for for passing to dojo._toDom. 7371 // If content.parse is true, then it is remembered for later, for when the content 7372 // nodes are inserted into the DOM. At that point, the nodes will be parsed for widgets 7373 // (if dojo.parser has been dojo.required elsewhere). 7374 7375 //Wanted to just use a DocumentFragment, but for the array/NodeList 7376 //case that meant using cloneNode, but we may not want that. 7377 //Cloning should only happen if the node operations span 7378 //multiple refNodes. Also, need a real array, not a NodeList from the 7379 //DOM since the node movements could change those NodeLists. 7380 7381 var parse = content.parse === true ? true : false; 7382 7383 //Do we have an object that needs to be run through a template? 7384 if(typeof content.template == "string"){ 7385 var templateFunc = content.templateFunc || (dojo.string && dojo.string.substitute); 7386 content = templateFunc ? templateFunc(content.template, content) : content; 7387 } 7388 7389 var type = (typeof content); 7390 if(type == "string" || type == "number"){ 7391 content = dojo._toDom(content, (refNode && refNode.ownerDocument)); 7392 if(content.nodeType == 11){ 7393 //DocumentFragment. It cannot handle cloneNode calls, so pull out the children. 7394 content = dojo._toArray(content.childNodes); 7395 }else{ 7396 content = [content]; 7397 } 7398 }else if(!dojo.isArrayLike(content)){ 7399 content = [content]; 7400 }else if(!dojo.isArray(content)){ 7401 //To get to this point, content is array-like, but 7402 //not an array, which likely means a DOM NodeList. Convert it now. 7403 content = dojo._toArray(content); 7404 } 7405 7406 //Pass around the parse info 7407 if(parse){ 7408 content._runParse = true; 7409 } 7410 return content; //Array 7411 }, 7412 7413 _cloneNode: function(/*DOMNode*/ node){ 7414 // summary: 7415 // private utility to clone a node. Not very interesting in the vanilla 7416 // dojo.NodeList case, but delegates could do interesting things like 7417 // clone event handlers if that is derivable from the node. 7418 return node.cloneNode(true); 7419 }, 7420 7421 _place: function(/*Array*/ary, /*DOMNode*/refNode, /*String*/position, /*Boolean*/useClone){ 7422 // summary: 7423 // private utility to handle placing an array of nodes relative to another node. 7424 // description: 7425 // Allows for cloning the nodes in the array, and for 7426 // optionally parsing widgets, if ary._runParse is true. 7427 7428 //Avoid a disallowed operation if trying to do an innerHTML on a non-element node. 7429 if(refNode.nodeType != 1 && position == "only"){ 7430 return; 7431 } 7432 var rNode = refNode, tempNode; 7433 7434 //Always cycle backwards in case the array is really a 7435 //DOM NodeList and the DOM operations take it out of the live collection. 7436 var length = ary.length; 7437 for(var i = length - 1; i >= 0; i--){ 7438 var node = (useClone ? this._cloneNode(ary[i]) : ary[i]); 7439 7440 //If need widget parsing, use a temp node, instead of waiting after inserting into 7441 //real DOM because we need to start widget parsing at one node up from current node, 7442 //which could cause some already parsed widgets to be parsed again. 7443 if(ary._runParse && dojo.parser && dojo.parser.parse){ 7444 if(!tempNode){ 7445 tempNode = rNode.ownerDocument.createElement("div"); 7446 } 7447 tempNode.appendChild(node); 7448 dojo.parser.parse(tempNode); 7449 node = tempNode.firstChild; 7450 while(tempNode.firstChild){ 7451 tempNode.removeChild(tempNode.firstChild); 7452 } 7453 } 7454 7455 if(i == length - 1){ 7456 dojo.place(node, rNode, position); 7457 }else{ 7458 rNode.parentNode.insertBefore(node, rNode); 7459 } 7460 rNode = node; 7461 } 7462 }, 7463 7464 _stash: function(parent){ 7465 // summary: 7466 // private function to hold to a parent NodeList. end() to return the parent NodeList. 7467 // 7468 // example: 7469 // How to make a `dojo.NodeList` method that only returns the third node in 7470 // the dojo.NodeList but allows access to the original NodeList by using this._stash: 7471 // | dojo.extend(dojo.NodeList, { 7472 // | third: function(){ 7473 // | var newNodeList = dojo.NodeList(this[2]); 7474 // | return newNodeList._stash(this); 7475 // | } 7476 // | }); 7477 // | // then see how _stash applies a sub-list, to be .end()'ed out of 7478 // | dojo.query(".foo") 7479 // | .third() 7480 // | .addClass("thirdFoo") 7481 // | .end() 7482 // | // access to the orig .foo list 7483 // | .removeClass("foo") 7484 // | 7485 // 7486 this._parent = parent; 7487 return this; //dojo.NodeList 7488 }, 7489 7490 end: function(){ 7491 // summary: 7492 // Ends use of the current `dojo.NodeList` by returning the previous dojo.NodeList 7493 // that generated the current dojo.NodeList. 7494 // description: 7495 // Returns the `dojo.NodeList` that generated the current `dojo.NodeList`. If there 7496 // is no parent dojo.NodeList, an empty dojo.NodeList is returned. 7497 // example: 7498 // | dojo.query("a") 7499 // | .filter(".disabled") 7500 // | // operate on the anchors that only have a disabled class 7501 // | .style("color", "grey") 7502 // | .end() 7503 // | // jump back to the list of anchors 7504 // | .style(...) 7505 // 7506 if(this._parent){ 7507 return this._parent; 7508 }else{ 7509 //Just return empty list. 7510 return new this._NodeListCtor(); 7511 } 7512 }, 7513 7514 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods 7515 7516 // FIXME: handle return values for #3244 7517 // http://trac.dojotoolkit.org/ticket/3244 7518 7519 // FIXME: 7520 // need to wrap or implement: 7521 // join (perhaps w/ innerHTML/outerHTML overload for toString() of items?) 7522 // reduce 7523 // reduceRight 7524 7525 /*===== 7526 slice: function(begin, end){ 7527 // summary: 7528 // Returns a new NodeList, maintaining this one in place 7529 // description: 7530 // This method behaves exactly like the Array.slice method 7531 // with the caveat that it returns a dojo.NodeList and not a 7532 // raw Array. For more details, see Mozilla's (slice 7533 // documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice] 7534 // begin: Integer 7535 // Can be a positive or negative integer, with positive 7536 // integers noting the offset to begin at, and negative 7537 // integers denoting an offset from the end (i.e., to the left 7538 // of the end) 7539 // end: Integer? 7540 // Optional parameter to describe what position relative to 7541 // the NodeList's zero index to end the slice at. Like begin, 7542 // can be positive or negative. 7543 return this._wrap(a.slice.apply(this, arguments)); 7544 }, 7545 7546 splice: function(index, howmany, item){ 7547 // summary: 7548 // Returns a new NodeList, manipulating this NodeList based on 7549 // the arguments passed, potentially splicing in new elements 7550 // at an offset, optionally deleting elements 7551 // description: 7552 // This method behaves exactly like the Array.splice method 7553 // with the caveat that it returns a dojo.NodeList and not a 7554 // raw Array. For more details, see Mozilla's (splice 7555 // documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice] 7556 // For backwards compatibility, calling .end() on the spliced NodeList 7557 // does not return the original NodeList -- splice alters the NodeList in place. 7558 // index: Integer 7559 // begin can be a positive or negative integer, with positive 7560 // integers noting the offset to begin at, and negative 7561 // integers denoting an offset from the end (i.e., to the left 7562 // of the end) 7563 // howmany: Integer? 7564 // Optional parameter to describe what position relative to 7565 // the NodeList's zero index to end the slice at. Like begin, 7566 // can be positive or negative. 7567 // item: Object...? 7568 // Any number of optional parameters may be passed in to be 7569 // spliced into the NodeList 7570 // returns: 7571 // dojo.NodeList 7572 return this._wrap(a.splice.apply(this, arguments)); 7573 }, 7574 7575 indexOf: function(value, fromIndex){ 7576 // summary: 7577 // see dojo.indexOf(). The primary difference is that the acted-on 7578 // array is implicitly this NodeList 7579 // value: Object: 7580 // The value to search for. 7581 // fromIndex: Integer?: 7582 // The location to start searching from. Optional. Defaults to 0. 7583 // description: 7584 // For more details on the behavior of indexOf, see Mozilla's 7585 // (indexOf 7586 // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf] 7587 // returns: 7588 // Positive Integer or 0 for a match, -1 of not found. 7589 return d.indexOf(this, value, fromIndex); // Integer 7590 }, 7591 7592 lastIndexOf: function(value, fromIndex){ 7593 // summary: 7594 // see dojo.lastIndexOf(). The primary difference is that the 7595 // acted-on array is implicitly this NodeList 7596 // description: 7597 // For more details on the behavior of lastIndexOf, see 7598 // Mozilla's (lastIndexOf 7599 // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf] 7600 // value: Object 7601 // The value to search for. 7602 // fromIndex: Integer? 7603 // The location to start searching from. Optional. Defaults to 0. 7604 // returns: 7605 // Positive Integer or 0 for a match, -1 of not found. 7606 return d.lastIndexOf(this, value, fromIndex); // Integer 7607 }, 7608 7609 every: function(callback, thisObject){ 7610 // summary: 7611 // see `dojo.every()` and the (Array.every 7612 // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every]. 7613 // Takes the same structure of arguments and returns as 7614 // dojo.every() with the caveat that the passed array is 7615 // implicitly this NodeList 7616 // callback: Function: the callback 7617 // thisObject: Object?: the context 7618 return d.every(this, callback, thisObject); // Boolean 7619 }, 7620 7621 some: function(callback, thisObject){ 7622 // summary: 7623 // Takes the same structure of arguments and returns as 7624 // `dojo.some()` with the caveat that the passed array is 7625 // implicitly this NodeList. See `dojo.some()` and Mozilla's 7626 // (Array.some 7627 // documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some]. 7628 // callback: Function: the callback 7629 // thisObject: Object?: the context 7630 return d.some(this, callback, thisObject); // Boolean 7631 }, 7632 =====*/ 7633 7634 concat: function(item){ 7635 // summary: 7636 // Returns a new NodeList comprised of items in this NodeList 7637 // as well as items passed in as parameters 7638 // description: 7639 // This method behaves exactly like the Array.concat method 7640 // with the caveat that it returns a `dojo.NodeList` and not a 7641 // raw Array. For more details, see the (Array.concat 7642 // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat] 7643 // item: Object? 7644 // Any number of optional parameters may be passed in to be 7645 // spliced into the NodeList 7646 // returns: 7647 // dojo.NodeList 7648 7649 //return this._wrap(apc.apply(this, arguments)); 7650 // the line above won't work for the native NodeList :-( 7651 7652 // implementation notes: 7653 // 1) Native NodeList is not an array, and cannot be used directly 7654 // in concat() --- the latter doesn't recognize it as an array, and 7655 // does not inline it, but append as a single entity. 7656 // 2) On some browsers (e.g., Safari) the "constructor" property is 7657 // read-only and cannot be changed. So we have to test for both 7658 // native NodeList and dojo.NodeList in this property to recognize 7659 // the node list. 7660 7661 var t = d.isArray(this) ? this : aps.call(this, 0), 7662 m = d.map(arguments, function(a){ 7663 return a && !d.isArray(a) && 7664 (typeof NodeList != "undefined" && a.constructor === NodeList || a.constructor === this._NodeListCtor) ? 7665 aps.call(a, 0) : a; 7666 }); 7667 return this._wrap(apc.apply(t, m), this); // dojo.NodeList 7668 }, 7669 7670 map: function(/*Function*/ func, /*Function?*/ obj){ 7671 // summary: 7672 // see dojo.map(). The primary difference is that the acted-on 7673 // array is implicitly this NodeList and the return is a 7674 // dojo.NodeList (a subclass of Array) 7675 ///return d.map(this, func, obj, d.NodeList); // dojo.NodeList 7676 return this._wrap(d.map(this, func, obj), this); // dojo.NodeList 7677 }, 7678 7679 forEach: function(callback, thisObj){ 7680 // summary: 7681 // see `dojo.forEach()`. The primary difference is that the acted-on 7682 // array is implicitly this NodeList. If you want the option to break out 7683 // of the forEach loop, use every() or some() instead. 7684 d.forEach(this, callback, thisObj); 7685 // non-standard return to allow easier chaining 7686 return this; // dojo.NodeList 7687 }, 7688 7689 /*===== 7690 coords: function(){ 7691 // summary: 7692 // Returns the box objects of all elements in a node list as 7693 // an Array (*not* a NodeList). Acts like `dojo.coords`, though assumes 7694 // the node passed is each node in this list. 7695 7696 return d.map(this, d.coords); // Array 7697 }, 7698 7699 position: function(){ 7700 // summary: 7701 // Returns border-box objects (x/y/w/h) of all elements in a node list 7702 // as an Array (*not* a NodeList). Acts like `dojo.position`, though 7703 // assumes the node passed is each node in this list. 7704 7705 return d.map(this, d.position); // Array 7706 }, 7707 7708 attr: function(property, value){ 7709 // summary: 7710 // gets or sets the DOM attribute for every element in the 7711 // NodeList. See also `dojo.attr` 7712 // property: String 7713 // the attribute to get/set 7714 // value: String? 7715 // optional. The value to set the property to 7716 // returns: 7717 // if no value is passed, the result is an array of attribute values 7718 // If a value is passed, the return is this NodeList 7719 // example: 7720 // Make all nodes with a particular class focusable: 7721 // | dojo.query(".focusable").attr("tabIndex", -1); 7722 // example: 7723 // Disable a group of buttons: 7724 // | dojo.query("button.group").attr("disabled", true); 7725 // example: 7726 // innerHTML can be assigned or retrieved as well: 7727 // | // get the innerHTML (as an array) for each list item 7728 // | var ih = dojo.query("li.replaceable").attr("innerHTML"); 7729 return; // dojo.NodeList 7730 return; // Array 7731 }, 7732 7733 style: function(property, value){ 7734 // summary: 7735 // gets or sets the CSS property for every element in the NodeList 7736 // property: String 7737 // the CSS property to get/set, in JavaScript notation 7738 // ("lineHieght" instead of "line-height") 7739 // value: String? 7740 // optional. The value to set the property to 7741 // returns: 7742 // if no value is passed, the result is an array of strings. 7743 // If a value is passed, the return is this NodeList 7744 return; // dojo.NodeList 7745 return; // Array 7746 }, 7747 7748 addClass: function(className){ 7749 // summary: 7750 // adds the specified class to every node in the list 7751 // className: String|Array 7752 // A String class name to add, or several space-separated class names, 7753 // or an array of class names. 7754 return; // dojo.NodeList 7755 }, 7756 7757 removeClass: function(className){ 7758 // summary: 7759 // removes the specified class from every node in the list 7760 // className: String|Array? 7761 // An optional String class name to remove, or several space-separated 7762 // class names, or an array of class names. If omitted, all class names 7763 // will be deleted. 7764 // returns: 7765 // dojo.NodeList, this list 7766 return; // dojo.NodeList 7767 }, 7768 7769 toggleClass: function(className, condition){ 7770 // summary: 7771 // Adds a class to node if not present, or removes if present. 7772 // Pass a boolean condition if you want to explicitly add or remove. 7773 // condition: Boolean? 7774 // If passed, true means to add the class, false means to remove. 7775 // className: String 7776 // the CSS class to add 7777 return; // dojo.NodeList 7778 }, 7779 7780 connect: function(methodName, objOrFunc, funcName){ 7781 // summary: 7782 // attach event handlers to every item of the NodeList. Uses dojo.connect() 7783 // so event properties are normalized 7784 // methodName: String 7785 // the name of the method to attach to. For DOM events, this should be 7786 // the lower-case name of the event 7787 // objOrFunc: Object|Function|String 7788 // if 2 arguments are passed (methodName, objOrFunc), objOrFunc should 7789 // reference a function or be the name of the function in the global 7790 // namespace to attach. If 3 arguments are provided 7791 // (methodName, objOrFunc, funcName), objOrFunc must be the scope to 7792 // locate the bound function in 7793 // funcName: String? 7794 // optional. A string naming the function in objOrFunc to bind to the 7795 // event. May also be a function reference. 7796 // example: 7797 // add an onclick handler to every button on the page 7798 // | dojo.query("div:nth-child(odd)").connect("onclick", function(e){ 7799 // | console.log("clicked!"); 7800 // | }); 7801 // example: 7802 // attach foo.bar() to every odd div's onmouseover 7803 // | dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar"); 7804 }, 7805 7806 empty: function(){ 7807 // summary: 7808 // clears all content from each node in the list. Effectively 7809 // equivalent to removing all child nodes from every item in 7810 // the list. 7811 return this.forEach("item.innerHTML='';"); // dojo.NodeList 7812 // FIXME: should we be checking for and/or disposing of widgets below these nodes? 7813 }, 7814 =====*/ 7815 7816 // useful html methods 7817 coords: adaptAsMap(d.coords), 7818 position: adaptAsMap(d.position), 7819 7820 // FIXME: connectPublisher()? connectRunOnce()? 7821 7822 /* 7823 destroy: function(){ 7824 // summary: 7825 // destroys every item in the list. 7826 this.forEach(d.destroy); 7827 // FIXME: should we be checking for and/or disposing of widgets below these nodes? 7828 }, 7829 */ 7830 7831 place: function(/*String||Node*/ queryOrNode, /*String*/ position){ 7832 // summary: 7833 // places elements of this node list relative to the first element matched 7834 // by queryOrNode. Returns the original NodeList. See: `dojo.place` 7835 // queryOrNode: 7836 // may be a string representing any valid CSS3 selector or a DOM node. 7837 // In the selector case, only the first matching element will be used 7838 // for relative positioning. 7839 // position: 7840 // can be one of: 7841 // | "last" (default) 7842 // | "first" 7843 // | "before" 7844 // | "after" 7845 // | "only" 7846 // | "replace" 7847 // or an offset in the childNodes property 7848 var item = d.query(queryOrNode)[0]; 7849 return this.forEach(function(node){ d.place(node, item, position); }); // dojo.NodeList 7850 }, 7851 7852 orphan: function(/*String?*/ filter){ 7853 // summary: 7854 // removes elements in this list that match the filter 7855 // from their parents and returns them as a new NodeList. 7856 // filter: 7857 // CSS selector like ".foo" or "div > span" 7858 // returns: 7859 // `dojo.NodeList` containing the orphaned elements 7860 return (filter ? d._filterQueryResult(this, filter) : this).forEach(orphan); // dojo.NodeList 7861 }, 7862 7863 adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){ 7864 // summary: 7865 // places any/all elements in queryOrListOrNode at a 7866 // position relative to the first element in this list. 7867 // Returns a dojo.NodeList of the adopted elements. 7868 // queryOrListOrNode: 7869 // a DOM node or a query string or a query result. 7870 // Represents the nodes to be adopted relative to the 7871 // first element of this NodeList. 7872 // position: 7873 // can be one of: 7874 // | "last" (default) 7875 // | "first" 7876 // | "before" 7877 // | "after" 7878 // | "only" 7879 // | "replace" 7880 // or an offset in the childNodes property 7881 return d.query(queryOrListOrNode).place(this[0], position)._stash(this); // dojo.NodeList 7882 }, 7883 7884 // FIXME: do we need this? 7885 query: function(/*String*/ queryStr){ 7886 // summary: 7887 // Returns a new list whose members match the passed query, 7888 // assuming elements of the current NodeList as the root for 7889 // each search. 7890 // example: 7891 // assume a DOM created by this markup: 7892 // | <div id="foo"> 7893 // | <p> 7894 // | bacon is tasty, <span>dontcha think?</span> 7895 // | </p> 7896 // | </div> 7897 // | <div id="bar"> 7898 // | <p>great comedians may not be funny <span>in person</span></p> 7899 // | </div> 7900 // If we are presented with the following definition for a NodeList: 7901 // | var l = new dojo.NodeList(dojo.byId("foo"), dojo.byId("bar")); 7902 // it's possible to find all span elements under paragraphs 7903 // contained by these elements with this sub-query: 7904 // | var spans = l.query("p span"); 7905 7906 // FIXME: probably slow 7907 if(!queryStr){ return this; } 7908 var ret = this.map(function(node){ 7909 // FIXME: why would we ever get undefined here? 7910 return d.query(queryStr, node).filter(function(subNode){ return subNode !== undefined; }); 7911 }); 7912 return this._wrap(apc.apply([], ret), this); // dojo.NodeList 7913 }, 7914 7915 filter: function(/*String|Function*/ filter){ 7916 // summary: 7917 // "masks" the built-in javascript filter() method (supported 7918 // in Dojo via `dojo.filter`) to support passing a simple 7919 // string filter in addition to supporting filtering function 7920 // objects. 7921 // filter: 7922 // If a string, a CSS rule like ".thinger" or "div > span". 7923 // example: 7924 // "regular" JS filter syntax as exposed in dojo.filter: 7925 // | dojo.query("*").filter(function(item){ 7926 // | // highlight every paragraph 7927 // | return (item.nodeName == "p"); 7928 // | }).style("backgroundColor", "yellow"); 7929 // example: 7930 // the same filtering using a CSS selector 7931 // | dojo.query("*").filter("p").styles("backgroundColor", "yellow"); 7932 7933 var a = arguments, items = this, start = 0; 7934 if(typeof filter == "string"){ // inline'd type check 7935 items = d._filterQueryResult(this, a[0]); 7936 if(a.length == 1){ 7937 // if we only got a string query, pass back the filtered results 7938 return items._stash(this); // dojo.NodeList 7939 } 7940 // if we got a callback, run it over the filtered items 7941 start = 1; 7942 } 7943 return this._wrap(d.filter(items, a[start], a[start + 1]), this); // dojo.NodeList 7944 }, 7945 7946 /* 7947 // FIXME: should this be "copyTo" and include parenting info? 7948 clone: function(){ 7949 // summary: 7950 // creates node clones of each element of this list 7951 // and returns a new list containing the clones 7952 }, 7953 */ 7954 7955 addContent: function(/*String||DomNode||Object||dojo.NodeList*/ content, /*String||Integer?*/ position){ 7956 // summary: 7957 // add a node, NodeList or some HTML as a string to every item in the 7958 // list. Returns the original list. 7959 // description: 7960 // a copy of the HTML content is added to each item in the 7961 // list, with an optional position argument. If no position 7962 // argument is provided, the content is appended to the end of 7963 // each item. 7964 // content: 7965 // DOM node, HTML in string format, a NodeList or an Object. If a DOM node or 7966 // NodeList, the content will be cloned if the current NodeList has more than one 7967 // element. Only the DOM nodes are cloned, no event handlers. If it is an Object, 7968 // it should be an object with at "template" String property that has the HTML string 7969 // to insert. If dojo.string has already been dojo.required, then dojo.string.substitute 7970 // will be used on the "template" to generate the final HTML string. Other allowed 7971 // properties on the object are: "parse" if the HTML 7972 // string should be parsed for widgets (dojo.require("dojo.parser") to get that 7973 // option to work), and "templateFunc" if a template function besides dojo.string.substitute 7974 // should be used to transform the "template". 7975 // position: 7976 // can be one of: 7977 // | "last"||"end" (default) 7978 // | "first||"start" 7979 // | "before" 7980 // | "after" 7981 // | "replace" (replaces nodes in this NodeList with new content) 7982 // | "only" (removes other children of the nodes so new content is the only child) 7983 // or an offset in the childNodes property 7984 // example: 7985 // appends content to the end if the position is omitted 7986 // | dojo.query("h3 > p").addContent("hey there!"); 7987 // example: 7988 // add something to the front of each element that has a 7989 // "thinger" property: 7990 // | dojo.query("[thinger]").addContent("...", "first"); 7991 // example: 7992 // adds a header before each element of the list 7993 // | dojo.query(".note").addContent("<h4>NOTE:</h4>", "before"); 7994 // example: 7995 // add a clone of a DOM node to the end of every element in 7996 // the list, removing it from its existing parent. 7997 // | dojo.query(".note").addContent(dojo.byId("foo")); 7998 // example: 7999 // Append nodes from a templatized string. 8000 // dojo.require("dojo.string"); 8001 // dojo.query(".note").addContent({ 8002 // template: '<b>${id}: </b><span>${name}</span>', 8003 // id: "user332", 8004 // name: "Mr. Anderson" 8005 // }); 8006 // example: 8007 // Append nodes from a templatized string that also has widgets parsed. 8008 // dojo.require("dojo.string"); 8009 // dojo.require("dojo.parser"); 8010 // var notes = dojo.query(".note").addContent({ 8011 // template: '<button dojoType="dijit.form.Button">${text}</button>', 8012 // parse: true, 8013 // text: "Send" 8014 // }); 8015 content = this._normalize(content, this[0]); 8016 for(var i = 0, node; (node = this[i]); i++){ 8017 this._place(content, node, position, i > 0); 8018 } 8019 return this; //dojo.NodeList 8020 }, 8021 8022 instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){ 8023 // summary: 8024 // Create a new instance of a specified class, using the 8025 // specified properties and each node in the nodeList as a 8026 // srcNodeRef. 8027 // example: 8028 // Grabs all buttons in the page and converts them to diji.form.Buttons. 8029 // | var buttons = dojo.query("button").instantiate("dijit.form.Button", {showLabel: true}); 8030 var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass); 8031 properties = properties || {}; 8032 return this.forEach(function(node){ 8033 new c(properties, node); 8034 }); // dojo.NodeList 8035 }, 8036 8037 at: function(/*===== index =====*/){ 8038 // summary: 8039 // Returns a new NodeList comprised of items in this NodeList 8040 // at the given index or indices. 8041 // 8042 // index: Integer... 8043 // One or more 0-based indices of items in the current 8044 // NodeList. A negative index will start at the end of the 8045 // list and go backwards. 8046 // 8047 // example: 8048 // Shorten the list to the first, second, and third elements 8049 // | dojo.query("a").at(0, 1, 2).forEach(fn); 8050 // 8051 // example: 8052 // Retrieve the first and last elements of a unordered list: 8053 // | dojo.query("ul > li").at(0, -1).forEach(cb); 8054 // 8055 // example: 8056 // Do something for the first element only, but end() out back to 8057 // the original list and continue chaining: 8058 // | dojo.query("a").at(0).onclick(fn).end().forEach(function(n){ 8059 // | console.log(n); // all anchors on the page. 8060 // | }) 8061 // 8062 // returns: 8063 // dojo.NodeList 8064 var t = new this._NodeListCtor(); 8065 d.forEach(arguments, function(i){ 8066 if(i < 0){ i = this.length + i } 8067 if(this[i]){ t.push(this[i]); } 8068 }, this); 8069 return t._stash(this); // dojo.NodeList 8070 } 8071 8072 }); 8073 8074 nl.events = [ 8075 // summary: 8076 // list of all DOM events used in NodeList 8077 "blur", "focus", "change", "click", "error", "keydown", "keypress", 8078 "keyup", "load", "mousedown", "mouseenter", "mouseleave", "mousemove", 8079 "mouseout", "mouseover", "mouseup", "submit" 8080 ]; 8081 8082 // FIXME: pseudo-doc the above automatically generated on-event functions 8083 8084 // syntactic sugar for DOM events 8085 d.forEach(nl.events, function(evt){ 8086 var _oe = "on" + evt; 8087 nlp[_oe] = function(a, b){ 8088 return this.connect(_oe, a, b); 8089 }; 8090 // FIXME: should these events trigger publishes? 8091 /* 8092 return (a ? this.connect(_oe, a, b) : 8093 this.forEach(function(n){ 8094 // FIXME: 8095 // listeners get buried by 8096 // addEventListener and can't be dug back 8097 // out to be triggered externally. 8098 // see: 8099 // http://developer.mozilla.org/en/docs/DOM:element 8100 8101 console.log(n, evt, _oe); 8102 8103 // FIXME: need synthetic event support! 8104 var _e = { target: n, faux: true, type: evt }; 8105 // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt }); 8106 try{ n[evt](_e); }catch(e){ console.log(e); } 8107 try{ n[_oe](_e); }catch(e){ console.log(e); } 8108 }) 8109 ); 8110 */ 8111 } 8112 ); 8113 8114 })(); 8115 8116 } 8117 8118 if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 8119 dojo._hasResource["dojo._base.query"] = true; 8120 (function(){ 8121 8122 /* 8123 dojo.query() architectural overview: 8124 8125 dojo.query is a relatively full-featured CSS3 query library. It is 8126 designed to take any valid CSS3 selector and return the nodes matching 8127 the selector. To do this quickly, it processes queries in several 8128 steps, applying caching where profitable. 8129 8130 The steps (roughly in reverse order of the way they appear in the code): 8131 1.) check to see if we already have a "query dispatcher" 8132 - if so, use that with the given parameterization. Skip to step 4. 8133 2.) attempt to determine which branch to dispatch the query to: 8134 - JS (optimized DOM iteration) 8135 - native (FF3.1+, Safari 3.1+, IE 8+) 8136 3.) tokenize and convert to executable "query dispatcher" 8137 - this is where the lion's share of the complexity in the 8138 system lies. In the DOM version, the query dispatcher is 8139 assembled as a chain of "yes/no" test functions pertaining to 8140 a section of a simple query statement (".blah:nth-child(odd)" 8141 but not "div div", which is 2 simple statements). Individual 8142 statement dispatchers are cached (to prevent re-definition) 8143 as are entire dispatch chains (to make re-execution of the 8144 same query fast) 8145 4.) the resulting query dispatcher is called in the passed scope 8146 (by default the top-level document) 8147 - for DOM queries, this results in a recursive, top-down 8148 evaluation of nodes based on each simple query section 8149 - for native implementations, this may mean working around spec 8150 bugs. So be it. 8151 5.) matched nodes are pruned to ensure they are unique (if necessary) 8152 */ 8153 8154 var defineQuery= function(d){ 8155 // define everything in a closure for compressability reasons. "d" is an 8156 // alias to "dojo" (or the toolkit alias object, e.g., "acme"). 8157 8158 //////////////////////////////////////////////////////////////////////// 8159 // Toolkit aliases 8160 //////////////////////////////////////////////////////////////////////// 8161 8162 // if you are extracting dojo.query for use in your own system, you will 8163 // need to provide these methods and properties. No other porting should be 8164 // necessary, save for configuring the system to use a class other than 8165 // dojo.NodeList as the return instance instantiator 8166 var trim = d.trim; 8167 var each = d.forEach; 8168 // d.isIE; // float 8169 // d.isSafari; // float 8170 // d.isOpera; // float 8171 // d.isWebKit; // float 8172 // d.doc ; // document element 8173 var qlc = (d._NodeListCtor = d.NodeList); 8174 8175 var getDoc = function(){ return d.doc; }; 8176 // NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo 8177 var cssCaseBug = ((d.isWebKit||d.isMozilla) && ((getDoc().compatMode) == "BackCompat")); 8178 8179 //////////////////////////////////////////////////////////////////////// 8180 // Global utilities 8181 //////////////////////////////////////////////////////////////////////// 8182 8183 8184 // on browsers that support the "children" collection we can avoid a lot of 8185 // iteration on chaff (non-element) nodes. 8186 // why. 8187 var childNodesName = !!getDoc().firstChild["children"] ? "children" : "childNodes"; 8188 8189 var specials = ">~+"; 8190 8191 // global thunk to determine whether we should treat the current query as 8192 // case sensitive or not. This switch is flipped by the query evaluator 8193 // based on the document passed as the context to search. 8194 var caseSensitive = false; 8195 8196 // how high? 8197 var yesman = function(){ return true; }; 8198 8199 //////////////////////////////////////////////////////////////////////// 8200 // Tokenizer 8201 //////////////////////////////////////////////////////////////////////// 8202 8203 var getQueryParts = function(query){ 8204 // summary: 8205 // state machine for query tokenization 8206 // description: 8207 // instead of using a brittle and slow regex-based CSS parser, 8208 // dojo.query implements an AST-style query representation. This 8209 // representation is only generated once per query. For example, 8210 // the same query run multiple times or under different root nodes 8211 // does not re-parse the selector expression but instead uses the 8212 // cached data structure. The state machine implemented here 8213 // terminates on the last " " (space) character and returns an 8214 // ordered array of query component structures (or "parts"). Each 8215 // part represents an operator or a simple CSS filtering 8216 // expression. The structure for parts is documented in the code 8217 // below. 8218 8219 8220 // NOTE: 8221 // this code is designed to run fast and compress well. Sacrifices 8222 // to readability and maintainability have been made. Your best 8223 // bet when hacking the tokenizer is to put The Donnas on *really* 8224 // loud (may we recommend their "Spend The Night" release?) and 8225 // just assume you're gonna make mistakes. Keep the unit tests 8226 // open and run them frequently. Knowing is half the battle ;-) 8227 if(specials.indexOf(query.slice(-1)) >= 0){ 8228 // if we end with a ">", "+", or "~", that means we're implicitly 8229 // searching all children, so make it explicit 8230 query += " * " 8231 }else{ 8232 // if you have not provided a terminator, one will be provided for 8233 // you... 8234 query += " "; 8235 } 8236 8237 var ts = function(/*Integer*/ s, /*Integer*/ e){ 8238 // trim and slice. 8239 8240 // take an index to start a string slice from and an end position 8241 // and return a trimmed copy of that sub-string 8242 return trim(query.slice(s, e)); 8243 } 8244 8245 // the overall data graph of the full query, as represented by queryPart objects 8246 var queryParts = []; 8247 8248 8249 // state keeping vars 8250 var inBrackets = -1, inParens = -1, inMatchFor = -1, 8251 inPseudo = -1, inClass = -1, inId = -1, inTag = -1, 8252 lc = "", cc = "", pStart; 8253 8254 // iteration vars 8255 var x = 0, // index in the query 8256 ql = query.length, 8257 currentPart = null, // data structure representing the entire clause 8258 _cp = null; // the current pseudo or attr matcher 8259 8260 // several temporary variables are assigned to this structure during a 8261 // potential sub-expression match: 8262 // attr: 8263 // a string representing the current full attribute match in a 8264 // bracket expression 8265 // type: 8266 // if there's an operator in a bracket expression, this is 8267 // used to keep track of it 8268 // value: 8269 // the internals of parenthetical expression for a pseudo. for 8270 // :nth-child(2n+1), value might be "2n+1" 8271 8272 var endTag = function(){ 8273 // called when the tokenizer hits the end of a particular tag name. 8274 // Re-sets state variables for tag matching and sets up the matcher 8275 // to handle the next type of token (tag or operator). 8276 if(inTag >= 0){ 8277 var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase(); 8278 currentPart[ (specials.indexOf(tv) < 0) ? "tag" : "oper" ] = tv; 8279 inTag = -1; 8280 } 8281 } 8282 8283 var endId = function(){ 8284 // called when the tokenizer might be at the end of an ID portion of a match 8285 if(inId >= 0){ 8286 currentPart.id = ts(inId, x).replace(/\\/g, ""); 8287 inId = -1; 8288 } 8289 } 8290 8291 var endClass = function(){ 8292 // called when the tokenizer might be at the end of a class name 8293 // match. CSS allows for multiple classes, so we augment the 8294 // current item with another class in its list 8295 if(inClass >= 0){ 8296 currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, "")); 8297 inClass = -1; 8298 } 8299 } 8300 8301 var endAll = function(){ 8302 // at the end of a simple fragment, so wall off the matches 8303 endId(); endTag(); endClass(); 8304 } 8305 8306 var endPart = function(){ 8307 endAll(); 8308 if(inPseudo >= 0){ 8309 currentPart.pseudos.push({ name: ts(inPseudo+1, x) }); 8310 } 8311 // hint to the selector engine to tell it whether or not it 8312 // needs to do any iteration. Many simple selectors don't, and 8313 // we can avoid significant construction-time work by advising 8314 // the system to skip them 8315 currentPart.loops = ( 8316 currentPart.pseudos.length || 8317 currentPart.attrs.length || 8318 currentPart.classes.length ); 8319 8320 currentPart.oquery = currentPart.query = ts(pStart, x); // save the full expression as a string 8321 8322 8323 // otag/tag are hints to suggest to the system whether or not 8324 // it's an operator or a tag. We save a copy of otag since the 8325 // tag name is cast to upper-case in regular HTML matches. The 8326 // system has a global switch to figure out if the current 8327 // expression needs to be case sensitive or not and it will use 8328 // otag or tag accordingly 8329 currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*"); 8330 8331 if(currentPart.tag){ 8332 // if we're in a case-insensitive HTML doc, we likely want 8333 // the toUpperCase when matching on element.tagName. If we 8334 // do it here, we can skip the string op per node 8335 // comparison 8336 currentPart.tag = currentPart.tag.toUpperCase(); 8337 } 8338 8339 // add the part to the list 8340 if(queryParts.length && (queryParts[queryParts.length-1].oper)){ 8341 // operators are always infix, so we remove them from the 8342 // list and attach them to the next match. The evaluator is 8343 // responsible for sorting out how to handle them. 8344 currentPart.infixOper = queryParts.pop(); 8345 currentPart.query = currentPart.infixOper.query + " " + currentPart.query; 8346 /* 8347 console.debug( "swapping out the infix", 8348 currentPart.infixOper, 8349 "and attaching it to", 8350 currentPart); 8351 */ 8352 } 8353 queryParts.push(currentPart); 8354 8355 currentPart = null; 8356 } 8357 8358 // iterate over the query, character by character, building up a 8359 // list of query part objects 8360 for(; lc=cc, cc=query.charAt(x), x < ql; x++){ 8361 // cc: the current character in the match 8362 // lc: the last character (if any) 8363 8364 // someone is trying to escape something, so don't try to match any 8365 // fragments. We assume we're inside a literal. 8366 if(lc == "\\"){ continue; } 8367 if(!currentPart){ // a part was just ended or none has yet been created 8368 // NOTE: I hate all this alloc, but it's shorter than writing tons of if's 8369 pStart = x; 8370 // rules describe full CSS sub-expressions, like: 8371 // #someId 8372 // .className:first-child 8373 // but not: 8374 // thinger > div.howdy[type=thinger] 8375 // the indidual components of the previous query would be 8376 // split into 3 parts that would be represented a structure 8377 // like: 8378 // [ 8379 // { 8380 // query: "thinger", 8381 // tag: "thinger", 8382 // }, 8383 // { 8384 // query: "div.howdy[type=thinger]", 8385 // classes: ["howdy"], 8386 // infixOper: { 8387 // query: ">", 8388 // oper: ">", 8389 // } 8390 // }, 8391 // ] 8392 currentPart = { 8393 query: null, // the full text of the part's rule 8394 pseudos: [], // CSS supports multiple pseud-class matches in a single rule 8395 attrs: [], // CSS supports multi-attribute match, so we need an array 8396 classes: [], // class matches may be additive, e.g.: .thinger.blah.howdy 8397 tag: null, // only one tag... 8398 oper: null, // ...or operator per component. Note that these wind up being exclusive. 8399 id: null, // the id component of a rule 8400 getTag: function(){ 8401 return (caseSensitive) ? this.otag : this.tag; 8402 } 8403 }; 8404 8405 // if we don't have a part, we assume we're going to start at 8406 // the beginning of a match, which should be a tag name. This 8407 // might fault a little later on, but we detect that and this 8408 // iteration will still be fine. 8409 inTag = x; 8410 } 8411 8412 if(inBrackets >= 0){ 8413 // look for a the close first 8414 if(cc == "]"){ // if we're in a [...] clause and we end, do assignment 8415 if(!_cp.attr){ 8416 // no attribute match was previously begun, so we 8417 // assume this is an attribute existence match in the 8418 // form of [someAttributeName] 8419 _cp.attr = ts(inBrackets+1, x); 8420 }else{ 8421 // we had an attribute already, so we know that we're 8422 // matching some sort of value, as in [attrName=howdy] 8423 _cp.matchFor = ts((inMatchFor||inBrackets+1), x); 8424 } 8425 var cmf = _cp.matchFor; 8426 if(cmf){ 8427 // try to strip quotes from the matchFor value. We want 8428 // [attrName=howdy] to match the same 8429 // as [attrName = 'howdy' ] 8430 if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){ 8431 _cp.matchFor = cmf.slice(1, -1); 8432 } 8433 } 8434 // end the attribute by adding it to the list of attributes. 8435 currentPart.attrs.push(_cp); 8436 _cp = null; // necessary? 8437 inBrackets = inMatchFor = -1; 8438 }else if(cc == "="){ 8439 // if the last char was an operator prefix, make sure we 8440 // record it along with the "=" operator. 8441 var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : ""; 8442 _cp.type = addToCc+cc; 8443 _cp.attr = ts(inBrackets+1, x-addToCc.length); 8444 inMatchFor = x+1; 8445 } 8446 // now look for other clause parts 8447 }else if(inParens >= 0){ 8448 // if we're in a parenthetical expression, we need to figure 8449 // out if it's attached to a pseudo-selector rule like 8450 // :nth-child(1) 8451 if(cc == ")"){ 8452 if(inPseudo >= 0){ 8453 _cp.value = ts(inParens+1, x); 8454 } 8455 inPseudo = inParens = -1; 8456 } 8457 }else if(cc == "#"){ 8458 // start of an ID match 8459 endAll(); 8460 inId = x+1; 8461 }else if(cc == "."){ 8462 // start of a class match 8463 endAll(); 8464 inClass = x; 8465 }else if(cc == ":"){ 8466 // start of a pseudo-selector match 8467 endAll(); 8468 inPseudo = x; 8469 }else if(cc == "["){ 8470 // start of an attribute match. 8471 endAll(); 8472 inBrackets = x; 8473 // provide a new structure for the attribute match to fill-in 8474 _cp = { 8475 /*===== 8476 attr: null, type: null, matchFor: null 8477 =====*/ 8478 }; 8479 }else if(cc == "("){ 8480 // we really only care if we've entered a parenthetical 8481 // expression if we're already inside a pseudo-selector match 8482 if(inPseudo >= 0){ 8483 // provide a new structure for the pseudo match to fill-in 8484 _cp = { 8485 name: ts(inPseudo+1, x), 8486 value: null 8487 } 8488 currentPart.pseudos.push(_cp); 8489 } 8490 inParens = x; 8491 }else if( 8492 (cc == " ") && 8493 // if it's a space char and the last char is too, consume the 8494 // current one without doing more work 8495 (lc != cc) 8496 ){ 8497 endPart(); 8498 } 8499 } 8500 return queryParts; 8501 }; 8502 8503 8504 //////////////////////////////////////////////////////////////////////// 8505 // DOM query infrastructure 8506 //////////////////////////////////////////////////////////////////////// 8507 8508 var agree = function(first, second){ 8509 // the basic building block of the yes/no chaining system. agree(f1, 8510 // f2) generates a new function which returns the boolean results of 8511 // both of the passed functions to a single logical-anded result. If 8512 // either are not passed, the other is used exclusively. 8513 if(!first){ return second; } 8514 if(!second){ return first; } 8515 8516 return function(){ 8517 return first.apply(window, arguments) && second.apply(window, arguments); 8518 } 8519 }; 8520 8521 var getArr = function(i, arr){ 8522 // helps us avoid array alloc when we don't need it 8523 var r = arr||[]; // FIXME: should this be 'new d._NodeListCtor()' ? 8524 if(i){ r.push(i); } 8525 return r; 8526 }; 8527 8528 var _isElement = function(n){ return (1 == n.nodeType); }; 8529 8530 // FIXME: need to coalesce _getAttr with defaultGetter 8531 var blank = ""; 8532 var _getAttr = function(elem, attr){ 8533 if(!elem){ return blank; } 8534 if(attr == "class"){ 8535 return elem.className || blank; 8536 } 8537 if(attr == "for"){ 8538 return elem.htmlFor || blank; 8539 } 8540 if(attr == "style"){ 8541 return elem.style.cssText || blank; 8542 } 8543 return (caseSensitive ? elem.getAttribute(attr) : elem.getAttribute(attr, 2)) || blank; 8544 }; 8545 8546 var attrs = { 8547 "*=": function(attr, value){ 8548 return function(elem){ 8549 // E[foo*="bar"] 8550 // an E element whose "foo" attribute value contains 8551 // the substring "bar" 8552 return (_getAttr(elem, attr).indexOf(value)>=0); 8553 } 8554 }, 8555 "^=": function(attr, value){ 8556 // E[foo^="bar"] 8557 // an E element whose "foo" attribute value begins exactly 8558 // with the string "bar" 8559 return function(elem){ 8560 return (_getAttr(elem, attr).indexOf(value)==0); 8561 } 8562 }, 8563 "$=": function(attr, value){ 8564 // E[foo$="bar"] 8565 // an E element whose "foo" attribute value ends exactly 8566 // with the string "bar" 8567 var tval = " "+value; 8568 return function(elem){ 8569 var ea = " "+_getAttr(elem, attr); 8570 return (ea.lastIndexOf(value)==(ea.length-value.length)); 8571 } 8572 }, 8573 "~=": function(attr, value){ 8574 // E[foo~="bar"] 8575 // an E element whose "foo" attribute value is a list of 8576 // space-separated values, one of which is exactly equal 8577 // to "bar" 8578 8579 // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]"; 8580 var tval = " "+value+" "; 8581 return function(elem){ 8582 var ea = " "+_getAttr(elem, attr)+" "; 8583 return (ea.indexOf(tval)>=0); 8584 } 8585 }, 8586 "|=": function(attr, value){ 8587 // E[hreflang|="en"] 8588 // an E element whose "hreflang" attribute has a 8589 // hyphen-separated list of values beginning (from the 8590 // left) with "en" 8591 var valueDash = " "+value+"-"; 8592 return function(elem){ 8593 var ea = " "+_getAttr(elem, attr); 8594 return ( 8595 (ea == value) || 8596 (ea.indexOf(valueDash)==0) 8597 ); 8598 } 8599 }, 8600 "=": function(attr, value){ 8601 return function(elem){ 8602 return (_getAttr(elem, attr) == value); 8603 } 8604 } 8605 }; 8606 8607 // avoid testing for node type if we can. Defining this in the negative 8608 // here to avoid negation in the fast path. 8609 var _noNES = (typeof getDoc().firstChild.nextElementSibling == "undefined"); 8610 var _ns = !_noNES ? "nextElementSibling" : "nextSibling"; 8611 var _ps = !_noNES ? "previousElementSibling" : "previousSibling"; 8612 var _simpleNodeTest = (_noNES ? _isElement : yesman); 8613 8614 var _lookLeft = function(node){ 8615 // look left 8616 while(node = node[_ps]){ 8617 if(_simpleNodeTest(node)){ return false; } 8618 } 8619 return true; 8620 }; 8621 8622 var _lookRight = function(node){ 8623 // look right 8624 while(node = node[_ns]){ 8625 if(_simpleNodeTest(node)){ return false; } 8626 } 8627 return true; 8628 }; 8629 8630 var getNodeIndex = function(node){ 8631 var root = node.parentNode; 8632 var i = 0, 8633 tret = root[childNodesName], 8634 ci = (node["_i"]||-1), 8635 cl = (root["_l"]||-1); 8636 8637 if(!tret){ return -1; } 8638 var l = tret.length; 8639 8640 // we calculate the parent length as a cheap way to invalidate the 8641 // cache. It's not 100% accurate, but it's much more honest than what 8642 // other libraries do 8643 if( cl == l && ci >= 0 && cl >= 0 ){ 8644 // if it's legit, tag and release 8645 return ci; 8646 } 8647 8648 // else re-key things 8649 root["_l"] = l; 8650 ci = -1; 8651 for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){ 8652 if(_simpleNodeTest(te)){ 8653 te["_i"] = ++i; 8654 if(node === te){ 8655 // NOTE: 8656 // shortcutting the return at this step in indexing works 8657 // very well for benchmarking but we avoid it here since 8658 // it leads to potential O(n^2) behavior in sequential 8659 // getNodexIndex operations on a previously un-indexed 8660 // parent. We may revisit this at a later time, but for 8661 // now we just want to get the right answer more often 8662 // than not. 8663 ci = i; 8664 } 8665 } 8666 } 8667 return ci; 8668 }; 8669 8670 var isEven = function(elem){ 8671 return !((getNodeIndex(elem)) % 2); 8672 }; 8673 8674 var isOdd = function(elem){ 8675 return ((getNodeIndex(elem)) % 2); 8676 }; 8677 8678 var pseudos = { 8679 "checked": function(name, condition){ 8680 return function(elem){ 8681 return !!("checked" in elem ? elem.checked : elem.selected); 8682 } 8683 }, 8684 "first-child": function(){ return _lookLeft; }, 8685 "last-child": function(){ return _lookRight; }, 8686 "only-child": function(name, condition){ 8687 return function(node){ 8688 if(!_lookLeft(node)){ return false; } 8689 if(!_lookRight(node)){ return false; } 8690 return true; 8691 }; 8692 }, 8693 "empty": function(name, condition){ 8694 return function(elem){ 8695 // DomQuery and jQuery get this wrong, oddly enough. 8696 // The CSS 3 selectors spec is pretty explicit about it, too. 8697 var cn = elem.childNodes; 8698 var cnl = elem.childNodes.length; 8699 // if(!cnl){ return true; } 8700 for(var x=cnl-1; x >= 0; x--){ 8701 var nt = cn[x].nodeType; 8702 if((nt === 1)||(nt == 3)){ return false; } 8703 } 8704 return true; 8705 } 8706 }, 8707 "contains": function(name, condition){ 8708 var cz = condition.charAt(0); 8709 if( cz == '"' || cz == "'" ){ //remove quote 8710 condition = condition.slice(1, -1); 8711 } 8712 return function(elem){ 8713 return (elem.innerHTML.indexOf(condition) >= 0); 8714 } 8715 }, 8716 "not": function(name, condition){ 8717 var p = getQueryParts(condition)[0]; 8718 var ignores = { el: 1 }; 8719 if(p.tag != "*"){ 8720 ignores.tag = 1; 8721 } 8722 if(!p.classes.length){ 8723 ignores.classes = 1; 8724 } 8725 var ntf = getSimpleFilterFunc(p, ignores); 8726 return function(elem){ 8727 return (!ntf(elem)); 8728 } 8729 }, 8730 "nth-child": function(name, condition){ 8731 var pi = parseInt; 8732 // avoid re-defining function objects if we can 8733 if(condition == "odd"){ 8734 return isOdd; 8735 }else if(condition == "even"){ 8736 return isEven; 8737 } 8738 // FIXME: can we shorten this? 8739 if(condition.indexOf("n") != -1){ 8740 var tparts = condition.split("n", 2); 8741 var pred = tparts[0] ? ((tparts[0] == '-') ? -1 : pi(tparts[0])) : 1; 8742 var idx = tparts[1] ? pi(tparts[1]) : 0; 8743 var lb = 0, ub = -1; 8744 if(pred > 0){ 8745 if(idx < 0){ 8746 idx = (idx % pred) && (pred + (idx % pred)); 8747 }else if(idx>0){ 8748 if(idx >= pred){ 8749 lb = idx - idx % pred; 8750 } 8751 idx = idx % pred; 8752 } 8753 }else if(pred<0){ 8754 pred *= -1; 8755 // idx has to be greater than 0 when pred is negative; 8756 // shall we throw an error here? 8757 if(idx > 0){ 8758 ub = idx; 8759 idx = idx % pred; 8760 } 8761 } 8762 if(pred > 0){ 8763 return function(elem){ 8764 var i = getNodeIndex(elem); 8765 return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx); 8766 } 8767 }else{ 8768 condition = idx; 8769 } 8770 } 8771 var ncount = pi(condition); 8772 return function(elem){ 8773 return (getNodeIndex(elem) == ncount); 8774 } 8775 } 8776 }; 8777 8778 var defaultGetter = (d.isIE < 9 || (dojo.isIE && dojo.isQuirks)) ? function(cond){ 8779 var clc = cond.toLowerCase(); 8780 if(clc == "class"){ cond = "className"; } 8781 return function(elem){ 8782 return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]); 8783 } 8784 } : function(cond){ 8785 return function(elem){ 8786 return (elem && elem.getAttribute && elem.hasAttribute(cond)); 8787 } 8788 }; 8789 8790 var getSimpleFilterFunc = function(query, ignores){ 8791 // generates a node tester function based on the passed query part. The 8792 // query part is one of the structures generated by the query parser 8793 // when it creates the query AST. The "ignores" object specifies which 8794 // (if any) tests to skip, allowing the system to avoid duplicating 8795 // work where it may have already been taken into account by other 8796 // factors such as how the nodes to test were fetched in the first 8797 // place 8798 if(!query){ return yesman; } 8799 ignores = ignores||{}; 8800 8801 var ff = null; 8802 8803 if(!("el" in ignores)){ 8804 ff = agree(ff, _isElement); 8805 } 8806 8807 if(!("tag" in ignores)){ 8808 if(query.tag != "*"){ 8809 ff = agree(ff, function(elem){ 8810 return (elem && (elem.tagName == query.getTag())); 8811 }); 8812 } 8813 } 8814 8815 if(!("classes" in ignores)){ 8816 each(query.classes, function(cname, idx, arr){ 8817 // get the class name 8818 /* 8819 var isWildcard = cname.charAt(cname.length-1) == "*"; 8820 if(isWildcard){ 8821 cname = cname.substr(0, cname.length-1); 8822 } 8823 // I dislike the regex thing, even if memoized in a cache, but it's VERY short 8824 var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)"); 8825 */ 8826 var re = new RegExp("(?:^|\\s)" + cname + "(?:\\s|$)"); 8827 ff = agree(ff, function(elem){ 8828 return re.test(elem.className); 8829 }); 8830 ff.count = idx; 8831 }); 8832 } 8833 8834 if(!("pseudos" in ignores)){ 8835 each(query.pseudos, function(pseudo){ 8836 var pn = pseudo.name; 8837 if(pseudos[pn]){ 8838 ff = agree(ff, pseudos[pn](pn, pseudo.value)); 8839 } 8840 }); 8841 } 8842 8843 if(!("attrs" in ignores)){ 8844 each(query.attrs, function(attr){ 8845 var matcher; 8846 var a = attr.attr; 8847 // type, attr, matchFor 8848 if(attr.type && attrs[attr.type]){ 8849 matcher = attrs[attr.type](a, attr.matchFor); 8850 }else if(a.length){ 8851 matcher = defaultGetter(a); 8852 } 8853 if(matcher){ 8854 ff = agree(ff, matcher); 8855 } 8856 }); 8857 } 8858 8859 if(!("id" in ignores)){ 8860 if(query.id){ 8861 ff = agree(ff, function(elem){ 8862 return (!!elem && (elem.id == query.id)); 8863 }); 8864 } 8865 } 8866 8867 if(!ff){ 8868 if(!("default" in ignores)){ 8869 ff = yesman; 8870 } 8871 } 8872 return ff; 8873 }; 8874 8875 var _nextSibling = function(filterFunc){ 8876 return function(node, ret, bag){ 8877 while(node = node[_ns]){ 8878 if(_noNES && (!_isElement(node))){ continue; } 8879 if( 8880 (!bag || _isUnique(node, bag)) && 8881 filterFunc(node) 8882 ){ 8883 ret.push(node); 8884 } 8885 break; 8886 } 8887 return ret; 8888 } 8889 }; 8890 8891 var _nextSiblings = function(filterFunc){ 8892 return function(root, ret, bag){ 8893 var te = root[_ns]; 8894 while(te){ 8895 if(_simpleNodeTest(te)){ 8896 if(bag && !_isUnique(te, bag)){ 8897 break; 8898 } 8899 if(filterFunc(te)){ 8900 ret.push(te); 8901 } 8902 } 8903 te = te[_ns]; 8904 } 8905 return ret; 8906 } 8907 }; 8908 8909 // get an array of child *elements*, skipping text and comment nodes 8910 var _childElements = function(filterFunc){ 8911 filterFunc = filterFunc||yesman; 8912 return function(root, ret, bag){ 8913 // get an array of child elements, skipping text and comment nodes 8914 var te, x = 0, tret = root[childNodesName]; 8915 while(te = tret[x++]){ 8916 if( 8917 _simpleNodeTest(te) && 8918 (!bag || _isUnique(te, bag)) && 8919 (filterFunc(te, x)) 8920 ){ 8921 ret.push(te); 8922 } 8923 } 8924 return ret; 8925 }; 8926 }; 8927 8928 /* 8929 // thanks, Dean! 8930 var itemIsAfterRoot = d.isIE ? function(item, root){ 8931 return (item.sourceIndex > root.sourceIndex); 8932 } : function(item, root){ 8933 return (item.compareDocumentPosition(root) == 2); 8934 }; 8935 */ 8936 8937 // test to see if node is below root 8938 var _isDescendant = function(node, root){ 8939 var pn = node.parentNode; 8940 while(pn){ 8941 if(pn == root){ 8942 break; 8943 } 8944 pn = pn.parentNode; 8945 } 8946 return !!pn; 8947 }; 8948 8949 var _getElementsFuncCache = {}; 8950 8951 var getElementsFunc = function(query){ 8952 var retFunc = _getElementsFuncCache[query.query]; 8953 // if we've got a cached dispatcher, just use that 8954 if(retFunc){ return retFunc; } 8955 // else, generate a new on 8956 8957 // NOTE: 8958 // this function returns a function that searches for nodes and 8959 // filters them. The search may be specialized by infix operators 8960 // (">", "~", or "+") else it will default to searching all 8961 // descendants (the " " selector). Once a group of children is 8962 // found, a test function is applied to weed out the ones we 8963 // don't want. Many common cases can be fast-pathed. We spend a 8964 // lot of cycles to create a dispatcher that doesn't do more work 8965 // than necessary at any point since, unlike this function, the 8966 // dispatchers will be called every time. The logic of generating 8967 // efficient dispatchers looks like this in pseudo code: 8968 // 8969 // # if it's a purely descendant query (no ">", "+", or "~" modifiers) 8970 // if infixOperator == " ": 8971 // if only(id): 8972 // return def(root): 8973 // return d.byId(id, root); 8974 // 8975 // elif id: 8976 // return def(root): 8977 // return filter(d.byId(id, root)); 8978 // 8979 // elif cssClass && getElementsByClassName: 8980 // return def(root): 8981 // return filter(root.getElementsByClassName(cssClass)); 8982 // 8983 // elif only(tag): 8984 // return def(root): 8985 // return root.getElementsByTagName(tagName); 8986 // 8987 // else: 8988 // # search by tag name, then filter 8989 // return def(root): 8990 // return filter(root.getElementsByTagName(tagName||"*")); 8991 // 8992 // elif infixOperator == ">": 8993 // # search direct children 8994 // return def(root): 8995 // return filter(root.children); 8996 // 8997 // elif infixOperator == "+": 8998 // # search next sibling 8999 // return def(root): 9000 // return filter(root.nextElementSibling); 9001 // 9002 // elif infixOperator == "~": 9003 // # search rightward siblings 9004 // return def(root): 9005 // return filter(nextSiblings(root)); 9006 9007 var io = query.infixOper; 9008 var oper = (io ? io.oper : ""); 9009 // the default filter func which tests for all conditions in the query 9010 // part. This is potentially inefficient, so some optimized paths may 9011 // re-define it to test fewer things. 9012 var filterFunc = getSimpleFilterFunc(query, { el: 1 }); 9013 var qt = query.tag; 9014 var wildcardTag = ("*" == qt); 9015 var ecs = getDoc()["getElementsByClassName"]; 9016 9017 if(!oper){ 9018 // if there's no infix operator, then it's a descendant query. ID 9019 // and "elements by class name" variants can be accelerated so we 9020 // call them out explicitly: 9021 if(query.id){ 9022 // testing shows that the overhead of yesman() is acceptable 9023 // and can save us some bytes vs. re-defining the function 9024 // everywhere. 9025 filterFunc = (!query.loops && wildcardTag) ? 9026 yesman : 9027 getSimpleFilterFunc(query, { el: 1, id: 1 }); 9028 9029 retFunc = function(root, arr){ 9030 var te = d.byId(query.id, (root.ownerDocument||root)); 9031 if(!te || !filterFunc(te)){ return; } 9032 if(9 == root.nodeType){ // if root's a doc, we just return directly 9033 return getArr(te, arr); 9034 }else{ // otherwise check ancestry 9035 if(_isDescendant(te, root)){ 9036 return getArr(te, arr); 9037 } 9038 } 9039 } 9040 }else if( 9041 ecs && 9042 // isAlien check. Workaround for Prototype.js being totally evil/dumb. 9043 /\{\s*\[native code\]\s*\}/.test(String(ecs)) && 9044 query.classes.length && 9045 !cssCaseBug 9046 ){ 9047 // it's a class-based query and we've got a fast way to run it. 9048 9049 // ignore class and ID filters since we will have handled both 9050 filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 }); 9051 var classesString = query.classes.join(" "); 9052 retFunc = function(root, arr, bag){ 9053 var ret = getArr(0, arr), te, x=0; 9054 var tret = root.getElementsByClassName(classesString); 9055 while((te = tret[x++])){ 9056 if(filterFunc(te, root) && _isUnique(te, bag)){ 9057 ret.push(te); 9058 } 9059 } 9060 return ret; 9061 }; 9062 9063 }else if(!wildcardTag && !query.loops){ 9064 // it's tag only. Fast-path it. 9065 retFunc = function(root, arr, bag){ 9066 var ret = getArr(0, arr), te, x=0; 9067 var tret = root.getElementsByTagName(query.getTag()); 9068 while((te = tret[x++])){ 9069 if(_isUnique(te, bag)){ 9070 ret.push(te); 9071 } 9072 } 9073 return ret; 9074 }; 9075 }else{ 9076 // the common case: 9077 // a descendant selector without a fast path. By now it's got 9078 // to have a tag selector, even if it's just "*" so we query 9079 // by that and filter 9080 filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 }); 9081 retFunc = function(root, arr, bag){ 9082 var ret = getArr(0, arr), te, x=0; 9083 // we use getTag() to avoid case sensitivity issues 9084 var tret = root.getElementsByTagName(query.getTag()); 9085 while((te = tret[x++])){ 9086 if(filterFunc(te, root) && _isUnique(te, bag)){ 9087 ret.push(te); 9088 } 9089 } 9090 return ret; 9091 }; 9092 } 9093 }else{ 9094 // the query is scoped in some way. Instead of querying by tag we 9095 // use some other collection to find candidate nodes 9096 var skipFilters = { el: 1 }; 9097 if(wildcardTag){ 9098 skipFilters.tag = 1; 9099 } 9100 filterFunc = getSimpleFilterFunc(query, skipFilters); 9101 if("+" == oper){ 9102 retFunc = _nextSibling(filterFunc); 9103 }else if("~" == oper){ 9104 retFunc = _nextSiblings(filterFunc); 9105 }else if(">" == oper){ 9106 retFunc = _childElements(filterFunc); 9107 } 9108 } 9109 // cache it and return 9110 return _getElementsFuncCache[query.query] = retFunc; 9111 }; 9112 9113 var filterDown = function(root, queryParts){ 9114 // NOTE: 9115 // this is the guts of the DOM query system. It takes a list of 9116 // parsed query parts and a root and finds children which match 9117 // the selector represented by the parts 9118 var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret; 9119 9120 for(var i = 0; i < qpl; i++){ 9121 ret = []; 9122 qp = queryParts[i]; 9123 x = candidates.length - 1; 9124 if(x > 0){ 9125 // if we have more than one root at this level, provide a new 9126 // hash to use for checking group membership but tell the 9127 // system not to post-filter us since we will already have been 9128 // gauranteed to be unique 9129 bag = {}; 9130 ret.nozip = true; 9131 } 9132 var gef = getElementsFunc(qp); 9133 for(var j = 0; (te = candidates[j]); j++){ 9134 // for every root, get the elements that match the descendant 9135 // selector, adding them to the "ret" array and filtering them 9136 // via membership in this level's bag. If there are more query 9137 // parts, then this level's return will be used as the next 9138 // level's candidates 9139 gef(te, ret, bag); 9140 } 9141 if(!ret.length){ break; } 9142 candidates = ret; 9143 } 9144 return ret; 9145 }; 9146 9147 //////////////////////////////////////////////////////////////////////// 9148 // the query runner 9149 //////////////////////////////////////////////////////////////////////// 9150 9151 // these are the primary caches for full-query results. The query 9152 // dispatcher functions are generated then stored here for hash lookup in 9153 // the future 9154 var _queryFuncCacheDOM = {}, 9155 _queryFuncCacheQSA = {}; 9156 9157 // this is the second level of spliting, from full-length queries (e.g., 9158 // "div.foo .bar") into simple query expressions (e.g., ["div.foo", 9159 // ".bar"]) 9160 var getStepQueryFunc = function(query){ 9161 var qparts = getQueryParts(trim(query)); 9162 9163 // if it's trivial, avoid iteration and zipping costs 9164 if(qparts.length == 1){ 9165 // we optimize this case here to prevent dispatch further down the 9166 // chain, potentially slowing things down. We could more elegantly 9167 // handle this in filterDown(), but it's slower for simple things 9168 // that need to be fast (e.g., "#someId"). 9169 var tef = getElementsFunc(qparts[0]); 9170 return function(root){ 9171 var r = tef(root, new qlc()); 9172 if(r){ r.nozip = true; } 9173 return r; 9174 } 9175 } 9176 9177 // otherwise, break it up and return a runner that iterates over the parts recursively 9178 return function(root){ 9179 return filterDown(root, qparts); 9180 } 9181 }; 9182 9183 // NOTES: 9184 // * we can't trust QSA for anything but document-rooted queries, so 9185 // caching is split into DOM query evaluators and QSA query evaluators 9186 // * caching query results is dirty and leak-prone (or, at a minimum, 9187 // prone to unbounded growth). Other toolkits may go this route, but 9188 // they totally destroy their own ability to manage their memory 9189 // footprint. If we implement it, it should only ever be with a fixed 9190 // total element reference # limit and an LRU-style algorithm since JS 9191 // has no weakref support. Caching compiled query evaluators is also 9192 // potentially problematic, but even on large documents the size of the 9193 // query evaluators is often < 100 function objects per evaluator (and 9194 // LRU can be applied if it's ever shown to be an issue). 9195 // * since IE's QSA support is currently only for HTML documents and even 9196 // then only in IE 8's "standards mode", we have to detect our dispatch 9197 // route at query time and keep 2 separate caches. Ugg. 9198 9199 // we need to determine if we think we can run a given query via 9200 // querySelectorAll or if we'll need to fall back on DOM queries to get 9201 // there. We need a lot of information about the environment and the query 9202 // to make the determiniation (e.g. does it support QSA, does the query in 9203 // question work in the native QSA impl, etc.). 9204 var nua = navigator.userAgent; 9205 // some versions of Safari provided QSA, but it was buggy and crash-prone. 9206 // We need te detect the right "internal" webkit version to make this work. 9207 var wk = "WebKit/"; 9208 var is525 = ( 9209 d.isWebKit && 9210 (nua.indexOf(wk) > 0) && 9211 (parseFloat(nua.split(wk)[1]) > 528) 9212 ); 9213 9214 // IE QSA queries may incorrectly include comment nodes, so we throw the 9215 // zipping function into "remove" comments mode instead of the normal "skip 9216 // it" which every other QSA-clued browser enjoys 9217 var noZip = d.isIE ? "commentStrip" : "nozip"; 9218 9219 var qsa = "querySelectorAll"; 9220 var qsaAvail = ( 9221 !!getDoc()[qsa] && 9222 // see #5832 9223 (!d.isSafari || (d.isSafari > 3.1) || is525 ) 9224 ); 9225 9226 //Don't bother with n+3 type of matches, IE complains if we modify those. 9227 var infixSpaceRe = /n\+\d|([^ ])?([>~+])([^ =])?/g; 9228 var infixSpaceFunc = function(match, pre, ch, post) { 9229 return ch ? (pre ? pre + " " : "") + ch + (post ? " " + post : "") : /*n+3*/ match; 9230 }; 9231 9232 var getQueryFunc = function(query, forceDOM){ 9233 //Normalize query. The CSS3 selectors spec allows for omitting spaces around 9234 //infix operators, >, ~ and + 9235 //Do the work here since detection for spaces is used as a simple "not use QSA" 9236 //test below. 9237 query = query.replace(infixSpaceRe, infixSpaceFunc); 9238 9239 if(qsaAvail){ 9240 // if we've got a cached variant and we think we can do it, run it! 9241 var qsaCached = _queryFuncCacheQSA[query]; 9242 if(qsaCached && !forceDOM){ return qsaCached; } 9243 } 9244 9245 // else if we've got a DOM cached variant, assume that we already know 9246 // all we need to and use it 9247 var domCached = _queryFuncCacheDOM[query]; 9248 if(domCached){ return domCached; } 9249 9250 // TODO: 9251 // today we're caching DOM and QSA branches separately so we 9252 // recalc useQSA every time. If we had a way to tag root+query 9253 // efficiently, we'd be in good shape to do a global cache. 9254 9255 var qcz = query.charAt(0); 9256 var nospace = (-1 == query.indexOf(" ")); 9257 9258 // byId searches are wicked fast compared to QSA, even when filtering 9259 // is required 9260 if( (query.indexOf("#") >= 0) && (nospace) ){ 9261 forceDOM = true; 9262 } 9263 9264 var useQSA = ( 9265 qsaAvail && (!forceDOM) && 9266 // as per CSS 3, we can't currently start w/ combinator: 9267 // http://www.w3.org/TR/css3-selectors/#w3cselgrammar 9268 (specials.indexOf(qcz) == -1) && 9269 // IE's QSA impl sucks on pseudos 9270 (!d.isIE || (query.indexOf(":") == -1)) && 9271 9272 (!(cssCaseBug && (query.indexOf(".") >= 0))) && 9273 9274 // FIXME: 9275 // need to tighten up browser rules on ":contains" and "|=" to 9276 // figure out which aren't good 9277 // Latest webkit (around 531.21.8) does not seem to do well with :checked on option 9278 // elements, even though according to spec, selected options should 9279 // match :checked. So go nonQSA for it: 9280 // http://bugs.dojotoolkit.org/ticket/5179 9281 (query.indexOf(":contains") == -1) && (query.indexOf(":checked") == -1) && 9282 (query.indexOf("|=") == -1) // some browsers don't grok it 9283 ); 9284 9285 // TODO: 9286 // if we've got a descendant query (e.g., "> .thinger" instead of 9287 // just ".thinger") in a QSA-able doc, but are passed a child as a 9288 // root, it should be possible to give the item a synthetic ID and 9289 // trivially rewrite the query to the form "#synid > .thinger" to 9290 // use the QSA branch 9291 9292 9293 if(useQSA){ 9294 var tq = (specials.indexOf(query.charAt(query.length-1)) >= 0) ? 9295 (query + " *") : query; 9296 return _queryFuncCacheQSA[query] = function(root){ 9297 try{ 9298 // the QSA system contains an egregious spec bug which 9299 // limits us, effectively, to only running QSA queries over 9300 // entire documents. See: 9301 // http://ejohn.org/blog/thoughts-on-queryselectorall/ 9302 // despite this, we can also handle QSA runs on simple 9303 // selectors, but we don't want detection to be expensive 9304 // so we're just checking for the presence of a space char 9305 // right now. Not elegant, but it's cheaper than running 9306 // the query parser when we might not need to 9307 if(!((9 == root.nodeType) || nospace)){ throw ""; } 9308 var r = root[qsa](tq); 9309 // skip expensive duplication checks and just wrap in a NodeList 9310 r[noZip] = true; 9311 return r; 9312 }catch(e){ 9313 // else run the DOM branch on this query, ensuring that we 9314 // default that way in the future 9315 return getQueryFunc(query, true)(root); 9316 } 9317 } 9318 }else{ 9319 // DOM branch 9320 var parts = query.split(/\s*,\s*/); 9321 return _queryFuncCacheDOM[query] = ((parts.length < 2) ? 9322 // if not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher 9323 getStepQueryFunc(query) : 9324 // if it *is* a complex query, break it up into its 9325 // constituent parts and return a dispatcher that will 9326 // merge the parts when run 9327 function(root){ 9328 var pindex = 0, // avoid array alloc for every invocation 9329 ret = [], 9330 tp; 9331 while((tp = parts[pindex++])){ 9332 ret = ret.concat(getStepQueryFunc(tp)(root)); 9333 } 9334 return ret; 9335 } 9336 ); 9337 } 9338 }; 9339 9340 var _zipIdx = 0; 9341 9342 // NOTE: 9343 // this function is Moo inspired, but our own impl to deal correctly 9344 // with XML in IE 9345 var _nodeUID = d.isIE ? function(node){ 9346 if(caseSensitive){ 9347 // XML docs don't have uniqueID on their nodes 9348 return (node.getAttribute("_uid") || node.setAttribute("_uid", ++_zipIdx) || _zipIdx); 9349 9350 }else{ 9351 return node.uniqueID; 9352 } 9353 } : 9354 function(node){ 9355 return (node._uid || (node._uid = ++_zipIdx)); 9356 }; 9357 9358 // determine if a node in is unique in a "bag". In this case we don't want 9359 // to flatten a list of unique items, but rather just tell if the item in 9360 // question is already in the bag. Normally we'd just use hash lookup to do 9361 // this for us but IE's DOM is busted so we can't really count on that. On 9362 // the upside, it gives us a built in unique ID function. 9363 var _isUnique = function(node, bag){ 9364 if(!bag){ return 1; } 9365 var id = _nodeUID(node); 9366 if(!bag[id]){ return bag[id] = 1; } 9367 return 0; 9368 }; 9369 9370 // attempt to efficiently determine if an item in a list is a dupe, 9371 // returning a list of "uniques", hopefully in doucment order 9372 var _zipIdxName = "_zipIdx"; 9373 var _zip = function(arr){ 9374 if(arr && arr.nozip){ 9375 return (qlc._wrap) ? qlc._wrap(arr) : arr; 9376 } 9377 // var ret = new d._NodeListCtor(); 9378 var ret = new qlc(); 9379 if(!arr || !arr.length){ return ret; } 9380 if(arr[0]){ 9381 ret.push(arr[0]); 9382 } 9383 if(arr.length < 2){ return ret; } 9384 9385 _zipIdx++; 9386 9387 // we have to fork here for IE and XML docs because we can't set 9388 // expandos on their nodes (apparently). *sigh* 9389 if(d.isIE && caseSensitive){ 9390 var szidx = _zipIdx+""; 9391 arr[0].setAttribute(_zipIdxName, szidx); 9392 for(var x = 1, te; te = arr[x]; x++){ 9393 if(arr[x].getAttribute(_zipIdxName) != szidx){ 9394 ret.push(te); 9395 } 9396 te.setAttribute(_zipIdxName, szidx); 9397 } 9398 }else if(d.isIE && arr.commentStrip){ 9399 try{ 9400 for(var x = 1, te; te = arr[x]; x++){ 9401 if(_isElement(te)){ 9402 ret.push(te); 9403 } 9404 } 9405 }catch(e){ /* squelch */ } 9406 }else{ 9407 if(arr[0]){ arr[0][_zipIdxName] = _zipIdx; } 9408 for(var x = 1, te; te = arr[x]; x++){ 9409 if(arr[x][_zipIdxName] != _zipIdx){ 9410 ret.push(te); 9411 } 9412 te[_zipIdxName] = _zipIdx; 9413 } 9414 } 9415 return ret; 9416 }; 9417 9418 // the main executor 9419 d.query = function(/*String*/ query, /*String|DOMNode?*/ root){ 9420 // summary: 9421 // Returns nodes which match the given CSS3 selector, searching the 9422 // entire document by default but optionally taking a node to scope 9423 // the search by. Returns an instance of dojo.NodeList. 9424 // description: 9425 // dojo.query() is the swiss army knife of DOM node manipulation in 9426 // Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's 9427 // "$" function, dojo.query provides robust, high-performance 9428 // CSS-based node selector support with the option of scoping searches 9429 // to a particular sub-tree of a document. 9430 // 9431 // Supported Selectors: 9432 // -------------------- 9433 // 9434 // dojo.query() supports a rich set of CSS3 selectors, including: 9435 // 9436 // * class selectors (e.g., `.foo`) 9437 // * node type selectors like `span` 9438 // * ` ` descendant selectors 9439 // * `>` child element selectors 9440 // * `#foo` style ID selectors 9441 // * `*` universal selector 9442 // * `~`, the preceded-by sibling selector 9443 // * `+`, the immediately preceded-by sibling selector 9444 // * attribute queries: 9445 // | * `[foo]` attribute presence selector 9446 // | * `[foo='bar']` attribute value exact match 9447 // | * `[foo~='bar']` attribute value list item match 9448 // | * `[foo^='bar']` attribute start match 9449 // | * `[foo$='bar']` attribute end match 9450 // | * `[foo*='bar']` attribute substring match 9451 // * `:first-child`, `:last-child`, and `:only-child` positional selectors 9452 // * `:empty` content emtpy selector 9453 // * `:checked` pseudo selector 9454 // * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations 9455 // * `:nth-child(even)`, `:nth-child(odd)` positional selectors 9456 // * `:not(...)` negation pseudo selectors 9457 // 9458 // Any legal combination of these selectors will work with 9459 // `dojo.query()`, including compound selectors ("," delimited). 9460 // Very complex and useful searches can be constructed with this 9461 // palette of selectors and when combined with functions for 9462 // manipulation presented by dojo.NodeList, many types of DOM 9463 // manipulation operations become very straightforward. 9464 // 9465 // Unsupported Selectors: 9466 // ---------------------- 9467 // 9468 // While dojo.query handles many CSS3 selectors, some fall outside of 9469 // what's reasonable for a programmatic node querying engine to 9470 // handle. Currently unsupported selectors include: 9471 // 9472 // * namespace-differentiated selectors of any form 9473 // * all `::` pseduo-element selectors 9474 // * certain pseduo-selectors which don't get a lot of day-to-day use: 9475 // | * `:root`, `:lang()`, `:target`, `:focus` 9476 // * all visual and state selectors: 9477 // | * `:root`, `:active`, `:hover`, `:visisted`, `:link`, 9478 // `:enabled`, `:disabled` 9479 // * `:*-of-type` pseudo selectors 9480 // 9481 // dojo.query and XML Documents: 9482 // ----------------------------- 9483 // 9484 // `dojo.query` (as of dojo 1.2) supports searching XML documents 9485 // in a case-sensitive manner. If an HTML document is served with 9486 // a doctype that forces case-sensitivity (e.g., XHTML 1.1 9487 // Strict), dojo.query() will detect this and "do the right 9488 // thing". Case sensitivity is dependent upon the document being 9489 // searched and not the query used. It is therefore possible to 9490 // use case-sensitive queries on strict sub-documents (iframes, 9491 // etc.) or XML documents while still assuming case-insensitivity 9492 // for a host/root document. 9493 // 9494 // Non-selector Queries: 9495 // --------------------- 9496 // 9497 // If something other than a String is passed for the query, 9498 // `dojo.query` will return a new `dojo.NodeList` instance 9499 // constructed from that parameter alone and all further 9500 // processing will stop. This means that if you have a reference 9501 // to a node or NodeList, you can quickly construct a new NodeList 9502 // from the original by calling `dojo.query(node)` or 9503 // `dojo.query(list)`. 9504 // 9505 // query: 9506 // The CSS3 expression to match against. For details on the syntax of 9507 // CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors> 9508 // root: 9509 // A DOMNode (or node id) to scope the search from. Optional. 9510 // returns: dojo.NodeList 9511 // An instance of `dojo.NodeList`. Many methods are available on 9512 // NodeLists for searching, iterating, manipulating, and handling 9513 // events on the matched nodes in the returned list. 9514 // example: 9515 // search the entire document for elements with the class "foo": 9516 // | dojo.query(".foo"); 9517 // these elements will match: 9518 // | <span class="foo"></span> 9519 // | <span class="foo bar"></span> 9520 // | <p class="thud foo"></p> 9521 // example: 9522 // search the entire document for elements with the classes "foo" *and* "bar": 9523 // | dojo.query(".foo.bar"); 9524 // these elements will match: 9525 // | <span class="foo bar"></span> 9526 // while these will not: 9527 // | <span class="foo"></span> 9528 // | <p class="thud foo"></p> 9529 // example: 9530 // find `<span>` elements which are descendants of paragraphs and 9531 // which have a "highlighted" class: 9532 // | dojo.query("p span.highlighted"); 9533 // the innermost span in this fragment matches: 9534 // | <p class="foo"> 9535 // | <span>... 9536 // | <span class="highlighted foo bar">...</span> 9537 // | </span> 9538 // | </p> 9539 // example: 9540 // set an "odd" class on all odd table rows inside of the table 9541 // `#tabular_data`, using the `>` (direct child) selector to avoid 9542 // affecting any nested tables: 9543 // | dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd"); 9544 // example: 9545 // remove all elements with the class "error" from the document 9546 // and store them in a list: 9547 // | var errors = dojo.query(".error").orphan(); 9548 // example: 9549 // add an onclick handler to every submit button in the document 9550 // which causes the form to be sent via Ajax instead: 9551 // | dojo.query("input[type='submit']").onclick(function(e){ 9552 // | dojo.stopEvent(e); // prevent sending the form 9553 // | var btn = e.target; 9554 // | dojo.xhrPost({ 9555 // | form: btn.form, 9556 // | load: function(data){ 9557 // | // replace the form with the response 9558 // | var div = dojo.doc.createElement("div"); 9559 // | dojo.place(div, btn.form, "after"); 9560 // | div.innerHTML = data; 9561 // | dojo.style(btn.form, "display", "none"); 9562 // | } 9563 // | }); 9564 // | }); 9565 9566 //Set list constructor to desired value. This can change 9567 //between calls, so always re-assign here. 9568 qlc = d._NodeListCtor; 9569 9570 if(!query){ 9571 return new qlc(); 9572 } 9573 9574 if(query.constructor == qlc){ 9575 return query; 9576 } 9577 if(typeof query != "string"){ // inline'd type check 9578 return new qlc(query); // dojo.NodeList 9579 } 9580 if(typeof root == "string"){ // inline'd type check 9581 root = d.byId(root); 9582 if(!root){ return new qlc(); } 9583 } 9584 9585 root = root||getDoc(); 9586 var od = root.ownerDocument||root.documentElement; 9587 9588 // throw the big case sensitivity switch 9589 9590 // NOTE: 9591 // Opera in XHTML mode doesn't detect case-sensitivity correctly 9592 // and it's not clear that there's any way to test for it 9593 caseSensitive = (root.contentType && root.contentType=="application/xml") || 9594 (d.isOpera && (root.doctype || od.toString() == "[object XMLDocument]")) || 9595 (!!od) && 9596 (d.isIE ? od.xml : (root.xmlVersion||od.xmlVersion)); 9597 9598 // NOTE: 9599 // adding "true" as the 2nd argument to getQueryFunc is useful for 9600 // testing the DOM branch without worrying about the 9601 // behavior/performance of the QSA branch. 9602 var r = getQueryFunc(query)(root); 9603 9604 // FIXME: 9605 // need to investigate this branch WRT #8074 and #8075 9606 if(r && r.nozip && !qlc._wrap){ 9607 return r; 9608 } 9609 return _zip(r); // dojo.NodeList 9610 } 9611 9612 // FIXME: need to add infrastructure for post-filtering pseudos, ala :last 9613 d.query.pseudos = pseudos; 9614 9615 // function for filtering a NodeList based on a selector, optimized for simple selectors 9616 d._filterQueryResult = function(/*NodeList*/ nodeList, /*String*/ filter, /*String|DOMNode?*/ root){ 9617 var tmpNodeList = new d._NodeListCtor(), 9618 parts = getQueryParts(filter), 9619 filterFunc = 9620 (parts.length == 1 && !/[^\w#\.]/.test(filter)) ? 9621 getSimpleFilterFunc(parts[0]) : 9622 function(node) { 9623 return dojo.query(filter, root).indexOf(node) != -1; 9624 }; 9625 for(var x = 0, te; te = nodeList[x]; x++){ 9626 if(filterFunc(te)){ tmpNodeList.push(te); } 9627 } 9628 return tmpNodeList; 9629 } 9630 };//end defineQuery 9631 9632 var defineAcme= function(){ 9633 // a self-sufficient query impl 9634 acme = { 9635 trim: function(/*String*/ str){ 9636 // summary: 9637 // trims whitespaces from both sides of the string 9638 str = str.replace(/^\s+/, ''); 9639 for(var i = str.length - 1; i >= 0; i--){ 9640 if(/\S/.test(str.charAt(i))){ 9641 str = str.substring(0, i + 1); 9642 break; 9643 } 9644 } 9645 return str; // String 9646 }, 9647 forEach: function(/*String*/ arr, /*Function*/ callback, /*Object?*/ thisObject){ 9648 // summary: 9649 // an iterator function that passes items, indexes, 9650 // and the array to a callback 9651 if(!arr || !arr.length){ return; } 9652 for(var i=0,l=arr.length; i<l; ++i){ 9653 callback.call(thisObject||window, arr[i], i, arr); 9654 } 9655 }, 9656 byId: function(id, doc){ 9657 // summary: 9658 // a function that return an element by ID, but also 9659 // accepts nodes safely 9660 if(typeof id == "string"){ 9661 return (doc||document).getElementById(id); // DomNode 9662 }else{ 9663 return id; // DomNode 9664 } 9665 }, 9666 // the default document to search 9667 doc: document, 9668 // the constructor for node list objects returned from query() 9669 NodeList: Array 9670 }; 9671 9672 // define acme.isIE, acme.isSafari, acme.isOpera, etc. 9673 var n = navigator; 9674 var dua = n.userAgent; 9675 var dav = n.appVersion; 9676 var tv = parseFloat(dav); 9677 acme.isOpera = (dua.indexOf("Opera") >= 0) ? tv: undefined; 9678 acme.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : undefined; 9679 acme.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined; 9680 acme.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined; 9681 var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0); 9682 if(index && !acme.isChrome){ 9683 acme.isSafari = parseFloat(dav.split("Version/")[1]); 9684 if(!acme.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){ 9685 acme.isSafari = 2; 9686 } 9687 } 9688 if(document.all && !acme.isOpera){ 9689 acme.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined; 9690 } 9691 9692 Array._wrap = function(arr){ return arr; }; 9693 return acme; 9694 }; 9695 9696 //prefers queryPortability, then acme, then dojo 9697 if(this["dojo"]){ 9698 dojo.provide("dojo._base.query"); 9699 9700 9701 defineQuery(this["queryPortability"]||this["acme"]||dojo); 9702 }else{ 9703 defineQuery(this["queryPortability"]||this["acme"]||defineAcme()); 9704 } 9705 9706 })(); 9707 9708 /* 9709 */ 9710 9711 } 9712 9713 if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 9714 dojo._hasResource["dojo._base.xhr"] = true; 9715 dojo.provide("dojo._base.xhr"); 9716 9717 9718 9719 9720 9721 9722 (function(){ 9723 var _d = dojo, cfg = _d.config; 9724 9725 function setValue(/*Object*/obj, /*String*/name, /*String*/value){ 9726 //summary: 9727 // For the named property in object, set the value. If a value 9728 // already exists and it is a string, convert the value to be an 9729 // array of values. 9730 9731 //Skip it if there is no value 9732 if(value === null){ 9733 return; 9734 } 9735 9736 var val = obj[name]; 9737 if(typeof val == "string"){ // inline'd type check 9738 obj[name] = [val, value]; 9739 }else if(_d.isArray(val)){ 9740 val.push(value); 9741 }else{ 9742 obj[name] = value; 9743 } 9744 } 9745 9746 dojo.fieldToObject = function(/*DOMNode||String*/ inputNode){ 9747 // summary: 9748 // Serialize a form field to a JavaScript object. 9749 // 9750 // description: 9751 // Returns the value encoded in a form field as 9752 // as a string or an array of strings. Disabled form elements 9753 // and unchecked radio and checkboxes are skipped. Multi-select 9754 // elements are returned as an array of string values. 9755 var ret = null; 9756 var item = _d.byId(inputNode); 9757 if(item){ 9758 var _in = item.name; 9759 var type = (item.type||"").toLowerCase(); 9760 if(_in && type && !item.disabled){ 9761 if(type == "radio" || type == "checkbox"){ 9762 if(item.checked){ ret = item.value; } 9763 }else if(item.multiple){ 9764 ret = []; 9765 _d.query("option", item).forEach(function(opt){ 9766 if(opt.selected){ 9767 ret.push(opt.value); 9768 } 9769 }); 9770 }else{ 9771 ret = item.value; 9772 } 9773 } 9774 } 9775 return ret; // Object 9776 }; 9777 9778 dojo.formToObject = function(/*DOMNode||String*/ formNode){ 9779 // summary: 9780 // Serialize a form node to a JavaScript object. 9781 // description: 9782 // Returns the values encoded in an HTML form as 9783 // string properties in an object which it then returns. Disabled form 9784 // elements, buttons, and other non-value form elements are skipped. 9785 // Multi-select elements are returned as an array of string values. 9786 // 9787 // example: 9788 // This form: 9789 // | <form id="test_form"> 9790 // | <input type="text" name="blah" value="blah"> 9791 // | <input type="text" name="no_value" value="blah" disabled> 9792 // | <input type="button" name="no_value2" value="blah"> 9793 // | <select type="select" multiple name="multi" size="5"> 9794 // | <option value="blah">blah</option> 9795 // | <option value="thud" selected>thud</option> 9796 // | <option value="thonk" selected>thonk</option> 9797 // | </select> 9798 // | </form> 9799 // 9800 // yields this object structure as the result of a call to 9801 // formToObject(): 9802 // 9803 // | { 9804 // | blah: "blah", 9805 // | multi: [ 9806 // | "thud", 9807 // | "thonk" 9808 // | ] 9809 // | }; 9810 9811 var ret = {}; 9812 var exclude = "file|submit|image|reset|button|"; 9813 _d.forEach(dojo.byId(formNode).elements, function(item){ 9814 var _in = item.name; 9815 var type = (item.type||"").toLowerCase(); 9816 if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){ 9817 setValue(ret, _in, _d.fieldToObject(item)); 9818 if(type == "image"){ 9819 ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0; 9820 } 9821 } 9822 }); 9823 return ret; // Object 9824 }; 9825 9826 dojo.objectToQuery = function(/*Object*/ map){ 9827 // summary: 9828 // takes a name/value mapping object and returns a string representing 9829 // a URL-encoded version of that object. 9830 // example: 9831 // this object: 9832 // 9833 // | { 9834 // | blah: "blah", 9835 // | multi: [ 9836 // | "thud", 9837 // | "thonk" 9838 // | ] 9839 // | }; 9840 // 9841 // yields the following query string: 9842 // 9843 // | "blah=blah&multi=thud&multi=thonk" 9844 9845 // FIXME: need to implement encodeAscii!! 9846 var enc = encodeURIComponent; 9847 var pairs = []; 9848 var backstop = {}; 9849 for(var name in map){ 9850 var value = map[name]; 9851 if(value != backstop[name]){ 9852 var assign = enc(name) + "="; 9853 if(_d.isArray(value)){ 9854 for(var i=0; i < value.length; i++){ 9855 pairs.push(assign + enc(value[i])); 9856 } 9857 }else{ 9858 pairs.push(assign + enc(value)); 9859 } 9860 } 9861 } 9862 return pairs.join("&"); // String 9863 }; 9864 9865 dojo.formToQuery = function(/*DOMNode||String*/ formNode){ 9866 // summary: 9867 // Returns a URL-encoded string representing the form passed as either a 9868 // node or string ID identifying the form to serialize 9869 return _d.objectToQuery(_d.formToObject(formNode)); // String 9870 }; 9871 9872 dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){ 9873 // summary: 9874 // Create a serialized JSON string from a form node or string 9875 // ID identifying the form to serialize 9876 return _d.toJson(_d.formToObject(formNode), prettyPrint); // String 9877 }; 9878 9879 dojo.queryToObject = function(/*String*/ str){ 9880 // summary: 9881 // Create an object representing a de-serialized query section of a 9882 // URL. Query keys with multiple values are returned in an array. 9883 // 9884 // example: 9885 // This string: 9886 // 9887 // | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&" 9888 // 9889 // results in this object structure: 9890 // 9891 // | { 9892 // | foo: [ "bar", "baz" ], 9893 // | thinger: " spaces =blah", 9894 // | zonk: "blarg" 9895 // | } 9896 // 9897 // Note that spaces and other urlencoded entities are correctly 9898 // handled. 9899 9900 // FIXME: should we grab the URL string if we're not passed one? 9901 var ret = {}; 9902 var qp = str.split("&"); 9903 var dec = decodeURIComponent; 9904 _d.forEach(qp, function(item){ 9905 if(item.length){ 9906 var parts = item.split("="); 9907 var name = dec(parts.shift()); 9908 var val = dec(parts.join("=")); 9909 if(typeof ret[name] == "string"){ // inline'd type check 9910 ret[name] = [ret[name]]; 9911 } 9912 9913 if(_d.isArray(ret[name])){ 9914 ret[name].push(val); 9915 }else{ 9916 ret[name] = val; 9917 } 9918 } 9919 }); 9920 return ret; // Object 9921 }; 9922 9923 // need to block async callbacks from snatching this thread as the result 9924 // of an async callback might call another sync XHR, this hangs khtml forever 9925 // must checked by watchInFlight() 9926 9927 dojo._blockAsync = false; 9928 9929 // MOW: remove dojo._contentHandlers alias in 2.0 9930 var handlers = _d._contentHandlers = dojo.contentHandlers = { 9931 // summary: 9932 // A map of availble XHR transport handle types. Name matches the 9933 // `handleAs` attribute passed to XHR calls. 9934 // 9935 // description: 9936 // A map of availble XHR transport handle types. Name matches the 9937 // `handleAs` attribute passed to XHR calls. Each contentHandler is 9938 // called, passing the xhr object for manipulation. The return value 9939 // from the contentHandler will be passed to the `load` or `handle` 9940 // functions defined in the original xhr call. 9941 // 9942 // example: 9943 // Creating a custom content-handler: 9944 // | dojo.contentHandlers.makeCaps = function(xhr){ 9945 // | return xhr.responseText.toUpperCase(); 9946 // | } 9947 // | // and later: 9948 // | dojo.xhrGet({ 9949 // | url:"foo.txt", 9950 // | handleAs:"makeCaps", 9951 // | load: function(data){ /* data is a toUpper version of foo.txt */ } 9952 // | }); 9953 9954 text: function(xhr){ 9955 // summary: A contentHandler which simply returns the plaintext response data 9956 return xhr.responseText; 9957 }, 9958 json: function(xhr){ 9959 // summary: A contentHandler which returns a JavaScript object created from the response data 9960 return _d.fromJson(xhr.responseText || null); 9961 }, 9962 "json-comment-filtered": function(xhr){ 9963 // summary: A contentHandler which expects comment-filtered JSON. 9964 // description: 9965 // A contentHandler which expects comment-filtered JSON. 9966 // the json-comment-filtered option was implemented to prevent 9967 // "JavaScript Hijacking", but it is less secure than standard JSON. Use 9968 // standard JSON instead. JSON prefixing can be used to subvert hijacking. 9969 // 9970 // Will throw a notice suggesting to use application/json mimetype, as 9971 // json-commenting can introduce security issues. To decrease the chances of hijacking, 9972 // use the standard `json` contentHandler, and prefix your "JSON" with: {}&& 9973 // 9974 // use djConfig.useCommentedJson = true to turn off the notice 9975 if(!dojo.config.useCommentedJson){ 9976 console.warn("Consider using the standard mimetype:application/json." 9977 + " json-commenting can introduce security issues. To" 9978 + " decrease the chances of hijacking, use the standard the 'json' handler and" 9979 + " prefix your json with: {}&&\n" 9980 + "Use djConfig.useCommentedJson=true to turn off this message."); 9981 } 9982 9983 var value = xhr.responseText; 9984 var cStartIdx = value.indexOf("\/*"); 9985 var cEndIdx = value.lastIndexOf("*\/"); 9986 if(cStartIdx == -1 || cEndIdx == -1){ 9987 throw new Error("JSON was not comment filtered"); 9988 } 9989 return _d.fromJson(value.substring(cStartIdx+2, cEndIdx)); 9990 }, 9991 javascript: function(xhr){ 9992 // summary: A contentHandler which evaluates the response data, expecting it to be valid JavaScript 9993 9994 // FIXME: try Moz and IE specific eval variants? 9995 return _d.eval(xhr.responseText); 9996 }, 9997 xml: function(xhr){ 9998 // summary: A contentHandler returning an XML Document parsed from the response data 9999 var result = xhr.responseXML; 10000 if(_d.isIE && (!result || !result.documentElement)){ 10001 //WARNING: this branch used by the xml handling in dojo.io.iframe, 10002 //so be sure to test dojo.io.iframe if making changes below. 10003 var ms = function(n){ return "MSXML" + n + ".DOMDocument"; }; 10004 var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)]; 10005 _d.some(dp, function(p){ 10006 try{ 10007 var dom = new ActiveXObject(p); 10008 dom.async = false; 10009 dom.loadXML(xhr.responseText); 10010 result = dom; 10011 }catch(e){ return false; } 10012 return true; 10013 }); 10014 } 10015 return result; // DOMDocument 10016 }, 10017 "json-comment-optional": function(xhr){ 10018 // summary: A contentHandler which checks the presence of comment-filtered JSON and 10019 // alternates between the `json` and `json-comment-filtered` contentHandlers. 10020 if(xhr.responseText && /^[^{\[]*\/\*/.test(xhr.responseText)){ 10021 return handlers["json-comment-filtered"](xhr); 10022 }else{ 10023 return handlers["json"](xhr); 10024 } 10025 } 10026 }; 10027 10028 /*===== 10029 dojo.__IoArgs = function(){ 10030 // url: String 10031 // URL to server endpoint. 10032 // content: Object? 10033 // Contains properties with string values. These 10034 // properties will be serialized as name1=value2 and 10035 // passed in the request. 10036 // timeout: Integer? 10037 // Milliseconds to wait for the response. If this time 10038 // passes, the then error callbacks are called. 10039 // form: DOMNode? 10040 // DOM node for a form. Used to extract the form values 10041 // and send to the server. 10042 // preventCache: Boolean? 10043 // Default is false. If true, then a 10044 // "dojo.preventCache" parameter is sent in the request 10045 // with a value that changes with each request 10046 // (timestamp). Useful only with GET-type requests. 10047 // handleAs: String? 10048 // Acceptable values depend on the type of IO 10049 // transport (see specific IO calls for more information). 10050 // rawBody: String? 10051 // Sets the raw body for an HTTP request. If this is used, then the content 10052 // property is ignored. This is mostly useful for HTTP methods that have 10053 // a body to their requests, like PUT or POST. This property can be used instead 10054 // of postData and putData for dojo.rawXhrPost and dojo.rawXhrPut respectively. 10055 // ioPublish: Boolean? 10056 // Set this explicitly to false to prevent publishing of topics related to 10057 // IO operations. Otherwise, if djConfig.ioPublish is set to true, topics 10058 // will be published via dojo.publish for different phases of an IO operation. 10059 // See dojo.__IoPublish for a list of topics that are published. 10060 // load: Function? 10061 // This function will be 10062 // called on a successful HTTP response code. 10063 // error: Function? 10064 // This function will 10065 // be called when the request fails due to a network or server error, the url 10066 // is invalid, etc. It will also be called if the load or handle callback throws an 10067 // exception, unless djConfig.debugAtAllCosts is true. This allows deployed applications 10068 // to continue to run even when a logic error happens in the callback, while making 10069 // it easier to troubleshoot while in debug mode. 10070 // handle: Function? 10071 // This function will 10072 // be called at the end of every request, whether or not an error occurs. 10073 this.url = url; 10074 this.content = content; 10075 this.timeout = timeout; 10076 this.form = form; 10077 this.preventCache = preventCache; 10078 this.handleAs = handleAs; 10079 this.ioPublish = ioPublish; 10080 this.load = function(response, ioArgs){ 10081 // ioArgs: dojo.__IoCallbackArgs 10082 // Provides additional information about the request. 10083 // response: Object 10084 // The response in the format as defined with handleAs. 10085 } 10086 this.error = function(response, ioArgs){ 10087 // ioArgs: dojo.__IoCallbackArgs 10088 // Provides additional information about the request. 10089 // response: Object 10090 // The response in the format as defined with handleAs. 10091 } 10092 this.handle = function(loadOrError, response, ioArgs){ 10093 // loadOrError: String 10094 // Provides a string that tells you whether this function 10095 // was called because of success (load) or failure (error). 10096 // response: Object 10097 // The response in the format as defined with handleAs. 10098 // ioArgs: dojo.__IoCallbackArgs 10099 // Provides additional information about the request. 10100 } 10101 } 10102 =====*/ 10103 10104 /*===== 10105 dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){ 10106 // args: Object 10107 // the original object argument to the IO call. 10108 // xhr: XMLHttpRequest 10109 // For XMLHttpRequest calls only, the 10110 // XMLHttpRequest object that was used for the 10111 // request. 10112 // url: String 10113 // The final URL used for the call. Many times it 10114 // will be different than the original args.url 10115 // value. 10116 // query: String 10117 // For non-GET requests, the 10118 // name1=value1&name2=value2 parameters sent up in 10119 // the request. 10120 // handleAs: String 10121 // The final indicator on how the response will be 10122 // handled. 10123 // id: String 10124 // For dojo.io.script calls only, the internal 10125 // script ID used for the request. 10126 // canDelete: Boolean 10127 // For dojo.io.script calls only, indicates 10128 // whether the script tag that represents the 10129 // request can be deleted after callbacks have 10130 // been called. Used internally to know when 10131 // cleanup can happen on JSONP-type requests. 10132 // json: Object 10133 // For dojo.io.script calls only: holds the JSON 10134 // response for JSONP-type requests. Used 10135 // internally to hold on to the JSON responses. 10136 // You should not need to access it directly -- 10137 // the same object should be passed to the success 10138 // callbacks directly. 10139 this.args = args; 10140 this.xhr = xhr; 10141 this.url = url; 10142 this.query = query; 10143 this.handleAs = handleAs; 10144 this.id = id; 10145 this.canDelete = canDelete; 10146 this.json = json; 10147 } 10148 =====*/ 10149 10150 10151 /*===== 10152 dojo.__IoPublish = function(){ 10153 // summary: 10154 // This is a list of IO topics that can be published 10155 // if djConfig.ioPublish is set to true. IO topics can be 10156 // published for any Input/Output, network operation. So, 10157 // dojo.xhr, dojo.io.script and dojo.io.iframe can all 10158 // trigger these topics to be published. 10159 // start: String 10160 // "/dojo/io/start" is sent when there are no outstanding IO 10161 // requests, and a new IO request is started. No arguments 10162 // are passed with this topic. 10163 // send: String 10164 // "/dojo/io/send" is sent whenever a new IO request is started. 10165 // It passes the dojo.Deferred for the request with the topic. 10166 // load: String 10167 // "/dojo/io/load" is sent whenever an IO request has loaded 10168 // successfully. It passes the response and the dojo.Deferred 10169 // for the request with the topic. 10170 // error: String 10171 // "/dojo/io/error" is sent whenever an IO request has errored. 10172 // It passes the error and the dojo.Deferred 10173 // for the request with the topic. 10174 // done: String 10175 // "/dojo/io/done" is sent whenever an IO request has completed, 10176 // either by loading or by erroring. It passes the error and 10177 // the dojo.Deferred for the request with the topic. 10178 // stop: String 10179 // "/dojo/io/stop" is sent when all outstanding IO requests have 10180 // finished. No arguments are passed with this topic. 10181 this.start = "/dojo/io/start"; 10182 this.send = "/dojo/io/send"; 10183 this.load = "/dojo/io/load"; 10184 this.error = "/dojo/io/error"; 10185 this.done = "/dojo/io/done"; 10186 this.stop = "/dojo/io/stop"; 10187 } 10188 =====*/ 10189 10190 10191 dojo._ioSetArgs = function(/*dojo.__IoArgs*/args, 10192 /*Function*/canceller, 10193 /*Function*/okHandler, 10194 /*Function*/errHandler){ 10195 // summary: 10196 // sets up the Deferred and ioArgs property on the Deferred so it 10197 // can be used in an io call. 10198 // args: 10199 // The args object passed into the public io call. Recognized properties on 10200 // the args object are: 10201 // canceller: 10202 // The canceller function used for the Deferred object. The function 10203 // will receive one argument, the Deferred object that is related to the 10204 // canceller. 10205 // okHandler: 10206 // The first OK callback to be registered with Deferred. It has the opportunity 10207 // to transform the OK response. It will receive one argument -- the Deferred 10208 // object returned from this function. 10209 // errHandler: 10210 // The first error callback to be registered with Deferred. It has the opportunity 10211 // to do cleanup on an error. It will receive two arguments: error (the 10212 // Error object) and dfd, the Deferred object returned from this function. 10213 10214 var ioArgs = {args: args, url: args.url}; 10215 10216 //Get values from form if requestd. 10217 var formObject = null; 10218 if(args.form){ 10219 var form = _d.byId(args.form); 10220 //IE requires going through getAttributeNode instead of just getAttribute in some form cases, 10221 //so use it for all. See #2844 10222 var actnNode = form.getAttributeNode("action"); 10223 ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null); 10224 formObject = _d.formToObject(form); 10225 } 10226 10227 // set up the query params 10228 var miArgs = [{}]; 10229 10230 if(formObject){ 10231 // potentially over-ride url-provided params w/ form values 10232 miArgs.push(formObject); 10233 } 10234 if(args.content){ 10235 // stuff in content over-rides what's set by form 10236 miArgs.push(args.content); 10237 } 10238 if(args.preventCache){ 10239 miArgs.push({"dojo.preventCache": new Date().valueOf()}); 10240 } 10241 ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs)); 10242 10243 // .. and the real work of getting the deferred in order, etc. 10244 ioArgs.handleAs = args.handleAs || "text"; 10245 var d = new _d.Deferred(canceller); 10246 d.addCallbacks(okHandler, function(error){ 10247 return errHandler(error, d); 10248 }); 10249 10250 //Support specifying load, error and handle callback functions from the args. 10251 //For those callbacks, the "this" object will be the args object. 10252 //The callbacks will get the deferred result value as the 10253 //first argument and the ioArgs object as the second argument. 10254 var ld = args.load; 10255 if(ld && _d.isFunction(ld)){ 10256 d.addCallback(function(value){ 10257 return ld.call(args, value, ioArgs); 10258 }); 10259 } 10260 var err = args.error; 10261 if(err && _d.isFunction(err)){ 10262 d.addErrback(function(value){ 10263 return err.call(args, value, ioArgs); 10264 }); 10265 } 10266 var handle = args.handle; 10267 if(handle && _d.isFunction(handle)){ 10268 d.addBoth(function(value){ 10269 return handle.call(args, value, ioArgs); 10270 }); 10271 } 10272 10273 //Plug in topic publishing, if dojo.publish is loaded. 10274 if(cfg.ioPublish && _d.publish && ioArgs.args.ioPublish !== false){ 10275 d.addCallbacks( 10276 function(res){ 10277 _d.publish("/dojo/io/load", [d, res]); 10278 return res; 10279 }, 10280 function(res){ 10281 _d.publish("/dojo/io/error", [d, res]); 10282 return res; 10283 } 10284 ); 10285 d.addBoth(function(res){ 10286 _d.publish("/dojo/io/done", [d, res]); 10287 return res; 10288 }); 10289 } 10290 10291 d.ioArgs = ioArgs; 10292 10293 // FIXME: need to wire up the xhr object's abort method to something 10294 // analagous in the Deferred 10295 return d; 10296 }; 10297 10298 var _deferredCancel = function(/*Deferred*/dfd){ 10299 // summary: canceller function for dojo._ioSetArgs call. 10300 10301 dfd.canceled = true; 10302 var xhr = dfd.ioArgs.xhr; 10303 var _at = typeof xhr.abort; 10304 if(_at == "function" || _at == "object" || _at == "unknown"){ 10305 xhr.abort(); 10306 } 10307 var err = dfd.ioArgs.error; 10308 if(!err){ 10309 err = new Error("xhr cancelled"); 10310 err.dojoType="cancel"; 10311 } 10312 return err; 10313 }; 10314 var _deferredOk = function(/*Deferred*/dfd){ 10315 // summary: okHandler function for dojo._ioSetArgs call. 10316 10317 var ret = handlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr); 10318 return ret === undefined ? null : ret; 10319 }; 10320 var _deferError = function(/*Error*/error, /*Deferred*/dfd){ 10321 // summary: errHandler function for dojo._ioSetArgs call. 10322 10323 if(!dfd.ioArgs.args.failOk){ 10324 console.error(error); 10325 } 10326 return error; 10327 }; 10328 10329 // avoid setting a timer per request. It degrades performance on IE 10330 // something fierece if we don't use unified loops. 10331 var _inFlightIntvl = null; 10332 var _inFlight = []; 10333 10334 10335 //Use a separate count for knowing if we are starting/stopping io calls. 10336 //Cannot use _inFlight.length since it can change at a different time than 10337 //when we want to do this kind of test. We only want to decrement the count 10338 //after a callback/errback has finished, since the callback/errback should be 10339 //considered as part of finishing a request. 10340 var _pubCount = 0; 10341 var _checkPubCount = function(dfd){ 10342 if(_pubCount <= 0){ 10343 _pubCount = 0; 10344 if(cfg.ioPublish && _d.publish && (!dfd || dfd && dfd.ioArgs.args.ioPublish !== false)){ 10345 _d.publish("/dojo/io/stop"); 10346 } 10347 } 10348 }; 10349 10350 var _watchInFlight = function(){ 10351 //summary: 10352 // internal method that checks each inflight XMLHttpRequest to see 10353 // if it has completed or if the timeout situation applies. 10354 10355 var now = (new Date()).getTime(); 10356 // make sure sync calls stay thread safe, if this callback is called 10357 // during a sync call and this results in another sync call before the 10358 // first sync call ends the browser hangs 10359 if(!_d._blockAsync){ 10360 // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating 10361 // note: the second clause is an assigment on purpose, lint may complain 10362 for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){ 10363 var dfd = tif.dfd; 10364 var func = function(){ 10365 if(!dfd || dfd.canceled || !tif.validCheck(dfd)){ 10366 _inFlight.splice(i--, 1); 10367 _pubCount -= 1; 10368 }else if(tif.ioCheck(dfd)){ 10369 _inFlight.splice(i--, 1); 10370 tif.resHandle(dfd); 10371 _pubCount -= 1; 10372 }else if(dfd.startTime){ 10373 //did we timeout? 10374 if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){ 10375 _inFlight.splice(i--, 1); 10376 var err = new Error("timeout exceeded"); 10377 err.dojoType = "timeout"; 10378 dfd.errback(err); 10379 //Cancel the request so the io module can do appropriate cleanup. 10380 dfd.cancel(); 10381 _pubCount -= 1; 10382 } 10383 } 10384 }; 10385 if(dojo.config.debugAtAllCosts){ 10386 func.call(this); 10387 }else{ 10388 try{ 10389 func.call(this); 10390 }catch(e){ 10391 dfd.errback(e); 10392 } 10393 } 10394 } 10395 } 10396 10397 _checkPubCount(dfd); 10398 10399 if(!_inFlight.length){ 10400 clearInterval(_inFlightIntvl); 10401 _inFlightIntvl = null; 10402 return; 10403 } 10404 }; 10405 10406 dojo._ioCancelAll = function(){ 10407 //summary: Cancels all pending IO requests, regardless of IO type 10408 //(xhr, script, iframe). 10409 try{ 10410 _d.forEach(_inFlight, function(i){ 10411 try{ 10412 i.dfd.cancel(); 10413 }catch(e){/*squelch*/} 10414 }); 10415 }catch(e){/*squelch*/} 10416 }; 10417 10418 //Automatically call cancel all io calls on unload 10419 //in IE for trac issue #2357. 10420 if(_d.isIE){ 10421 _d.addOnWindowUnload(_d._ioCancelAll); 10422 } 10423 10424 _d._ioNotifyStart = function(/*Deferred*/dfd){ 10425 // summary: 10426 // If dojo.publish is available, publish topics 10427 // about the start of a request queue and/or the 10428 // the beginning of request. 10429 // description: 10430 // Used by IO transports. An IO transport should 10431 // call this method before making the network connection. 10432 if(cfg.ioPublish && _d.publish && dfd.ioArgs.args.ioPublish !== false){ 10433 if(!_pubCount){ 10434 _d.publish("/dojo/io/start"); 10435 } 10436 _pubCount += 1; 10437 _d.publish("/dojo/io/send", [dfd]); 10438 } 10439 }; 10440 10441 _d._ioWatch = function(dfd, validCheck, ioCheck, resHandle){ 10442 // summary: 10443 // Watches the io request represented by dfd to see if it completes. 10444 // dfd: Deferred 10445 // The Deferred object to watch. 10446 // validCheck: Function 10447 // Function used to check if the IO request is still valid. Gets the dfd 10448 // object as its only argument. 10449 // ioCheck: Function 10450 // Function used to check if basic IO call worked. Gets the dfd 10451 // object as its only argument. 10452 // resHandle: Function 10453 // Function used to process response. Gets the dfd 10454 // object as its only argument. 10455 var args = dfd.ioArgs.args; 10456 if(args.timeout){ 10457 dfd.startTime = (new Date()).getTime(); 10458 } 10459 10460 _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle}); 10461 if(!_inFlightIntvl){ 10462 _inFlightIntvl = setInterval(_watchInFlight, 50); 10463 } 10464 // handle sync requests 10465 //A weakness: async calls in flight 10466 //could have their handlers called as part of the 10467 //_watchInFlight call, before the sync's callbacks 10468 // are called. 10469 if(args.sync){ 10470 _watchInFlight(); 10471 } 10472 }; 10473 10474 var _defaultContentType = "application/x-www-form-urlencoded"; 10475 10476 var _validCheck = function(/*Deferred*/dfd){ 10477 return dfd.ioArgs.xhr.readyState; //boolean 10478 }; 10479 var _ioCheck = function(/*Deferred*/dfd){ 10480 return 4 == dfd.ioArgs.xhr.readyState; //boolean 10481 }; 10482 var _resHandle = function(/*Deferred*/dfd){ 10483 var xhr = dfd.ioArgs.xhr; 10484 if(_d._isDocumentOk(xhr)){ 10485 dfd.callback(dfd); 10486 }else{ 10487 var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status); 10488 err.status = xhr.status; 10489 err.responseText = xhr.responseText; 10490 dfd.errback(err); 10491 } 10492 }; 10493 10494 dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){ 10495 //summary: Adds query params discovered by the io deferred construction to the URL. 10496 //Only use this for operations which are fundamentally GET-type operations. 10497 if(ioArgs.query.length){ 10498 ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query; 10499 ioArgs.query = null; 10500 } 10501 }; 10502 10503 /*===== 10504 dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, { 10505 constructor: function(){ 10506 // summary: 10507 // In addition to the properties listed for the dojo._IoArgs type, 10508 // the following properties are allowed for dojo.xhr* methods. 10509 // handleAs: String? 10510 // Acceptable values are: text (default), json, json-comment-optional, 10511 // json-comment-filtered, javascript, xml. See `dojo.contentHandlers` 10512 // sync: Boolean? 10513 // false is default. Indicates whether the request should 10514 // be a synchronous (blocking) request. 10515 // headers: Object? 10516 // Additional HTTP headers to send in the request. 10517 // failOk: Boolean? 10518 // false is default. Indicates whether a request should be 10519 // allowed to fail (and therefore no console error message in 10520 // the event of a failure) 10521 this.handleAs = handleAs; 10522 this.sync = sync; 10523 this.headers = headers; 10524 this.failOk = failOk; 10525 } 10526 }); 10527 =====*/ 10528 10529 dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){ 10530 // summary: 10531 // Sends an HTTP request with the given method. 10532 // description: 10533 // Sends an HTTP request with the given method. 10534 // See also dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts 10535 // for those HTTP methods. There are also methods for "raw" PUT and POST methods 10536 // via dojo.rawXhrPut() and dojo.rawXhrPost() respectively. 10537 // method: 10538 // HTTP method to be used, such as GET, POST, PUT, DELETE. Should be uppercase. 10539 // hasBody: 10540 // If the request has an HTTP body, then pass true for hasBody. 10541 10542 //Make the Deferred object for this xhr request. 10543 var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError); 10544 var ioArgs = dfd.ioArgs; 10545 10546 //Pass the args to _xhrObj, to allow alternate XHR calls based specific calls, like 10547 //the one used for iframe proxies. 10548 var xhr = ioArgs.xhr = _d._xhrObj(ioArgs.args); 10549 //If XHR factory fails, cancel the deferred. 10550 if(!xhr){ 10551 dfd.cancel(); 10552 return dfd; 10553 } 10554 10555 //Allow for specifying the HTTP body completely. 10556 if("postData" in args){ 10557 ioArgs.query = args.postData; 10558 }else if("putData" in args){ 10559 ioArgs.query = args.putData; 10560 }else if("rawBody" in args){ 10561 ioArgs.query = args.rawBody; 10562 }else if((arguments.length > 2 && !hasBody) || "POST|PUT".indexOf(method.toUpperCase()) == -1){ 10563 //Check for hasBody being passed. If no hasBody, 10564 //then only append query string if not a POST or PUT request. 10565 _d._ioAddQueryToUrl(ioArgs); 10566 } 10567 10568 // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open). 10569 // workaround for IE6's apply() "issues" 10570 xhr.open(method, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined); 10571 if(args.headers){ 10572 for(var hdr in args.headers){ 10573 if(hdr.toLowerCase() === "content-type" && !args.contentType){ 10574 args.contentType = args.headers[hdr]; 10575 }else if(args.headers[hdr]){ 10576 //Only add header if it has a value. This allows for instnace, skipping 10577 //insertion of X-Requested-With by specifying empty value. 10578 xhr.setRequestHeader(hdr, args.headers[hdr]); 10579 } 10580 } 10581 } 10582 // FIXME: is this appropriate for all content types? 10583 xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType); 10584 if(!args.headers || !("X-Requested-With" in args.headers)){ 10585 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 10586 } 10587 // FIXME: set other headers here! 10588 _d._ioNotifyStart(dfd); 10589 if(dojo.config.debugAtAllCosts){ 10590 xhr.send(ioArgs.query); 10591 }else{ 10592 try{ 10593 xhr.send(ioArgs.query); 10594 }catch(e){ 10595 ioArgs.error = e; 10596 dfd.cancel(); 10597 } 10598 } 10599 _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle); 10600 xhr = null; 10601 return dfd; // dojo.Deferred 10602 }; 10603 10604 dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){ 10605 // summary: 10606 // Sends an HTTP GET request to the server. 10607 return _d.xhr("GET", args); // dojo.Deferred 10608 }; 10609 10610 dojo.rawXhrPost = dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){ 10611 // summary: 10612 // Sends an HTTP POST request to the server. In addtion to the properties 10613 // listed for the dojo.__XhrArgs type, the following property is allowed: 10614 // postData: 10615 // String. Send raw data in the body of the POST request. 10616 return _d.xhr("POST", args, true); // dojo.Deferred 10617 }; 10618 10619 dojo.rawXhrPut = dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){ 10620 // summary: 10621 // Sends an HTTP PUT request to the server. In addtion to the properties 10622 // listed for the dojo.__XhrArgs type, the following property is allowed: 10623 // putData: 10624 // String. Send raw data in the body of the PUT request. 10625 return _d.xhr("PUT", args, true); // dojo.Deferred 10626 }; 10627 10628 dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){ 10629 // summary: 10630 // Sends an HTTP DELETE request to the server. 10631 return _d.xhr("DELETE", args); //dojo.Deferred 10632 }; 10633 10634 /* 10635 dojo.wrapForm = function(formNode){ 10636 //summary: 10637 // A replacement for FormBind, but not implemented yet. 10638 10639 // FIXME: need to think harder about what extensions to this we might 10640 // want. What should we allow folks to do w/ this? What events to 10641 // set/send? 10642 throw new Error("dojo.wrapForm not yet implemented"); 10643 } 10644 */ 10645 })(); 10646 10647 } 10648 10649 if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 10650 dojo._hasResource["dojo._base.fx"] = true; 10651 dojo.provide("dojo._base.fx"); 10652 10653 10654 10655 10656 10657 10658 /* 10659 Animation loosely package based on Dan Pupius' work, contributed under CLA: 10660 http://pupius.co.uk/js/Toolkit.Drawing.js 10661 */ 10662 (function(){ 10663 var d = dojo; 10664 var _mixin = d._mixin; 10665 10666 dojo._Line = function(/*int*/ start, /*int*/ end){ 10667 // summary: 10668 // dojo._Line is the object used to generate values from a start value 10669 // to an end value 10670 // start: int 10671 // Beginning value for range 10672 // end: int 10673 // Ending value for range 10674 this.start = start; 10675 this.end = end; 10676 }; 10677 10678 dojo._Line.prototype.getValue = function(/*float*/ n){ 10679 // summary: Returns the point on the line 10680 // n: a floating point number greater than 0 and less than 1 10681 return ((this.end - this.start) * n) + this.start; // Decimal 10682 }; 10683 10684 dojo.Animation = function(args){ 10685 // summary: 10686 // A generic animation class that fires callbacks into its handlers 10687 // object at various states. 10688 // description: 10689 // A generic animation class that fires callbacks into its handlers 10690 // object at various states. Nearly all dojo animation functions 10691 // return an instance of this method, usually without calling the 10692 // .play() method beforehand. Therefore, you will likely need to 10693 // call .play() on instances of `dojo.Animation` when one is 10694 // returned. 10695 // args: Object 10696 // The 'magic argument', mixing all the properties into this 10697 // animation instance. 10698 10699 _mixin(this, args); 10700 if(d.isArray(this.curve)){ 10701 this.curve = new d._Line(this.curve[0], this.curve[1]); 10702 } 10703 10704 }; 10705 10706 // Alias to drop come 2.0: 10707 d._Animation = d.Animation; 10708 10709 d.extend(dojo.Animation, { 10710 // duration: Integer 10711 // The time in milliseonds the animation will take to run 10712 duration: 350, 10713 10714 /*===== 10715 // curve: dojo._Line|Array 10716 // A two element array of start and end values, or a `dojo._Line` instance to be 10717 // used in the Animation. 10718 curve: null, 10719 10720 // easing: Function? 10721 // A Function to adjust the acceleration (or deceleration) of the progress 10722 // across a dojo._Line 10723 easing: null, 10724 =====*/ 10725 10726 // repeat: Integer? 10727 // The number of times to loop the animation 10728 repeat: 0, 10729 10730 // rate: Integer? 10731 // the time in milliseconds to wait before advancing to next frame 10732 // (used as a fps timer: 1000/rate = fps) 10733 rate: 20 /* 50 fps */, 10734 10735 /*===== 10736 // delay: Integer? 10737 // The time in milliseconds to wait before starting animation after it 10738 // has been .play()'ed 10739 delay: null, 10740 10741 // beforeBegin: Event? 10742 // Synthetic event fired before a dojo.Animation begins playing (synchronous) 10743 beforeBegin: null, 10744 10745 // onBegin: Event? 10746 // Synthetic event fired as a dojo.Animation begins playing (useful?) 10747 onBegin: null, 10748 10749 // onAnimate: Event? 10750 // Synthetic event fired at each interval of a `dojo.Animation` 10751 onAnimate: null, 10752 10753 // onEnd: Event? 10754 // Synthetic event fired after the final frame of a `dojo.Animation` 10755 onEnd: null, 10756 10757 // onPlay: Event? 10758 // Synthetic event fired any time a `dojo.Animation` is play()'ed 10759 onPlay: null, 10760 10761 // onPause: Event? 10762 // Synthetic event fired when a `dojo.Animation` is paused 10763 onPause: null, 10764 10765 // onStop: Event 10766 // Synthetic event fires when a `dojo.Animation` is stopped 10767 onStop: null, 10768 10769 =====*/ 10770 10771 _percent: 0, 10772 _startRepeatCount: 0, 10773 10774 _getStep: function(){ 10775 var _p = this._percent, 10776 _e = this.easing 10777 ; 10778 return _e ? _e(_p) : _p; 10779 }, 10780 _fire: function(/*Event*/ evt, /*Array?*/ args){ 10781 // summary: 10782 // Convenience function. Fire event "evt" and pass it the 10783 // arguments specified in "args". 10784 // description: 10785 // Convenience function. Fire event "evt" and pass it the 10786 // arguments specified in "args". 10787 // Fires the callback in the scope of the `dojo.Animation` 10788 // instance. 10789 // evt: 10790 // The event to fire. 10791 // args: 10792 // The arguments to pass to the event. 10793 var a = args||[]; 10794 if(this[evt]){ 10795 if(d.config.debugAtAllCosts){ 10796 this[evt].apply(this, a); 10797 }else{ 10798 try{ 10799 this[evt].apply(this, a); 10800 }catch(e){ 10801 // squelch and log because we shouldn't allow exceptions in 10802 // synthetic event handlers to cause the internal timer to run 10803 // amuck, potentially pegging the CPU. I'm not a fan of this 10804 // squelch, but hopefully logging will make it clear what's 10805 // going on 10806 console.error("exception in animation handler for:", evt); 10807 console.error(e); 10808 } 10809 } 10810 } 10811 return this; // dojo.Animation 10812 }, 10813 10814 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ 10815 // summary: 10816 // Start the animation. 10817 // delay: 10818 // How many milliseconds to delay before starting. 10819 // gotoStart: 10820 // If true, starts the animation from the beginning; otherwise, 10821 // starts it from its current position. 10822 // returns: dojo.Animation 10823 // The instance to allow chaining. 10824 10825 var _t = this; 10826 if(_t._delayTimer){ _t._clearTimer(); } 10827 if(gotoStart){ 10828 _t._stopTimer(); 10829 _t._active = _t._paused = false; 10830 _t._percent = 0; 10831 }else if(_t._active && !_t._paused){ 10832 return _t; 10833 } 10834 10835 _t._fire("beforeBegin", [_t.node]); 10836 10837 var de = delay || _t.delay, 10838 _p = dojo.hitch(_t, "_play", gotoStart); 10839 10840 if(de > 0){ 10841 _t._delayTimer = setTimeout(_p, de); 10842 return _t; 10843 } 10844 _p(); 10845 return _t; 10846 }, 10847 10848 _play: function(gotoStart){ 10849 var _t = this; 10850 if(_t._delayTimer){ _t._clearTimer(); } 10851 _t._startTime = new Date().valueOf(); 10852 if(_t._paused){ 10853 _t._startTime -= _t.duration * _t._percent; 10854 } 10855 10856 _t._active = true; 10857 _t._paused = false; 10858 var value = _t.curve.getValue(_t._getStep()); 10859 if(!_t._percent){ 10860 if(!_t._startRepeatCount){ 10861 _t._startRepeatCount = _t.repeat; 10862 } 10863 _t._fire("onBegin", [value]); 10864 } 10865 10866 _t._fire("onPlay", [value]); 10867 10868 _t._cycle(); 10869 return _t; // dojo.Animation 10870 }, 10871 10872 pause: function(){ 10873 // summary: Pauses a running animation. 10874 var _t = this; 10875 if(_t._delayTimer){ _t._clearTimer(); } 10876 _t._stopTimer(); 10877 if(!_t._active){ return _t; /*dojo.Animation*/ } 10878 _t._paused = true; 10879 _t._fire("onPause", [_t.curve.getValue(_t._getStep())]); 10880 return _t; // dojo.Animation 10881 }, 10882 10883 gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){ 10884 // summary: 10885 // Sets the progress of the animation. 10886 // percent: 10887 // A percentage in decimal notation (between and including 0.0 and 1.0). 10888 // andPlay: 10889 // If true, play the animation after setting the progress. 10890 var _t = this; 10891 _t._stopTimer(); 10892 _t._active = _t._paused = true; 10893 _t._percent = percent; 10894 if(andPlay){ _t.play(); } 10895 return _t; // dojo.Animation 10896 }, 10897 10898 stop: function(/*boolean?*/ gotoEnd){ 10899 // summary: Stops a running animation. 10900 // gotoEnd: If true, the animation will end. 10901 var _t = this; 10902 if(_t._delayTimer){ _t._clearTimer(); } 10903 if(!_t._timer){ return _t; /* dojo.Animation */ } 10904 _t._stopTimer(); 10905 if(gotoEnd){ 10906 _t._percent = 1; 10907 } 10908 _t._fire("onStop", [_t.curve.getValue(_t._getStep())]); 10909 _t._active = _t._paused = false; 10910 return _t; // dojo.Animation 10911 }, 10912 10913 status: function(){ 10914 // summary: 10915 // Returns a string token representation of the status of 10916 // the animation, one of: "paused", "playing", "stopped" 10917 if(this._active){ 10918 return this._paused ? "paused" : "playing"; // String 10919 } 10920 return "stopped"; // String 10921 }, 10922 10923 _cycle: function(){ 10924 var _t = this; 10925 if(_t._active){ 10926 var curr = new Date().valueOf(); 10927 var step = (curr - _t._startTime) / (_t.duration); 10928 10929 if(step >= 1){ 10930 step = 1; 10931 } 10932 _t._percent = step; 10933 10934 // Perform easing 10935 if(_t.easing){ 10936 step = _t.easing(step); 10937 } 10938 10939 _t._fire("onAnimate", [_t.curve.getValue(step)]); 10940 10941 if(_t._percent < 1){ 10942 _t._startTimer(); 10943 }else{ 10944 _t._active = false; 10945 10946 if(_t.repeat > 0){ 10947 _t.repeat--; 10948 _t.play(null, true); 10949 }else if(_t.repeat == -1){ 10950 _t.play(null, true); 10951 }else{ 10952 if(_t._startRepeatCount){ 10953 _t.repeat = _t._startRepeatCount; 10954 _t._startRepeatCount = 0; 10955 } 10956 } 10957 _t._percent = 0; 10958 _t._fire("onEnd", [_t.node]); 10959 !_t.repeat && _t._stopTimer(); 10960 } 10961 } 10962 return _t; // dojo.Animation 10963 }, 10964 10965 _clearTimer: function(){ 10966 // summary: Clear the play delay timer 10967 clearTimeout(this._delayTimer); 10968 delete this._delayTimer; 10969 } 10970 10971 }); 10972 10973 // the local timer, stubbed into all Animation instances 10974 var ctr = 0, 10975 timer = null, 10976 runner = { 10977 run: function(){} 10978 }; 10979 10980 d.extend(d.Animation, { 10981 10982 _startTimer: function(){ 10983 if(!this._timer){ 10984 this._timer = d.connect(runner, "run", this, "_cycle"); 10985 ctr++; 10986 } 10987 if(!timer){ 10988 timer = setInterval(d.hitch(runner, "run"), this.rate); 10989 } 10990 }, 10991 10992 _stopTimer: function(){ 10993 if(this._timer){ 10994 d.disconnect(this._timer); 10995 this._timer = null; 10996 ctr--; 10997 } 10998 if(ctr <= 0){ 10999 clearInterval(timer); 11000 timer = null; 11001 ctr = 0; 11002 } 11003 } 11004 11005 }); 11006 11007 var _makeFadeable = 11008 d.isIE ? function(node){ 11009 // only set the zoom if the "tickle" value would be the same as the 11010 // default 11011 var ns = node.style; 11012 // don't set the width to auto if it didn't already cascade that way. 11013 // We don't want to f anyones designs 11014 if(!ns.width.length && d.style(node, "width") == "auto"){ 11015 ns.width = "auto"; 11016 } 11017 } : 11018 function(){}; 11019 11020 dojo._fade = function(/*Object*/ args){ 11021 // summary: 11022 // Returns an animation that will fade the node defined by 11023 // args.node from the start to end values passed (args.start 11024 // args.end) (end is mandatory, start is optional) 11025 11026 args.node = d.byId(args.node); 11027 var fArgs = _mixin({ properties: {} }, args), 11028 props = (fArgs.properties.opacity = {}); 11029 11030 props.start = !("start" in fArgs) ? 11031 function(){ 11032 return +d.style(fArgs.node, "opacity")||0; 11033 } : fArgs.start; 11034 props.end = fArgs.end; 11035 11036 var anim = d.animateProperty(fArgs); 11037 d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node)); 11038 11039 return anim; // dojo.Animation 11040 }; 11041 11042 /*===== 11043 dojo.__FadeArgs = function(node, duration, easing){ 11044 // node: DOMNode|String 11045 // The node referenced in the animation 11046 // duration: Integer? 11047 // Duration of the animation in milliseconds. 11048 // easing: Function? 11049 // An easing function. 11050 this.node = node; 11051 this.duration = duration; 11052 this.easing = easing; 11053 } 11054 =====*/ 11055 11056 dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){ 11057 // summary: 11058 // Returns an animation that will fade node defined in 'args' from 11059 // its current opacity to fully opaque. 11060 return d._fade(_mixin({ end: 1 }, args)); // dojo.Animation 11061 }; 11062 11063 dojo.fadeOut = function(/*dojo.__FadeArgs*/ args){ 11064 // summary: 11065 // Returns an animation that will fade node defined in 'args' 11066 // from its current opacity to fully transparent. 11067 return d._fade(_mixin({ end: 0 }, args)); // dojo.Animation 11068 }; 11069 11070 dojo._defaultEasing = function(/*Decimal?*/ n){ 11071 // summary: The default easing function for dojo.Animation(s) 11072 return 0.5 + ((Math.sin((n + 1.5) * Math.PI)) / 2); 11073 }; 11074 11075 var PropLine = function(properties){ 11076 // PropLine is an internal class which is used to model the values of 11077 // an a group of CSS properties across an animation lifecycle. In 11078 // particular, the "getValue" function handles getting interpolated 11079 // values between start and end for a particular CSS value. 11080 this._properties = properties; 11081 for(var p in properties){ 11082 var prop = properties[p]; 11083 if(prop.start instanceof d.Color){ 11084 // create a reusable temp color object to keep intermediate results 11085 prop.tempColor = new d.Color(); 11086 } 11087 } 11088 }; 11089 11090 PropLine.prototype.getValue = function(r){ 11091 var ret = {}; 11092 for(var p in this._properties){ 11093 var prop = this._properties[p], 11094 start = prop.start; 11095 if(start instanceof d.Color){ 11096 ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss(); 11097 }else if(!d.isArray(start)){ 11098 ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units || "px" : 0); 11099 } 11100 } 11101 return ret; 11102 }; 11103 11104 /*===== 11105 dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], { 11106 // Properties: Object? 11107 // A hash map of style properties to Objects describing the transition, 11108 // such as the properties of dojo._Line with an additional 'units' property 11109 properties: {} 11110 11111 //TODOC: add event callbacks 11112 }); 11113 =====*/ 11114 11115 dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){ 11116 // summary: 11117 // Returns an animation that will transition the properties of 11118 // node defined in `args` depending how they are defined in 11119 // `args.properties` 11120 // 11121 // description: 11122 // `dojo.animateProperty` is the foundation of most `dojo.fx` 11123 // animations. It takes an object of "properties" corresponding to 11124 // style properties, and animates them in parallel over a set 11125 // duration. 11126 // 11127 // example: 11128 // A simple animation that changes the width of the specified node. 11129 // | dojo.animateProperty({ 11130 // | node: "nodeId", 11131 // | properties: { width: 400 }, 11132 // | }).play(); 11133 // Dojo figures out the start value for the width and converts the 11134 // integer specified for the width to the more expressive but 11135 // verbose form `{ width: { end: '400', units: 'px' } }` which you 11136 // can also specify directly. Defaults to 'px' if ommitted. 11137 // 11138 // example: 11139 // Animate width, height, and padding over 2 seconds... the 11140 // pedantic way: 11141 // | dojo.animateProperty({ node: node, duration:2000, 11142 // | properties: { 11143 // | width: { start: '200', end: '400', units:"px" }, 11144 // | height: { start:'200', end: '400', units:"px" }, 11145 // | paddingTop: { start:'5', end:'50', units:"px" } 11146 // | } 11147 // | }).play(); 11148 // Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties 11149 // are written using "mixed case", as the hyphen is illegal as an object key. 11150 // 11151 // example: 11152 // Plug in a different easing function and register a callback for 11153 // when the animation ends. Easing functions accept values between 11154 // zero and one and return a value on that basis. In this case, an 11155 // exponential-in curve. 11156 // | dojo.animateProperty({ 11157 // | node: "nodeId", 11158 // | // dojo figures out the start value 11159 // | properties: { width: { end: 400 } }, 11160 // | easing: function(n){ 11161 // | return (n==0) ? 0 : Math.pow(2, 10 * (n - 1)); 11162 // | }, 11163 // | onEnd: function(node){ 11164 // | // called when the animation finishes. The animation 11165 // | // target is passed to this function 11166 // | } 11167 // | }).play(500); // delay playing half a second 11168 // 11169 // example: 11170 // Like all `dojo.Animation`s, animateProperty returns a handle to the 11171 // Animation instance, which fires the events common to Dojo FX. Use `dojo.connect` 11172 // to access these events outside of the Animation definiton: 11173 // | var anim = dojo.animateProperty({ 11174 // | node:"someId", 11175 // | properties:{ 11176 // | width:400, height:500 11177 // | } 11178 // | }); 11179 // | dojo.connect(anim,"onEnd", function(){ 11180 // | console.log("animation ended"); 11181 // | }); 11182 // | // play the animation now: 11183 // | anim.play(); 11184 // 11185 // example: 11186 // Each property can be a function whose return value is substituted along. 11187 // Additionally, each measurement (eg: start, end) can be a function. The node 11188 // reference is passed direcly to callbacks. 11189 // | dojo.animateProperty({ 11190 // | node:"mine", 11191 // | properties:{ 11192 // | height:function(node){ 11193 // | // shrink this node by 50% 11194 // | return dojo.position(node).h / 2 11195 // | }, 11196 // | width:{ 11197 // | start:function(node){ return 100; }, 11198 // | end:function(node){ return 200; } 11199 // | } 11200 // | } 11201 // | }).play(); 11202 // 11203 11204 var n = args.node = d.byId(args.node); 11205 if(!args.easing){ args.easing = d._defaultEasing; } 11206 11207 var anim = new d.Animation(args); 11208 d.connect(anim, "beforeBegin", anim, function(){ 11209 var pm = {}; 11210 for(var p in this.properties){ 11211 // Make shallow copy of properties into pm because we overwrite 11212 // some values below. In particular if start/end are functions 11213 // we don't want to overwrite them or the functions won't be 11214 // called if the animation is reused. 11215 if(p == "width" || p == "height"){ 11216 this.node.display = "block"; 11217 } 11218 var prop = this.properties[p]; 11219 if(d.isFunction(prop)){ 11220 prop = prop(n); 11221 } 11222 prop = pm[p] = _mixin({}, (d.isObject(prop) ? prop: { end: prop })); 11223 11224 if(d.isFunction(prop.start)){ 11225 prop.start = prop.start(n); 11226 } 11227 if(d.isFunction(prop.end)){ 11228 prop.end = prop.end(n); 11229 } 11230 var isColor = (p.toLowerCase().indexOf("color") >= 0); 11231 function getStyle(node, p){ 11232 // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable: 11233 var v = { height: node.offsetHeight, width: node.offsetWidth }[p]; 11234 if(v !== undefined){ return v; } 11235 v = d.style(node, p); 11236 return (p == "opacity") ? +v : (isColor ? v : parseFloat(v)); 11237 } 11238 if(!("end" in prop)){ 11239 prop.end = getStyle(n, p); 11240 }else if(!("start" in prop)){ 11241 prop.start = getStyle(n, p); 11242 } 11243 11244 if(isColor){ 11245 prop.start = new d.Color(prop.start); 11246 prop.end = new d.Color(prop.end); 11247 }else{ 11248 prop.start = (p == "opacity") ? +prop.start : parseFloat(prop.start); 11249 } 11250 } 11251 this.curve = new PropLine(pm); 11252 }); 11253 d.connect(anim, "onAnimate", d.hitch(d, "style", anim.node)); 11254 return anim; // dojo.Animation 11255 }; 11256 11257 dojo.anim = function( /*DOMNode|String*/ node, 11258 /*Object*/ properties, 11259 /*Integer?*/ duration, 11260 /*Function?*/ easing, 11261 /*Function?*/ onEnd, 11262 /*Integer?*/ delay){ 11263 // summary: 11264 // A simpler interface to `dojo.animateProperty()`, also returns 11265 // an instance of `dojo.Animation` but begins the animation 11266 // immediately, unlike nearly every other Dojo animation API. 11267 // description: 11268 // `dojo.anim` is a simpler (but somewhat less powerful) version 11269 // of `dojo.animateProperty`. It uses defaults for many basic properties 11270 // and allows for positional parameters to be used in place of the 11271 // packed "property bag" which is used for other Dojo animation 11272 // methods. 11273 // 11274 // The `dojo.Animation` object returned from `dojo.anim` will be 11275 // already playing when it is returned from this function, so 11276 // calling play() on it again is (usually) a no-op. 11277 // node: 11278 // a DOM node or the id of a node to animate CSS properties on 11279 // duration: 11280 // The number of milliseconds over which the animation 11281 // should run. Defaults to the global animation default duration 11282 // (350ms). 11283 // easing: 11284 // An easing function over which to calculate acceleration 11285 // and deceleration of the animation through its duration. 11286 // A default easing algorithm is provided, but you may 11287 // plug in any you wish. A large selection of easing algorithms 11288 // are available in `dojo.fx.easing`. 11289 // onEnd: 11290 // A function to be called when the animation finishes 11291 // running. 11292 // delay: 11293 // The number of milliseconds to delay beginning the 11294 // animation by. The default is 0. 11295 // example: 11296 // Fade out a node 11297 // | dojo.anim("id", { opacity: 0 }); 11298 // example: 11299 // Fade out a node over a full second 11300 // | dojo.anim("id", { opacity: 0 }, 1000); 11301 return d.animateProperty({ // dojo.Animation 11302 node: node, 11303 duration: duration || d.Animation.prototype.duration, 11304 properties: properties, 11305 easing: easing, 11306 onEnd: onEnd 11307 }).play(delay || 0); 11308 }; 11309 })(); 11310 11311 } 11312 11313 if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 11314 dojo._hasResource["dojo._base.browser"] = true; 11315 dojo.provide("dojo._base.browser"); 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 //Need this to be the last code segment in base, so do not place any 11326 //dojo/requireIf calls in this file/ Otherwise, due to how the build system 11327 //puts all requireIf dependencies after the current file, the require calls 11328 //could be called before all of base is defined/ 11329 dojo.forEach(dojo.config.require, function(i){ 11330 dojo["require"](i); 11331 }); 11332 11333 } 11334 11335 if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 11336 dojo._hasResource["dojo._base"] = true; 11337 dojo.provide("dojo._base"); 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 } 11350 11351 //INSERT dojo.i18n._preloadLocalizations HERE 11352 11353 //Check if document already complete, and if so, just trigger page load 11354 //listeners. NOTE: does not work with Firefox before 3.6. To support 11355 //those browsers, set djConfig.afterOnLoad = true when you know Dojo is added 11356 //after page load. Using a timeout so the rest of this 11357 //script gets evaluated properly. This work needs to happen after the 11358 //dojo.config.require work done in dojo._base. 11359 if(dojo.isBrowser && (document.readyState === "complete" || dojo.config.afterOnLoad)){ 11360 window.setTimeout(dojo._loadInit, 100); 11361 } 11362 })(); 11363 11364