| /* |
| Copyright (c) 2004-2007, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing |
| */ |
| |
| /* |
| This is a compiled version of Dojo, built for deployment and not for |
| development. To get an editable version, please visit: |
| |
| http://dojotoolkit.org |
| |
| for documentation and information on getting the source. |
| */ |
| |
| if(typeof dojo == "undefined"){ |
| |
| /*===== |
| djConfig = { |
| // summary: |
| // Application code can set the global 'djConfig' prior to loading |
| // the library to override certain global settings for how dojo works. |
| // description: The variables that can be set are as follows: |
| // - isDebug: false |
| // - libraryScriptUri: "" |
| // - locale: undefined |
| // - extraLocale: undefined |
| // - preventBackButtonFix: true |
| // note: |
| // 'djConfig' does not exist under 'dojo.*' so that it can be set before the |
| // 'dojo' variable exists. |
| // note: |
| // Setting any of these variables *after* the library has loaded does |
| // nothing at all. |
| } |
| =====*/ |
| |
| (function(){ |
| // make sure djConfig is defined |
| if(typeof this["djConfig"] == "undefined"){ |
| this.djConfig = {}; |
| } |
| |
| // firebug stubs |
| if((!this["console"])||(!console["firebug"])){ |
| this.console = {}; |
| } |
| |
| var cn = [ |
| "assert", "count", "debug", "dir", "dirxml", "error", "group", |
| "groupEnd", "info", "log", "profile", "profileEnd", "time", |
| "timeEnd", "trace", "warn" |
| ]; |
| var i=0, tn; |
| while((tn=cn[i++])){ |
| if(!console[tn]){ |
| console[tn] = function(){}; |
| } |
| } |
| |
| //TODOC: HOW TO DOC THIS? |
| // dojo is the root variable of (almost all) our public symbols -- make sure it is defined. |
| if(typeof this["dojo"] == "undefined"){ |
| this.dojo = {}; |
| } |
| |
| var d = dojo; |
| |
| /*===== |
| dojo.global = { |
| // summary: |
| // Alias for the global scope |
| // (e.g. the window object in a browser). |
| // description: |
| // Refer to 'dojo.global' rather than referring to window to ensure your |
| // code runs correctly in contexts other than web browsers (e.g. Rhino on a server). |
| } |
| =====*/ |
| dojo.global = this; |
| |
| var _config =/*===== djConfig = =====*/{ |
| isDebug: false, |
| libraryScriptUri: "", |
| preventBackButtonFix: true, |
| delayMozLoadingFix: false |
| }; |
| |
| for(var option in _config){ |
| if(typeof djConfig[option] == "undefined"){ |
| djConfig[option] = _config[option]; |
| } |
| } |
| |
| var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"]; |
| var t; |
| while(t=_platforms.shift()){ |
| d["is"+t] = false; |
| } |
| |
| /*===== |
| // Override locale setting, if specified |
| dojo.locale = { |
| // summary: the locale as defined by Dojo (read-only) |
| }; |
| =====*/ |
| dojo.locale = djConfig.locale; |
| |
| var rev = "$Rev: 11742 $".match(/\d+/); |
| |
| dojo.version = { |
| // summary: version number of this instance of dojo. |
| major: 0, minor: 0, patch: 0, flag: "dev", |
| revision: rev ? Number(rev[0]) : 999999, |
| toString: function(){ |
| with(d.version){ |
| return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String |
| } |
| } |
| } |
| |
| // Register with the OpenAjax hub |
| if(typeof OpenAjax != "undefined"){ |
| OpenAjax.hub.registerLibrary("dojo", "http://dojotoolkit.org", d.version.toString()); |
| } |
| |
| dojo._mixin = function(/*Object*/ obj, /*Object*/ props){ |
| // summary: |
| // Adds all properties and methods of props to obj. This addition is |
| // "prototype extension safe", so that instances of objects will not |
| // pass along prototype defaults. |
| var tobj = {}; |
| for(var x in props){ |
| // the "tobj" condition avoid copying properties in "props" |
| // inherited from Object.prototype. For example, if obj has a custom |
| // toString() method, don't overwrite it with the toString() method |
| // that props inherited from Object.prototype |
| if(tobj[x] === undefined || tobj[x] != props[x]){ |
| obj[x] = props[x]; |
| } |
| } |
| // IE doesn't recognize custom toStrings in for..in |
| if(d["isIE"] && props){ |
| var p = props.toString; |
| if(typeof p == "function" && p != obj.toString && p != tobj.toString && |
| p != "\nfunction toString() {\n [native code]\n}\n"){ |
| obj.toString = props.toString; |
| } |
| } |
| return obj; // Object |
| } |
| |
| dojo.mixin = function(/*Object*/obj, /*Object...*/props){ |
| // summary: Adds all properties and methods of props to obj. |
| for(var i=1, l=arguments.length; i<l; i++){ |
| d._mixin(obj, arguments[i]); |
| } |
| return obj; // Object |
| } |
| |
| dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){ |
| var obj=context||d.global; |
| for(var i=0, p; obj&&(p=parts[i]); i++){ |
| obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined)); |
| } |
| return obj; // mixed |
| } |
| |
| dojo.setObject = function(/*String*/name, /*mixed*/value, /*Object*/context){ |
| // summary: |
| // Set a property from a dot-separated string, such as "A.B.C" |
| // description: |
| // Useful for longer api chains where you have to test each object in |
| // the chain, or when you have an object reference in string format. |
| // Objects are created as needed along 'path'. |
| // name: |
| // Path to a property, in the form "A.B.C". |
| // context: |
| // Optional. Object to use as root of path. Defaults to |
| // 'dojo.global'. Null may be passed. |
| var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context); |
| return (obj && p ? (obj[p]=value) : undefined); // mixed |
| } |
| |
| dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){ |
| // summary: |
| // Get a property from a dot-separated string, such as "A.B.C" |
| // description: |
| // Useful for longer api chains where you have to test each object in |
| // the chain, or when you have an object reference in string format. |
| // name: |
| // Path to an property, in the form "A.B.C". |
| // context: |
| // Optional. Object to use as root of path. Defaults to |
| // 'dojo.global'. Null may be passed. |
| // create: |
| // Optional. If true, Objects will be created at any point along the |
| // 'path' that is undefined. |
| return d._getProp(name.split("."), create, context); // mixed |
| } |
| |
| dojo.exists = function(/*String*/name, /*Object?*/obj){ |
| // summary: |
| // determine if an object supports a given method |
| // description: |
| // useful for longer api chains where you have to test each object in |
| // the chain |
| // name: |
| // Path to an object, in the form "A.B.C". |
| // obj: |
| // Object to use as root of path. Defaults to |
| // 'dojo.global'. Null may be passed. |
| return !!d.getObject(name, false, obj); // Boolean |
| } |
| |
| |
| dojo["eval"] = function(/*String*/ scriptFragment){ |
| // summary: |
| // Perform an evaluation in the global scope. Use this rather than |
| // calling 'eval()' directly. |
| // description: |
| // Placed in a separate function to minimize size of trapped |
| // evaluation context. |
| // note: |
| // - JSC eval() takes an optional second argument which can be 'unsafe'. |
| // - Mozilla/SpiderMonkey eval() takes an optional second argument which is the |
| // scope object for new symbols. |
| |
| // FIXME: investigate Joseph Smarr's technique for IE: |
| // http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/ |
| // see also: |
| // http://trac.dojotoolkit.org/ticket/744 |
| return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // mixed |
| } |
| |
| /*===== |
| dojo.deprecated = function(behaviour, extra, removal){ |
| // summary: |
| // Log a debug message to indicate that a behavior has been |
| // deprecated. |
| // behaviour: String |
| // The API or behavior being deprecated. Usually in the form |
| // of "myApp.someFunction()". |
| // extra: String? |
| // Text to append to the message. Often provides advice on a |
| // new function or facility to achieve the same goal during |
| // the deprecation period. |
| // removal: String? |
| // Text to indicate when in the future the behavior will be |
| // removed. Usually a version number. |
| // example: |
| // | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0"); |
| } |
| |
| dojo.experimental = function(moduleName, extra){ |
| // summary: Marks code as experimental. |
| // description: |
| // This can be used to mark a function, file, or module as |
| // experimental. Experimental code is not ready to be used, and the |
| // APIs are subject to change without notice. Experimental code may be |
| // completed deleted without going through the normal deprecation |
| // process. |
| // moduleName: String |
| // The name of a module, or the name of a module file or a specific |
| // function |
| // extra: String? |
| // some additional message for the user |
| // example: |
| // | dojo.experimental("dojo.data.Result"); |
| // example: |
| // | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA"); |
| } |
| =====*/ |
| |
| //Real functions declared in dojo._firebug.firebug. |
| d.deprecated = d.experimental = function(){}; |
| |
| })(); |
| // vim:ai:ts=4:noet |
| |
| /* |
| * loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains |
| * all of the package loading methods. |
| */ |
| |
| (function(){ |
| var d = dojo; |
| |
| d.mixin(d, { |
| _loadedModules: {}, |
| _inFlightCount: 0, |
| _hasResource: {}, |
| |
| // FIXME: it should be possible to pull module prefixes in from djConfig |
| _modulePrefixes: { |
| dojo: {name: "dojo", value: "."}, |
| doh: {name: "doh", value: "../util/doh"}, |
| tests: {name: "tests", value: "tests"} |
| }, |
| |
| _moduleHasPrefix: function(/*String*/module){ |
| // summary: checks to see if module has been established |
| var mp = this._modulePrefixes; |
| return !!(mp[module] && mp[module].value); // Boolean |
| }, |
| |
| _getModulePrefix: function(/*String*/module){ |
| // summary: gets the prefix associated with module |
| var mp = this._modulePrefixes; |
| if(this._moduleHasPrefix(module)){ |
| return mp[module].value; // String |
| } |
| return module; // String |
| }, |
| |
| _loadedUrls: [], |
| |
| //WARNING: |
| // This variable is referenced by packages outside of bootstrap: |
| // FloatingPane.js and undo/browser.js |
| _postLoad: false, |
| |
| //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad. |
| _loaders: [], |
| _unloaders: [], |
| _loadNotifying: false |
| }); |
| |
| |
| dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){ |
| // summary: |
| // Load a Javascript module given a relative path |
| // |
| // description: |
| // Loads and interprets the script located at relpath, which is |
| // relative to the script root directory. If the script is found but |
| // its interpretation causes a runtime exception, that exception is |
| // not caught by us, so the caller will see it. We return a true |
| // value if and only if the script is found. |
| // |
| // relpath: |
| // A relative path to a script (no leading '/', and typically ending |
| // in '.js'). |
| // module: |
| // A module whose existance to check for after loading a path. Can be |
| // used to determine success or failure of the load. |
| // cb: |
| // a callback function to pass the result of evaluating the script |
| |
| var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath; |
| if(djConfig.cacheBust && d.isBrowser){ |
| uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,""); |
| } |
| try{ |
| return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean |
| }catch(e){ |
| console.error(e); |
| return false; // Boolean |
| } |
| } |
| |
| dojo._loadUri = function(/*String (URL)*/uri, /*Function?*/cb){ |
| // summary: |
| // Loads JavaScript from a URI |
| // description: |
| // Reads the contents of the URI, and evaluates the contents. This is |
| // used to load modules as well as resource bundles. Returns true if |
| // it succeeded. Returns false if the URI reading failed. Throws if |
| // the evaluation throws. |
| // uri: a uri which points at the script to be loaded |
| // cb: |
| // a callback function to process the result of evaluating the script |
| // as an expression, typically used by the resource bundle loader to |
| // load JSON-style resources |
| |
| if(this._loadedUrls[uri]){ |
| return true; // Boolean |
| } |
| var contents = this._getText(uri, true); |
| if(!contents){ return false; } // Boolean |
| this._loadedUrls[uri] = true; |
| this._loadedUrls.push(uri); |
| if(cb){ contents = '('+contents+')'; } |
| var value = d["eval"](contents+"\r\n//@ sourceURL="+uri); |
| if(cb){ cb(value); } |
| return true; // Boolean |
| } |
| |
| // FIXME: probably need to add logging to this method |
| dojo._loadUriAndCheck = function(/*String (URL)*/uri, /*String*/moduleName, /*Function?*/cb){ |
| // summary: calls loadUri then findModule and returns true if both succeed |
| var ok = false; |
| try{ |
| ok = this._loadUri(uri, cb); |
| }catch(e){ |
| console.error("failed loading " + uri + " with error: " + e); |
| } |
| return !!(ok && this._loadedModules[moduleName]); // Boolean |
| } |
| |
| dojo.loaded = function(){ |
| // summary: |
| // signal fired when initial environment and package loading is |
| // complete. You may use dojo.addOnLoad() or dojo.connect() to |
| // this method in order to handle initialization tasks that |
| // require the environment to be initialized. In a browser host, |
| // declarative widgets will be constructed when this function |
| // finishes runing. |
| this._loadNotifying = true; |
| this._postLoad = true; |
| var mll = this._loaders; |
| |
| //Clear listeners so new ones can be added |
| //For other xdomain package loads after the initial load. |
| this._loaders = []; |
| |
| for(var x=0; x<mll.length; x++){ |
| try{ mll[x](); }catch(e){ console.error(e); /* let other events fire */ } |
| } |
| |
| this._loadNotifying = false; |
| |
| //Make sure nothing else got added to the onload queue |
| //after this first run. If something did, and we are not waiting for any |
| //more inflight resources, run again. |
| if(d._postLoad && d._inFlightCount == 0 && this._loaders.length > 0){ |
| d._callLoaded(); |
| } |
| } |
| |
| dojo.unloaded = function(){ |
| // summary: |
| // signal fired by impending environment destruction. You may use |
| // dojo.addOnUnload() or dojo.connect() to this method to perform |
| // page/application cleanup methods. |
| var mll = this._unloaders; |
| while(mll.length){ |
| (mll.pop())(); |
| } |
| } |
| |
| dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){ |
| // summary: |
| // Registers a function to be triggered after the DOM has finished |
| // loading and widgets declared in markup have been instantiated. |
| // Images and CSS files may or may not have finished downloading when |
| // the specified function is called. (Note that widgets' CSS and HTML |
| // code is guaranteed to be downloaded before said widgets are |
| // instantiated.) |
| // example: |
| // | dojo.addOnLoad(functionPointer); |
| // | dojo.addOnLoad(object, "functionName"); |
| if(arguments.length == 1){ |
| d._loaders.push(obj); |
| }else if(arguments.length > 1){ |
| d._loaders.push(function(){ |
| obj[functionName](); |
| }); |
| } |
| |
| //Added for xdomain loading. dojo.addOnLoad is used to |
| //indicate callbacks after doing some dojo.require() statements. |
| //In the xdomain case, if all the requires are loaded (after initial |
| //page load), then immediately call any listeners. |
| if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){ |
| d._callLoaded(); |
| } |
| } |
| |
| dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){ |
| // summary: registers a function to be triggered when the page unloads |
| // example: |
| // | dojo.addOnUnload(functionPointer) |
| // | dojo.addOnUnload(object, "functionName") |
| if(arguments.length == 1){ |
| d._unloaders.push(obj); |
| }else if(arguments.length > 1){ |
| d._unloaders.push(function(){ |
| obj[functionName](); |
| }); |
| } |
| } |
| |
| dojo._modulesLoaded = function(){ |
| if(d._postLoad){ return; } |
| if(d._inFlightCount > 0){ |
| console.warn("files still in flight!"); |
| return; |
| } |
| d._callLoaded(); |
| } |
| |
| dojo._callLoaded = function(){ |
| //The "object" check is for IE, and the other opera check fixes an issue |
| //in Opera where it could not find the body element in some widget test cases. |
| //For 0.9, maybe route all browsers through the setTimeout (need protection |
| //still for non-browser environments though). This might also help the issue with |
| //FF 2.0 and freezing issues where we try to do sync xhr while background css images |
| //are being loaded (trac #2572)? Consider for 0.9. |
| if(typeof setTimeout == "object" || (djConfig.useXDomain && d.isOpera)){ |
| setTimeout("dojo.loaded();", 0); |
| }else{ |
| d.loaded(); |
| } |
| } |
| |
| dojo._getModuleSymbols = function(/*String*/modulename){ |
| // summary: |
| // Converts a module name in dotted JS notation to an array |
| // representing the path in the source tree |
| var syms = modulename.split("."); |
| for(var i = syms.length; i>0; i--){ |
| var parentModule = syms.slice(0, i).join("."); |
| if((i==1) && !this._moduleHasPrefix(parentModule)){ |
| // Support default module directory (sibling of dojo) for top-level modules |
| syms[0] = "../" + syms[0]; |
| }else{ |
| var parentModulePath = this._getModulePrefix(parentModule); |
| if(parentModulePath != parentModule){ |
| syms.splice(0, i, parentModulePath); |
| break; |
| } |
| } |
| } |
| // console.debug(syms); |
| return syms; // Array |
| } |
| |
| dojo._global_omit_module_check = false; |
| |
| dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){ |
| // summary: |
| // loads a Javascript module from the appropriate URI |
| // moduleName: String |
| // omitModuleCheck: Boolean? |
| // description: |
| // _loadModule("A.B") first checks to see if symbol A.B is defined. If |
| // it is, it is simply returned (nothing to do). |
| // |
| // If it is not defined, it will look for "A/B.js" in the script root |
| // directory. |
| // |
| // It throws if it cannot find a file to load, or if the symbol A.B is |
| // not defined after loading. |
| // |
| // It returns the object A.B. |
| // |
| // This does nothing about importing symbols into the current package. |
| // It is presumed that the caller will take care of that. For example, |
| // to import all symbols: |
| // |
| // | with (dojo._loadModule("A.B")) { |
| // | ... |
| // | } |
| // |
| // And to import just the leaf symbol: |
| // |
| // | var B = dojo._loadModule("A.B"); |
| // | ... |
| // returns: the required namespace object |
| omitModuleCheck = this._global_omit_module_check || omitModuleCheck; |
| var module = this._loadedModules[moduleName]; |
| if(module){ |
| return module; |
| } |
| |
| // convert periods to slashes |
| var relpath = this._getModuleSymbols(moduleName).join("/") + '.js'; |
| |
| var modArg = (!omitModuleCheck) ? moduleName : null; |
| var ok = this._loadPath(relpath, modArg); |
| |
| if(!ok && !omitModuleCheck){ |
| throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'"); |
| } |
| |
| // check that the symbol was defined |
| // Don't bother if we're doing xdomain (asynchronous) loading. |
| if(!omitModuleCheck && !this._isXDomain){ |
| // pass in false so we can give better error |
| module = this._loadedModules[moduleName]; |
| if(!module){ |
| throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'"); |
| } |
| } |
| |
| return module; |
| } |
| |
| dojo.provide = function(/*String*/ resourceName){ |
| // summary: |
| // Each javascript source file must have (exactly) one dojo.provide() |
| // call at the top of the file, corresponding to the file name. |
| // For example, js/dojo/foo.js must have dojo.provide("dojo.foo"); at the |
| // top of the file. |
| // description: |
| // Each javascript source file is called a resource. When a resource |
| // is loaded by the browser, dojo.provide() registers that it has been |
| // loaded. |
| // |
| // For backwards compatibility reasons, in addition to registering the |
| // resource, dojo.provide() also ensures that the javascript object |
| // for the module exists. For example, |
| // dojo.provide("dojo.io.cometd"), in addition to registering that |
| // cometd.js is a resource for the dojo.iomodule, will ensure that |
| // the dojo.io javascript object exists, so that calls like |
| // dojo.io.foo = function(){ ... } don't fail. |
| // |
| // In the case of a build (or in the future, a rollup), where multiple |
| // javascript source files are combined into one bigger file (similar |
| // to a .lib or .jar file), that file will contain multiple |
| // dojo.provide() calls, to note that it includes multiple resources. |
| |
| //Make sure we have a string. |
| resourceName = resourceName + ""; |
| return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object |
| } |
| |
| //Start of old bootstrap2: |
| |
| dojo.platformRequire = function(/*Object containing Arrays*/modMap){ |
| // description: |
| // This method taks a "map" of arrays which one can use to optionally |
| // load dojo modules. The map is indexed by the possible |
| // dojo.name_ values, with two additional values: "default" |
| // and "common". The items in the "default" array will be loaded if |
| // none of the other items have been choosen based on the |
| // hostenv.name_ item. The items in the "common" array will _always_ |
| // be loaded, regardless of which list is chosen. Here's how it's |
| // normally called: |
| // |
| // | dojo.platformRequire({ |
| // | // an example that passes multiple args to _loadModule() |
| // | browser: [ |
| // | ["foo.bar.baz", true, true], |
| // | "foo.sample", |
| // | "foo.test, |
| // | ], |
| // | default: [ "foo.sample.*" ], |
| // | common: [ "really.important.module.*" ] |
| // | }); |
| |
| // FIXME: dojo.name_ no longer works!! |
| |
| var common = modMap.common || []; |
| var result = common.concat(modMap[d._name] || modMap["default"] || []); |
| |
| for(var x=0; x<result.length; x++){ |
| var curr = result[x]; |
| if(curr.constructor == Array){ |
| d._loadModule.apply(d, curr); |
| }else{ |
| d._loadModule(curr); |
| } |
| } |
| } |
| |
| dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){ |
| // summary: |
| // If the condition is true then call dojo.require() for the specified |
| // resource |
| if(condition === true){ |
| // FIXME: why do we support chained require()'s here? does the build system? |
| var args = []; |
| for(var i = 1; i < arguments.length; i++){ |
| args.push(arguments[i]); |
| } |
| d.require.apply(d, args); |
| } |
| } |
| |
| dojo.requireAfterIf = d.requireIf; |
| |
| dojo.registerModulePath = function(/*String*/module, /*String*/prefix){ |
| // summary: |
| // maps a module name to a path |
| // description: |
| // An unregistered module is given the default path of ../<module>, |
| // relative to Dojo root. For example, module acme is mapped to |
| // ../acme. If you want to use a different module name, use |
| // dojo.registerModulePath. |
| d._modulePrefixes[module] = { name: module, value: prefix }; |
| } |
| |
| dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){ |
| // summary: |
| // Declares translated resources and loads them if necessary, in the |
| // same style as dojo.require. Contents of the resource bundle are |
| // typically strings, but may be any name/value pair, represented in |
| // JSON format. See also dojo.i18n.getLocalization. |
| // moduleName: |
| // name of the package containing the "nls" directory in which the |
| // bundle is found |
| // bundleName: |
| // bundle name, i.e. the filename without the '.js' suffix |
| // locale: |
| // the locale to load (optional) By default, the browser's user |
| // locale as defined by dojo.locale |
| // availableFlatLocales: |
| // A comma-separated list of the available, flattened locales for this |
| // bundle. This argument should only be set by the build process. |
| // description: |
| // Load translated resource bundles provided underneath the "nls" |
| // directory within a package. Translated resources may be located in |
| // different packages throughout the source tree. For example, a |
| // particular widget may define one or more resource bundles, |
| // structured in a program as follows, where moduleName is |
| // mycode.mywidget and bundleNames available include bundleone and |
| // bundletwo: |
| // |
| // ... |
| // mycode/ |
| // mywidget/ |
| // nls/ |
| // bundleone.js (the fallback translation, English in this example) |
| // bundletwo.js (also a fallback translation) |
| // de/ |
| // bundleone.js |
| // bundletwo.js |
| // de-at/ |
| // bundleone.js |
| // en/ |
| // (empty; use the fallback translation) |
| // en-us/ |
| // bundleone.js |
| // en-gb/ |
| // bundleone.js |
| // es/ |
| // bundleone.js |
| // bundletwo.js |
| // ...etc |
| // ... |
| // |
| // Each directory is named for a locale as specified by RFC 3066, |
| // (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase. |
| // Note that the two bundles in the example do not define all the same |
| // variants. For a given locale, bundles will be loaded for that |
| // locale and all more general locales above it, including a fallback |
| // at the root directory. For example, a declaration for the "de-at" |
| // locale will first load nls/de-at/bundleone.js, then |
| // nls/de/bundleone.js and finally nls/bundleone.js. The data will be |
| // flattened into a single Object so that lookups will follow this |
| // cascading pattern. An optional build step can preload the bundles |
| // to avoid data redundancy and the multiple network hits normally |
| // required to load these resources. |
| |
| d.require("dojo.i18n"); |
| d.i18n._requireLocalization.apply(d.hostenv, arguments); |
| }; |
| |
| |
| var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"); |
| var ire = new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$"); |
| |
| dojo._Url = function(/*dojo._Url||String...*/){ |
| // summary: |
| // Constructor to create an object representing a URL. |
| // It is marked as private, since we might consider removing |
| // or simplifying it. |
| // description: |
| // Each argument is evaluated in order relative to the next until |
| // a canonical uri is produced. To get an absolute Uri relative to |
| // the current document use: |
| // new dojo._Url(document.baseURI, url) |
| |
| var n = null; |
| |
| // TODO: support for IPv6, see RFC 2732 |
| var _a = arguments; |
| var uri = _a[0]; |
| // resolve uri components relative to each other |
| for(var i = 1; i<_a.length; i++){ |
| if(!_a[i]){ continue; } |
| |
| // Safari doesn't support this.constructor so we have to be explicit |
| // FIXME: Tracked (and fixed) in Webkit bug 3537. |
| // http://bugs.webkit.org/show_bug.cgi?id=3537 |
| var relobj = new d._Url(_a[i]+""); |
| var uriobj = new d._Url(uri+""); |
| |
| if( |
| relobj.path == "" && |
| !relobj.scheme && |
| !relobj.authority && |
| !relobj.query |
| ){ |
| if(relobj.fragment != n){ |
| uriobj.fragment = relobj.fragment; |
| } |
| relobj = uriobj; |
| }else if(!relobj.scheme){ |
| relobj.scheme = uriobj.scheme; |
| |
| if(!relobj.authority){ |
| relobj.authority = uriobj.authority; |
| |
| if(relobj.path.charAt(0) != "/"){ |
| var path = uriobj.path.substring(0, |
| uriobj.path.lastIndexOf("/") + 1) + relobj.path; |
| |
| var segs = path.split("/"); |
| for(var j = 0; j < segs.length; j++){ |
| if(segs[j] == "."){ |
| if(j == segs.length - 1){ |
| segs[j] = ""; |
| }else{ |
| segs.splice(j, 1); |
| j--; |
| } |
| }else if(j > 0 && !(j == 1 && segs[0] == "") && |
| segs[j] == ".." && segs[j-1] != ".."){ |
| |
| if(j == (segs.length - 1)){ |
| segs.splice(j, 1); |
| segs[j - 1] = ""; |
| }else{ |
| segs.splice(j - 1, 2); |
| j -= 2; |
| } |
| } |
| } |
| relobj.path = segs.join("/"); |
| } |
| } |
| } |
| |
| uri = ""; |
| if(relobj.scheme){ |
| uri += relobj.scheme + ":"; |
| } |
| if(relobj.authority){ |
| uri += "//" + relobj.authority; |
| } |
| uri += relobj.path; |
| if(relobj.query){ |
| uri += "?" + relobj.query; |
| } |
| if(relobj.fragment){ |
| uri += "#" + relobj.fragment; |
| } |
| } |
| |
| this.uri = uri.toString(); |
| |
| // break the uri into its main components |
| var r = this.uri.match(ore); |
| |
| this.scheme = r[2] || (r[1] ? "" : n); |
| this.authority = r[4] || (r[3] ? "" : n); |
| this.path = r[5]; // can never be undefined |
| this.query = r[7] || (r[6] ? "" : n); |
| this.fragment = r[9] || (r[8] ? "" : n); |
| |
| if(this.authority != n){ |
| // server based naming authority |
| r = this.authority.match(ire); |
| |
| this.user = r[3] || n; |
| this.password = r[4] || n; |
| this.host = r[5]; |
| this.port = r[7] || n; |
| } |
| } |
| |
| dojo._Url.prototype.toString = function(){ return this.uri; }; |
| |
| dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){ |
| // summary: |
| // Returns a Url object relative to a module |
| // |
| // example: |
| // | dojo.moduleUrl("dojo.widget","templates/template.html"); |
| // example: |
| // | dojo.moduleUrl("acme","images/small.png") |
| |
| var loc = d._getModuleSymbols(module).join('/'); |
| if(!loc){ return null; } |
| if(loc.lastIndexOf("/") != loc.length-1){ |
| loc += "/"; |
| } |
| |
| //If the path is an absolute path (starts with a / or is on another |
| //domain/xdomain) then don't add the baseUrl. |
| var colonIndex = loc.indexOf(":"); |
| if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){ |
| loc = d.baseUrl + loc; |
| } |
| |
| return new d._Url(loc, url); // String |
| } |
| })(); |
| |
| /*===== |
| dojo.isBrowser = { |
| // summary: True if the client is a web-browser |
| // example: |
| // if(dojo.isBrowser){ ... } |
| }; |
| |
| dojo.isFF = { |
| // summary: True if client is using FireFox browser. False otherwise. |
| // example: |
| // if(dojo.isFF && dojo.isFF > 1){ ... } |
| }; |
| |
| dojo.isIE = { |
| // summary: The major version if client it using Internet Explorer (or false) |
| // example: |
| // if(dojo.isIE && dojo.isIE > 6){ |
| // // we are IE7 |
| // } |
| }; |
| |
| dojo.isKhtml = { |
| // summary: True if client is using Khtml browsers (konqueror, et al) |
| }; |
| |
| dojo.isMozilla = { |
| // summary: True if client is using a Mozilla-based browser. |
| }; |
| |
| dojo.isOpera = { |
| // summary: True if client is using the Opera web browser |
| }; |
| |
| dojo.isSafari = { |
| // summary: True if client is using the Safari web browser |
| // example: |
| // | if(dojo.isSafari){ ... } |
| // |
| // example: |
| // Detect iPhone: |
| // | if(dojo.isSafari && (navigator.userAgent.indexOf("iPhone") < 0)){ |
| // | // we are iPhone. iPod touch reports "iPod" above |
| // | } |
| }; |
| =====*/ |
| |
| if(typeof window != 'undefined'){ |
| dojo.isBrowser = true; |
| dojo._name = "browser"; |
| |
| |
| // attempt to figure out the path to dojo if it isn't set in the config |
| (function(){ |
| var d = dojo; |
| // this is a scope protection closure. We set browser versions and grab |
| // the URL we were loaded from here. |
| |
| // grab the node we were loaded from |
| if(document && document.getElementsByTagName){ |
| var scripts = document.getElementsByTagName("script"); |
| var rePkg = /dojo(\.xd)?\.js([\?\.]|$)/i; |
| for(var i = 0; i < scripts.length; i++){ |
| var src = scripts[i].getAttribute("src"); |
| if(!src){ continue; } |
| var m = src.match(rePkg); |
| if(m){ |
| // find out where we came from |
| if(!djConfig["baseUrl"]){ |
| djConfig["baseUrl"] = src.substring(0, m.index); |
| } |
| // and find out if we need to modify our behavior |
| var cfg = scripts[i].getAttribute("djConfig"); |
| if(cfg){ |
| var cfgo = eval("({ "+cfg+" })"); |
| for(var x in cfgo){ |
| djConfig[x] = cfgo[x]; |
| } |
| } |
| break; // "first Dojo wins" |
| } |
| } |
| } |
| d.baseUrl = djConfig["baseUrl"]; |
| |
| // fill in the rendering support information in dojo.render.* |
| var n = navigator; |
| var dua = n.userAgent; |
| var dav = n.appVersion; |
| var tv = parseFloat(dav); |
| |
| d.isOpera = (dua.indexOf("Opera") >= 0) ? tv : 0; |
| d.isKhtml = (dav.indexOf("Konqueror") >= 0)||(dav.indexOf("Safari") >= 0) ? tv : 0; |
| if(dav.indexOf("Safari") >= 0){ |
| d.isSafari = parseFloat(dav.split("Version/")[1]) || 2; |
| } |
| var geckoPos = dua.indexOf("Gecko"); |
| d.isMozilla = d.isMoz = ((geckoPos >= 0)&&(!d.isKhtml)) ? tv : 0; |
| d.isFF = 0; |
| d.isIE = 0; |
| try{ |
| if(d.isMoz){ |
| d.isFF = parseFloat(dua.split("Firefox/")[1].split(" ")[0]); |
| } |
| if((document.all)&&(!d.isOpera)){ |
| d.isIE = parseFloat(dav.split("MSIE ")[1].split(";")[0]); |
| } |
| }catch(e){} |
| |
| //Workaround to get local file loads of dojo to work on IE 7 |
| //by forcing to not use native xhr. |
| if(dojo.isIE && (window.location.protocol === "file:")){ |
| djConfig.ieForceActiveXXhr=true; |
| } |
| |
| var cm = document["compatMode"]; |
| d.isQuirks = (cm == "BackCompat")||(cm == "QuirksMode")||(d.isIE < 6); |
| |
| // TODO: is the HTML LANG attribute relevant? |
| d.locale = djConfig.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase(); |
| |
| d._println = console.debug; |
| |
| // These are in order of decreasing likelihood; this will change in time. |
| d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0']; |
| |
| d._xhrObj= function(){ |
| // summary: |
| // does the work of portably generating a new XMLHTTPRequest |
| // object. |
| var http = null; |
| var last_e = null; |
| if(!dojo.isIE || !djConfig.ieForceActiveXXhr){ |
| try{ http = new XMLHttpRequest(); }catch(e){} |
| } |
| if(!http){ |
| for(var i=0; i<3; ++i){ |
| var progid = dojo._XMLHTTP_PROGIDS[i]; |
| try{ |
| http = new ActiveXObject(progid); |
| }catch(e){ |
| last_e = e; |
| } |
| |
| if(http){ |
| dojo._XMLHTTP_PROGIDS = [progid]; // so faster next time |
| break; |
| } |
| } |
| } |
| |
| if(!http){ |
| throw new Error("XMLHTTP not available: "+last_e); |
| } |
| |
| return http; // XMLHTTPRequest instance |
| } |
| |
| d._isDocumentOk = function(http){ |
| var stat = http.status || 0; |
| return ( (stat>=200)&&(stat<300))|| // Boolean |
| (stat==304)|| // allow any 2XX response code |
| (stat==1223)|| // get it out of the cache |
| (!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code |
| } |
| |
| //See if base tag is in use. |
| //This is to fix http://trac.dojotoolkit.org/ticket/3973, |
| //but really, we need to find out how to get rid of the dojo._Url reference |
| //below and still have DOH work with the dojo.i18n test following some other |
| //test that uses the test frame to load a document (trac #2757). |
| //Opera still has problems, but perhaps a larger issue of base tag support |
| //with XHR requests (hasBase is true, but the request is still made to document |
| //path, not base path). |
| var owloc = window.location+""; |
| var base = document.getElementsByTagName("base"); |
| var hasBase = (base && base.length > 0); |
| |
| d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){ |
| // summary: Read the contents of the specified uri and return those contents. |
| // uri: |
| // A relative or absolute uri. If absolute, it still must be in |
| // the same "domain" as we are. |
| // fail_ok: |
| // Default false. If fail_ok and loading fails, return null |
| // instead of throwing. |
| // returns: The response text. null is returned when there is a |
| // failure and failure is okay (an exception otherwise) |
| |
| // alert("_getText: " + uri); |
| |
| // NOTE: must be declared before scope switches ie. this._xhrObj() |
| var http = this._xhrObj(); |
| |
| if(!hasBase && dojo._Url){ |
| uri = (new dojo._Url(owloc, uri)).toString(); |
| } |
| /* |
| console.debug("_getText:", uri); |
| console.debug(window.location+""); |
| alert(uri); |
| */ |
| |
| http.open('GET', uri, false); |
| try{ |
| http.send(null); |
| // alert(http); |
| if(!d._isDocumentOk(http)){ |
| var err = Error("Unable to load "+uri+" status:"+ http.status); |
| err.status = http.status; |
| err.responseText = http.responseText; |
| throw err; |
| } |
| }catch(e){ |
| if(fail_ok){ return null; } // null |
| // rethrow the exception |
| throw e; |
| } |
| return http.responseText; // String |
| } |
| })(); |
| |
| dojo._initFired = false; |
| // BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/) |
| dojo._loadInit = function(e){ |
| dojo._initFired = true; |
| // allow multiple calls, only first one will take effect |
| // A bug in khtml calls events callbacks for document for event which isnt supported |
| // for example a created contextmenu event calls DOMContentLoaded, workaround |
| var type = (e && e.type) ? e.type.toLowerCase() : "load"; |
| if(arguments.callee.initialized || (type!="domcontentloaded" && type!="load")){ return; } |
| arguments.callee.initialized = true; |
| if(typeof dojo["_khtmlTimer"] != 'undefined'){ |
| clearInterval(dojo._khtmlTimer); |
| delete dojo._khtmlTimer; |
| } |
| |
| if(dojo._inFlightCount == 0){ |
| dojo._modulesLoaded(); |
| } |
| } |
| |
| // START DOMContentLoaded |
| // Mozilla and Opera 9 expose the event we could use |
| if(document.addEventListener){ |
| // NOTE: |
| // due to a threading issue in Firefox 2.0, we can't enable |
| // DOMContentLoaded on that platform. For more information, see: |
| // http://trac.dojotoolkit.org/ticket/1704 |
| if(dojo.isOpera|| (dojo.isMoz && (djConfig["enableMozDomContentLoaded"] === true))){ |
| document.addEventListener("DOMContentLoaded", dojo._loadInit, null); |
| } |
| |
| // mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already. |
| // also used for Mozilla because of trac #1640 |
| window.addEventListener("load", dojo._loadInit, null); |
| } |
| |
| if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff |
| dojo._khtmlTimer = setInterval(function(){ |
| if(/loaded|complete/.test(document.readyState)){ |
| dojo._loadInit(); // call the onload handler |
| } |
| }, 10); |
| } |
| // END DOMContentLoaded |
| |
| (function(){ |
| |
| var _w = window; |
| var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){ |
| // summary: |
| // non-destructively adds the specified function to the node's |
| // evtName handler. |
| // evtName: should be in the form "onclick" for "onclick" handlers. |
| // Make sure you pass in the "on" part. |
| var oldHandler = _w[evtName] || function(){}; |
| _w[evtName] = function(){ |
| fp.apply(_w, arguments); |
| oldHandler.apply(_w, arguments); |
| } |
| } |
| |
| if(dojo.isIE){ |
| // for Internet Explorer. readyState will not be achieved on init |
| // call, but dojo doesn't need it however, we'll include it |
| // because we don't know if there are other functions added that |
| // might. Note that this has changed because the build process |
| // strips all comments -- including conditional ones. |
| |
| document.write('<scr'+'ipt defer src="//:" ' |
| + 'onreadystatechange="if(this.readyState==\'complete\'){dojo._loadInit();}">' |
| + '</scr'+'ipt>' |
| ); |
| |
| // IE WebControl hosted in an application can fire "beforeunload" and "unload" |
| // events when control visibility changes, causing Dojo to unload too soon. The |
| // following code fixes the problem |
| // Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155 |
| var _unloading = true; |
| _handleNodeEvent("onbeforeunload", function(){ |
| _w.setTimeout(function(){ _unloading = false; }, 0); |
| }); |
| _handleNodeEvent("onunload", function(){ |
| if(_unloading){ dojo.unloaded(); } |
| }); |
| |
| try{ |
| document.namespaces.add("v","urn:schemas-microsoft-com:vml"); |
| document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)"); |
| }catch(e){} |
| }else{ |
| // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper. |
| _handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); }); |
| } |
| |
| })(); |
| |
| /* |
| OpenAjax.subscribe("OpenAjax", "onload", function(){ |
| if(dojo._inFlightCount == 0){ |
| dojo._modulesLoaded(); |
| } |
| }); |
| |
| OpenAjax.subscribe("OpenAjax", "onunload", function(){ |
| dojo.unloaded(); |
| }); |
| */ |
| } //if (typeof window != 'undefined') |
| |
| //Load debug code if necessary. |
| // dojo.requireIf((djConfig["isDebug"] || djConfig["debugAtAllCosts"]), "dojo.debug"); |
| |
| //window.widget is for Dashboard detection |
| //The full conditionals are spelled out to avoid issues during builds. |
| //Builds may be looking for require/requireIf statements and processing them. |
| // dojo.requireIf(djConfig["debugAtAllCosts"] && !window.widget && !djConfig["useXDomain"], "dojo.browser_debug"); |
| // dojo.requireIf(djConfig["debugAtAllCosts"] && !window.widget && djConfig["useXDomain"], "dojo.browser_debug_xd"); |
| |
| if(djConfig.isDebug){ |
| dojo.require("dojo._firebug.firebug"); |
| } |
| |
| if(djConfig.debugAtAllCosts){ |
| djConfig.useXDomain = true; |
| dojo.require("dojo._base._loader.loader_xd"); |
| dojo.require("dojo._base._loader.loader_debug"); |
| dojo.require("dojo.i18n"); |
| } |
| |
| }; |
| |
| if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.lang"] = true; |
| dojo.provide("dojo._base.lang"); |
| |
| // Crockford (ish) functions |
| |
| dojo.isString = function(/*anything*/ it){ |
| // summary: Return true if it is a String |
| return typeof it == "string" || it instanceof String; // Boolean |
| } |
| |
| dojo.isArray = function(/*anything*/ it){ |
| // summary: Return true if it is an Array |
| return it && it instanceof Array || typeof it == "array"; // Boolean |
| } |
| |
| /*===== |
| dojo.isFunction = function(it){ |
| // summary: Return true if it is a Function |
| // it: anything |
| } |
| =====*/ |
| |
| dojo.isFunction = (function(){ |
| var _isFunction = function(/*anything*/ it){ |
| return typeof it == "function" || it instanceof Function; // Boolean |
| }; |
| |
| return dojo.isSafari ? |
| // only slow this down w/ gratuitious casting in Safari since it's what's b0rken |
| function(/*anything*/ it){ |
| if(typeof it == "function" && it == "[object NodeList]"){ return false; } |
| return _isFunction(it); // Boolean |
| } : _isFunction; |
| })(); |
| |
| dojo.isObject = function(/*anything*/ it){ |
| // summary: |
| // Returns true if it is a JavaScript object (or an Array, a Function or null) |
| return it !== undefined && |
| (it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean |
| } |
| |
| dojo.isArrayLike = function(/*anything*/ it){ |
| // summary: |
| // similar to dojo.isArray() but more permissive |
| // description: |
| // Doesn't strongly test for "arrayness". Instead, settles for "isn't |
| // a string or number and has a length property". Arguments objects |
| // and DOM collections will return true when passed to |
| // dojo.isArrayLike(), but will return false when passed to |
| // dojo.isArray(). |
| // return: |
| // If it walks like a duck and quicks like a duck, return true |
| var d = dojo; |
| return it && it !== undefined && |
| // keep out built-in constructors (Number, String, ...) which have length |
| // properties |
| !d.isString(it) && !d.isFunction(it) && |
| !(it.tagName && it.tagName.toLowerCase() == 'form') && |
| (d.isArray(it) || isFinite(it.length)); // Boolean |
| } |
| |
| dojo.isAlien = function(/*anything*/ it){ |
| // summary: |
| // Returns true if it is a built-in function or some other kind of |
| // oddball that *should* report as a function but doesn't |
| return it && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean |
| } |
| |
| dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){ |
| // summary: |
| // Adds all properties and methods of props to constructor's |
| // prototype, making them available to all instances created with |
| // constructor. |
| for(var i=1, l=arguments.length; i<l; i++){ |
| dojo._mixin(constructor.prototype, arguments[i]); |
| } |
| return constructor; // Object |
| } |
| |
| dojo._hitchArgs = function(scope, method /*,...*/){ |
| var pre = dojo._toArray(arguments, 2); |
| var named = dojo.isString(method); |
| return function(){ |
| // arrayify arguments |
| var args = dojo._toArray(arguments); |
| // locate our method |
| var f = named ? (scope||dojo.global)[method] : method; |
| // invoke with collected args |
| return f && f.apply(scope || this, pre.concat(args)); // mixed |
| } // Function |
| } |
| |
| dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){ |
| // summary: |
| // Returns a function that will only ever execute in the a given scope. |
| // This allows for easy use of object member functions |
| // in callbacks and other places in which the "this" keyword may |
| // otherwise not reference the expected scope. |
| // Any number of default positional arguments may be passed as parameters |
| // beyond "method". |
| // Each of these values will be used to "placehold" (similar to curry) |
| // for the hitched function. |
| // scope: |
| // The scope to use when method executes. If method is a string, |
| // scope is also the object containing method. |
| // method: |
| // A function to be hitched to scope, or the name of the method in |
| // scope to be hitched. |
| // example: |
| // | dojo.hitch(foo, "bar")(); |
| // runs foo.bar() in the scope of foo |
| // example: |
| // | dojo.hitch(foo, myFunction); |
| // returns a function that runs myFunction in the scope of foo |
| if(arguments.length > 2){ |
| return dojo._hitchArgs.apply(dojo, arguments); // Function |
| } |
| if(!method){ |
| method = scope; |
| scope = null; |
| } |
| if(dojo.isString(method)){ |
| scope = scope || dojo.global; |
| if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); } |
| return function(){ return scope[method].apply(scope, arguments || []); }; // Function |
| } |
| return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function |
| } |
| |
| /*===== |
| dojo.delegate = function(obj, props){ |
| // summary: |
| // returns a new object which "looks" to obj for properties which it |
| // does not have a value for. Optionally takes a bag of properties to |
| // seed the returned object with initially. |
| // description: |
| // This is a small implementaton of the Boodman/Crockford delegation |
| // pattern in JavaScript. An intermediate object constructor mediates |
| // the prototype chain for the returned object, using it to delegate |
| // down to obj for property lookup when object-local lookup fails. |
| // This can be thought of similarly to ES4's "wrap", save that it does |
| // not act on types but rather on pure objects. |
| // obj: |
| // The object to delegate to for properties not found directly on the |
| // return object or in props. |
| // props: |
| // an object containing properties to assign to the returned object |
| // returns: |
| // an Object of anonymous type |
| // example: |
| // | var foo = { bar: "baz" }; |
| // | var thinger = dojo.delegate(foo, { thud: "xyzzy"}); |
| // | thinger.bar == "baz"; // delegated to foo |
| // | foo.xyzzy == undefined; // by definition |
| // | thinger.xyzzy == "xyzzy"; // mixed in from props |
| // | foo.bar = "thonk"; |
| // | thinger.bar == "thonk"; // still delegated to foo's bar |
| } |
| =====*/ |
| |
| |
| dojo.delegate = dojo._delegate = function(obj, props){ |
| |
| // boodman/crockford delegation |
| function TMP(){}; |
| TMP.prototype = obj; |
| var tmp = new TMP(); |
| if(props){ |
| dojo.mixin(tmp, props); |
| } |
| return tmp; // Object |
| } |
| |
| dojo.partial = function(/*Function|String*/method /*, ...*/){ |
| // summary: |
| // similar to hitch() except that the scope object is left to be |
| // whatever the execution context eventually becomes. |
| // description: |
| // Calling dojo.partial is the functional equivalent of calling: |
| // | dojo.hitch(null, funcName, ...); |
| var arr = [ null ]; |
| return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function |
| } |
| |
| dojo._toArray = function(/*Object*/obj, /*Number?*/offset, /*Array?*/ startWith){ |
| // summary: |
| // Converts an array-like object (i.e. arguments, DOMCollection) |
| // to an array. Returns a new Array object. |
| // obj: |
| // the object to "arrayify". We expect the object to have, at a |
| // minimum, a length property which corresponds to integer-indexed |
| // properties. |
| // offset: |
| // the location in obj to start iterating from. Defaults to 0. Optional. |
| // startWith: |
| // An array to pack with the properties of obj. If provided, |
| // properties in obj are appended at the end of startWith and |
| // startWith is the returned array. |
| var arr = startWith||[]; |
| for(var x = offset || 0; x < obj.length; x++){ |
| arr.push(obj[x]); |
| } |
| return arr; // Array |
| } |
| |
| dojo.clone = function(/*anything*/ o){ |
| // summary: |
| // Clones objects (including DOM nodes) and all children. |
| // Warning: do not clone cyclic structures. |
| if(!o){ return o; } |
| if(dojo.isArray(o)){ |
| var r = []; |
| for(var i = 0; i < o.length; ++i){ |
| r.push(dojo.clone(o[i])); |
| } |
| return r; // Array |
| } |
| if(!dojo.isObject(o)){ |
| return o; /*anything*/ |
| } |
| if(o.nodeType && o.cloneNode){ // isNode |
| return o.cloneNode(true); // Node |
| } |
| if(o instanceof Date){ |
| return new Date(o.getTime()); // Date |
| } |
| // Generic objects |
| var r = new o.constructor(); // specific to dojo.declare()'d classes! |
| for(var i in o){ |
| if(!(i in r) || r[i] != o[i]){ |
| r[i] = dojo.clone(o[i]); |
| } |
| } |
| return r; // Object |
| } |
| |
| dojo.trim = function(/*String*/ str){ |
| // summary: |
| // trims whitespaces from both sides of the string |
| // description: |
| // This version of trim() was selected for inclusion into the base due |
| // to its compact size and relatively good performance (see Steven |
| // Levithan's blog: |
| // http://blog.stevenlevithan.com/archives/faster-trim-javascript). |
| // The fastest but longest version of this function is located at |
| // dojo.string.trim() |
| return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String |
| } |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.declare"] = true; |
| dojo.provide("dojo._base.declare"); |
| |
| |
| // this file courtesy of the TurboAjax group, licensed under a Dojo CLA |
| |
| dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){ |
| // summary: |
| // Create a feature-rich constructor from compact notation |
| // className: |
| // The name of the constructor (loosely, a "class") |
| // stored in the "declaredClass" property in the created prototype |
| // superclass: |
| // May be null, a Function, or an Array of Functions. If an array, |
| // the first element is used as the prototypical ancestor and |
| // any following Functions become mixin ancestors. |
| // props: |
| // An object whose properties are copied to the |
| // created prototype. |
| // Add an instance-initialization function by making it a property |
| // named "constructor". |
| // description: |
| // Create a constructor using a compact notation for inheritance and |
| // prototype extension. |
| // |
| // All superclasses (including mixins) must be Functions (not simple Objects). |
| // |
| // Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin |
| // ancestors are copied to the new class: changes to mixin prototypes will |
| // not affect classes to which they have been mixed in. |
| // |
| // "className" is cached in "declaredClass" property of the new class. |
| // |
| // example: |
| // | dojo.declare("my.classes.bar", my.classes.foo, { |
| // | // properties to be added to the class prototype |
| // | someValue: 2, |
| // | // initialization function |
| // | constructor: function(){ |
| // | this.myComplicatedObject = new ReallyComplicatedObject(); |
| // | }, |
| // | // other functions |
| // | someMethod: function(){ |
| // | doStuff(); |
| // | } |
| // | ); |
| |
| // argument juggling (deprecated) |
| if(dojo.isFunction(props)||(arguments.length>3)){ |
| dojo.deprecated("dojo.declare: for class '" + className + "' pass initializer function as 'constructor' property instead of as a separate argument.", "", "1.0"); |
| var c = props; |
| props = arguments[3] || {}; |
| props.constructor = c; |
| } |
| // process superclass argument |
| // var dd=dojo.declare, mixins=null; |
| var dd=arguments.callee, mixins=null; |
| if(dojo.isArray(superclass)){ |
| mixins = superclass; |
| superclass = mixins.shift(); |
| } |
| // construct intermediate classes for mixins |
| if(mixins){ |
| for(var i=0, m; i<mixins.length; i++){ |
| m = mixins[i]; |
| if(!m){throw("Mixin #" + i + " to declaration of " + className + " is null. It's likely a required module is not loaded.")}; |
| superclass = dd._delegate(superclass, m); |
| } |
| } |
| // prepare values |
| var init=(props||0).constructor, ctor=dd._delegate(superclass), fn; |
| // name methods (experimental) |
| for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}} |
| // decorate prototype |
| dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props||0); |
| // special help for IE |
| ctor.prototype.constructor = ctor; |
| // create named reference |
| return dojo.setObject(className, ctor); // Function |
| } |
| |
| dojo.mixin(dojo.declare, { |
| _delegate: function(base, mixin){ |
| var bp = (base||0).prototype, mp = (mixin||0).prototype; |
| // fresh constructor, fresh prototype |
| var ctor = dojo.declare._makeCtor(); |
| // cache ancestry |
| dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend}); |
| // chain prototypes |
| if(base){ctor.prototype = dojo._delegate(bp);} |
| // add mixin and core |
| dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null}); |
| // special help for IE |
| ctor.prototype.constructor = ctor; |
| // name this class for debugging |
| ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass; |
| return ctor; |
| }, |
| _extend: function(props){ |
| for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}} |
| dojo.extend(this, props); |
| }, |
| _makeCtor: function(){ |
| // we have to make a function, but don't want to close over anything |
| return function(){ this._construct(arguments); } |
| }, |
| _core: { |
| _construct: function(args){ |
| var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn; |
| // side-effect of = used on purpose here, lint may complain, don't try this at home |
| if(a[0]){ |
| // FIXME: preambles for each mixin should be allowed |
| // FIXME: |
| // should we allow the preamble here NOT to modify the |
| // default args, but instead to act on each mixin |
| // independently of the class instance being constructed |
| // (for impdedence matching)? |
| |
| // allow any first argument w/ a "preamble" property to act as a |
| // class preamble (not exclusive of the prototype preamble) |
| if(/*dojo.isFunction*/(fn = a[0]["preamble"])){ |
| a = fn.apply(this, a) || a; |
| } |
| } |
| // prototype preamble |
| if(fn=c.prototype.preamble){a = fn.apply(this, a) || a;} |
| // FIXME: |
| // need to provide an optional prototype-settable |
| // "_explicitSuper" property which disables this |
| // initialize superclass |
| if(ct&&ct.apply){ct.apply(this, a);} |
| // initialize mixin |
| if(mct&&mct.apply){mct.apply(this, a);} |
| // initialize self |
| if(ii=c.prototype._constructor){ii.apply(this, args);} |
| // post construction |
| if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ct.apply(this, args)}; |
| }, |
| _findMixin: function(mixin){ |
| var c = this.constructor, p, m; |
| while(c){ |
| p = c.superclass; |
| m = c.mixin; |
| if(m==mixin || (m instanceof mixin.constructor)){return p;} |
| if(m && (m=m._findMixin(mixin))){return m;} |
| c = p && p.constructor; |
| } |
| }, |
| _findMethod: function(name, method, ptype, has){ |
| // consciously trading readability for bytes and speed in this low-level method |
| var p=ptype, c, m, f; |
| do{ |
| c = p.constructor; |
| m = c.mixin; |
| // find method by name in our mixin ancestor |
| if(m && (m=this._findMethod(name, method, m, has))){return m}; |
| // if we found a named method that either exactly-is or exactly-is-not 'method' |
| if((f=p[name])&&(has==(f==method))){return p}; |
| // ascend chain |
| p = c.superclass; |
| }while(p); |
| // if we couldn't find an ancestor in our primary chain, try a mixin chain |
| return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has); |
| }, |
| inherited: function(name, args, newArgs){ |
| // optionalize name argument (experimental) |
| var a = arguments; |
| if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;} |
| var c=args.callee, p=this.constructor.prototype, a=newArgs||args, fn, mp; |
| // if not an instance override |
| if(this[name]!=c || p[name]==c){ |
| mp = this._findMethod(name, c, p, true); |
| if(!mp){throw(this.declaredClass + ': name argument ("' + name + '") to inherited must match callee (declare.js)');} |
| p = this._findMethod(name, c, mp, false); |
| } |
| fn = p && p[name]; |
| // FIXME: perhaps we should throw here? |
| if(!fn){console.debug(mp.declaredClass + ': no inherited "' + name + '" was found (declare.js)'); return;} |
| // if the function exists, invoke it in our scope |
| return fn.apply(this, a); |
| } |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.connect"] = true; |
| dojo.provide("dojo._base.connect"); |
| |
| |
| // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA |
| |
| // low-level delegation machinery |
| dojo._listener = { |
| // create a dispatcher function |
| getDispatcher: function(){ |
| // following comments pulled out-of-line to prevent cloning them |
| // in the returned function. |
| // - indices (i) that are really in the array of listeners (ls) will |
| // not be in Array.prototype. This is the 'sparse array' trick |
| // that keeps us safe from libs that take liberties with built-in |
| // objects |
| // - listener is invoked with current scope (this) |
| return function(){ |
| var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target; |
| // return value comes from original target function |
| var r=t && t.apply(this, arguments); |
| // invoke listeners after target function |
| for(var i in ls){ |
| if(!(i in ap)){ |
| ls[i].apply(this, arguments); |
| } |
| } |
| // return value comes from original target function |
| return r; |
| } |
| }, |
| // add a listener to an object |
| add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){ |
| // Whenever 'method' is invoked, 'listener' will have the same scope. |
| // Trying to supporting a context object for the listener led to |
| // complexity. |
| // Non trivial to provide 'once' functionality here |
| // because listener could be the result of a dojo.hitch call, |
| // in which case two references to the same hitch target would not |
| // be equivalent. |
| source = source || dojo.global; |
| // The source method is either null, a dispatcher, or some other function |
| var f = source[method]; |
| // Ensure a dispatcher |
| if(!f||!f._listeners){ |
| var d = dojo._listener.getDispatcher(); |
| // original target function is special |
| d.target = f; |
| // dispatcher holds a list of listeners |
| d._listeners = []; |
| // redirect source to dispatcher |
| f = source[method] = d; |
| } |
| // The contract is that a handle is returned that can |
| // identify this listener for disconnect. |
| // |
| // The type of the handle is private. Here is it implemented as Integer. |
| // DOM event code has this same contract but handle is Function |
| // in non-IE browsers. |
| // |
| // We could have separate lists of before and after listeners. |
| return f._listeners.push(listener) ; /*Handle*/ |
| }, |
| // remove a listener from an object |
| remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){ |
| var f = (source||dojo.global)[method]; |
| // remember that handle is the index+1 (0 is not a valid handle) |
| if(f && f._listeners && handle--){ |
| delete f._listeners[handle]; |
| } |
| } |
| }; |
| |
| // Multiple delegation for arbitrary methods. |
| |
| // This unit knows nothing about DOM, |
| // but we include DOM aware |
| // documentation and dontFix |
| // argument here to help the autodocs. |
| // Actual DOM aware code is in event.js. |
| |
| dojo.connect = function(/*Object|null*/ obj, |
| /*String*/ event, |
| /*Object|null*/ context, |
| /*String|Function*/ method, |
| /*Boolean*/ dontFix){ |
| // summary: |
| // Create a link that calls one function when another executes. |
| // |
| // description: |
| // Connects method to event, so that after event fires, method |
| // does too. All connected functions are passed the same arguments as |
| // the event function was initially called with. You may connect as |
| // many methods to event as needed. |
| // |
| // event must be a string. If obj is null, dojo.global is used. |
| // |
| // null arguments may simply be omitted. |
| // |
| // obj[event] can resolve to a function or undefined (null). |
| // If obj[event] is null, it is assigned a function. |
| // |
| // The return value is a handle that is needed to |
| // remove this connection with dojo.disconnect. |
| // |
| // obj: |
| // The source object for the event function. |
| // Defaults to dojo.global if null. |
| // If obj is a DOM node, the connection is delegated |
| // to the DOM event manager (unless dontFix is true). |
| // |
| // event: |
| // String name of the event function in obj. |
| // I.e. identifies a property obj[event]. |
| // |
| // context: |
| // The object that method will receive as "this". |
| // |
| // If context is null and method is a function, then method |
| // inherits the context of event. |
| // |
| // If method is a string then context must be the source |
| // object object for method (context[method]). If context is null, |
| // dojo.global is used. |
| // |
| // method: |
| // A function reference, or name of a function in context. |
| // The function identified by method fires after event does. |
| // method receives the same arguments as the event. |
| // See context argument comments for information on method's scope. |
| // |
| // dontFix: |
| // If obj is a DOM node, set dontFix to true to prevent delegation |
| // of this connection to the DOM event manager. |
| // |
| // example: |
| // When obj.onchange(), do ui.update(): |
| // | dojo.connect(obj, "onchange", ui, "update"); |
| // | dojo.connect(obj, "onchange", ui, ui.update); // same |
| // |
| // example: |
| // Using return value for disconnect: |
| // | var link = dojo.connect(obj, "onchange", ui, "update"); |
| // | ... |
| // | dojo.disconnect(link); |
| // |
| // example: |
| // When onglobalevent executes, watcher.handler is invoked: |
| // | dojo.connect(null, "onglobalevent", watcher, "handler"); |
| // |
| // example: |
| // When ob.onCustomEvent executes, customEventHandler is invoked: |
| // | dojo.connect(ob, "onCustomEvent", null, "customEventHandler"); |
| // | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same |
| // |
| // example: |
| // When ob.onCustomEvent executes, customEventHandler is invoked |
| // with the same scope (this): |
| // | dojo.connect(ob, "onCustomEvent", null, customEventHandler); |
| // | dojo.connect(ob, "onCustomEvent", customEventHandler); // same |
| // |
| // example: |
| // When globalEvent executes, globalHandler is invoked |
| // with the same scope (this): |
| // | dojo.connect(null, "globalEvent", null, globalHandler); |
| // | dojo.connect("globalEvent", globalHandler); // same |
| |
| // normalize arguments |
| var a=arguments, args=[], i=0; |
| // if a[0] is a String, obj was ommited |
| args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]); |
| // if the arg-after-next is a String or Function, context was NOT omitted |
| var a1 = a[i+1]; |
| args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]); |
| // absorb any additional arguments |
| for(var l=a.length; i<l; i++){ args.push(a[i]); } |
| // do the actual work |
| return dojo._connect.apply(this, args); /*Handle*/ |
| } |
| |
| // used by non-browser hostenvs. always overriden by event.js |
| dojo._connect = function(obj, event, context, method){ |
| var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method)); |
| return [obj, event, h, l]; // Handle |
| } |
| |
| dojo.disconnect = function(/*Handle*/ handle){ |
| // summary: |
| // Remove a link created by dojo.connect. |
| // description: |
| // Removes the connection between event and the method referenced by handle. |
| // handle: |
| // the return value of the dojo.connect call that created the connection. |
| if(handle && handle[0] !== undefined){ |
| dojo._disconnect.apply(this, handle); |
| // let's not keep this reference |
| delete handle[0]; |
| } |
| } |
| |
| dojo._disconnect = function(obj, event, handle, listener){ |
| listener.remove(obj, event, handle); |
| } |
| |
| // topic publish/subscribe |
| |
| dojo._topics = {}; |
| |
| dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){ |
| // summary: |
| // Attach a listener to a named topic. The listener function is invoked whenever the |
| // named topic is published (see: dojo.publish). |
| // Returns a handle which is needed to unsubscribe this listener. |
| // context: |
| // Scope in which method will be invoked, or null for default scope. |
| // method: |
| // The name of a function in context, or a function reference. This is the function that |
| // is invoked when topic is published. |
| // example: |
| // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); }; |
| // | dojo.publish("alerts", [ "read this", "hello world" ]); |
| |
| // support for 2 argument invocation (omitting context) depends on hitch |
| return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/ |
| } |
| |
| dojo.unsubscribe = function(/*Handle*/ handle){ |
| // summary: |
| // Remove a topic listener. |
| // handle: |
| // The handle returned from a call to subscribe. |
| // example: |
| // | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); }; |
| // | ... |
| // | dojo.unsubscribe(alerter); |
| if(handle){ |
| dojo._listener.remove(dojo._topics, handle[0], handle[1]); |
| } |
| } |
| |
| dojo.publish = function(/*String*/ topic, /*Array*/ args){ |
| // summary: |
| // Invoke all listener method subscribed to topic. |
| // topic: |
| // The name of the topic to publish. |
| // args: |
| // An array of arguments. The arguments will be applied |
| // to each topic subscriber (as first class parameters, via apply). |
| // example: |
| // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); }; |
| // | dojo.publish("alerts", [ "read this", "hello world" ]); |
| |
| // Note that args is an array, which is more efficient vs variable length |
| // argument list. Ideally, var args would be implemented via Array |
| // throughout the APIs. |
| var f = dojo._topics[topic]; |
| if(f){ |
| f.apply(this, args||[]); |
| } |
| } |
| |
| dojo.connectPublisher = function( /*String*/ topic, |
| /*Object|null*/ obj, |
| /*String*/ event){ |
| // summary: |
| // Ensure that everytime obj.event() is called, a message is published |
| // on the topic. Returns a handle which can be passed to |
| // dojo.disconnect() to disable subsequent automatic publication on |
| // the topic. |
| // topic: |
| // The name of the topic to publish. |
| // obj: |
| // The source object for the event function. Defaults to dojo.global |
| // if null. |
| // event: |
| // The name of the event function in obj. |
| // I.e. identifies a property obj[event]. |
| // example: |
| // | dojo.connectPublisher("/ajax/start", dojo, "xhrGet"}; |
| var pf = function(){ dojo.publish(topic, arguments); } |
| return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.Deferred"] = true; |
| dojo.provide("dojo._base.Deferred"); |
| |
| |
| dojo.Deferred = function(/*Function?*/ canceller){ |
| // summary: |
| // Encapsulates a sequence of callbacks in response to a value that |
| // may not yet be available. This is modeled after the Deferred class |
| // from Twisted <http://twistedmatrix.com>. |
| // description: |
| // JavaScript has no threads, and even if it did, threads are hard. |
| // Deferreds are a way of abstracting non-blocking events, such as the |
| // final response to an XMLHttpRequest. Deferreds create a promise to |
| // return a response a some point in the future and an easy way to |
| // register your interest in receiving that response. |
| // |
| // The most important methods for Deffered users are: |
| // |
| // * addCallback(handler) |
| // * addErrback(handler) |
| // * callback(result) |
| // * errback(result) |
| // |
| // In general, when a function returns a Deferred, users then "fill |
| // in" the second half of the contract by registering callbacks and |
| // error handlers. You may register as many callback and errback |
| // handlers as you like and they will be executed in the order |
| // registered when a result is provided. Usually this result is |
| // provided as the result of an asynchronous operation. The code |
| // "managing" the Deferred (the code that made the promise to provide |
| // an answer later) will use the callback() and errback() methods to |
| // communicate with registered listeners about the result of the |
| // operation. At this time, all registered result handlers are called |
| // *with the most recent result value*. |
| // |
| // Deferred callback handlers are treated as a chain, and each item in |
| // the chain is required to return a value that will be fed into |
| // successive handlers. The most minimal callback may be registered |
| // like this: |
| // |
| // | var d = new dojo.Deferred(); |
| // | d.addCallback(function(result){ return result; }); |
| // |
| // Perhaps the most common mistake when first using Deferreds is to |
| // forget to return a value (in most cases, the value you were |
| // passed). |
| // |
| // The sequence of callbacks is internally represented as a list of |
| // 2-tuples containing the callback/errback pair. For example, the |
| // following call sequence: |
| // |
| // | var d = new dojo.Deferred(); |
| // | d.addCallback(myCallback); |
| // | d.addErrback(myErrback); |
| // | d.addBoth(myBoth); |
| // | d.addCallbacks(myCallback, myErrback); |
| // |
| // is translated into a Deferred with the following internal |
| // representation: |
| // |
| // | [ |
| // | [myCallback, null], |
| // | [null, myErrback], |
| // | [myBoth, myBoth], |
| // | [myCallback, myErrback] |
| // | ] |
| // |
| // The Deferred also keeps track of its current status (fired). Its |
| // status may be one of three things: |
| // |
| // * -1: no value yet (initial condition) |
| // * 0: success |
| // * 1: error |
| // |
| // A Deferred will be in the error state if one of the following three |
| // conditions are met: |
| // |
| // 1. The result given to callback or errback is "instanceof" Error |
| // 2. The previous callback or errback raised an exception while |
| // executing |
| // 3. The previous callback or errback returned a value |
| // "instanceof" Error |
| // |
| // Otherwise, the Deferred will be in the success state. The state of |
| // the Deferred determines the next element in the callback sequence |
| // to run. |
| // |
| // When a callback or errback occurs with the example deferred chain, |
| // something equivalent to the following will happen (imagine |
| // that exceptions are caught and returned): |
| // |
| // | // d.callback(result) or d.errback(result) |
| // | if(!(result instanceof Error)){ |
| // | result = myCallback(result); |
| // | } |
| // | if(result instanceof Error){ |
| // | result = myErrback(result); |
| // | } |
| // | result = myBoth(result); |
| // | if(result instanceof Error){ |
| // | result = myErrback(result); |
| // | }else{ |
| // | result = myCallback(result); |
| // | } |
| // |
| // The result is then stored away in case another step is added to the |
| // callback sequence. Since the Deferred already has a value |
| // available, any new callbacks added will be called immediately. |
| // |
| // There are two other "advanced" details about this implementation |
| // that are useful: |
| // |
| // Callbacks are allowed to return Deferred instances themselves, so |
| // you can build complicated sequences of events with ease. |
| // |
| // The creator of the Deferred may specify a canceller. The canceller |
| // is a function that will be called if Deferred.cancel is called |
| // before the Deferred fires. You can use this to implement clean |
| // aborting of an XMLHttpRequest, etc. Note that cancel will fire the |
| // deferred with a CancelledError (unless your canceller returns |
| // another kind of error), so the errbacks should be prepared to |
| // handle that error for cancellable Deferreds. |
| // example: |
| // | var deferred = new dojo.Deferred(); |
| // | setTimeout(function(){ deferred.callback({success: true}); }, 1000); |
| // | return deferred; |
| // example: |
| // Deferred objects are often used when making code asynchronous. It |
| // may be easiest to write functions in a synchronous manner and then |
| // split code using a deferred to trigger a response to a long-lived |
| // operation. For example, instead of register a callback function to |
| // denote when a rendering operation completes, the function can |
| // simply return a deferred: |
| // |
| // | // callback style: |
| // | function renderLotsOfData(data, callback){ |
| // | var success = false |
| // | try{ |
| // | for(var x in data){ |
| // | renderDataitem(data[x]); |
| // | } |
| // | success = true; |
| // | }catch(e){ } |
| // | if(callback){ |
| // | callback(success); |
| // | } |
| // | } |
| // |
| // | // using callback style |
| // | renderLotsOfData(someDataObj, function(success){ |
| // | // handles success or failure |
| // | if(!success){ |
| // | promptUserToRecover(); |
| // | } |
| // | }); |
| // | // NOTE: no way to add another callback here!! |
| // example: |
| // Using a Deferred doesn't simplify the sending code any, but it |
| // provides a standard interface for callers and senders alike, |
| // providing both with a simple way to service multiple callbacks for |
| // an operation and freeing both sides from worrying about details |
| // such as "did this get called already?". With Deferreds, new |
| // callbacks can be added at any time. |
| // |
| // | // Deferred style: |
| // | function renderLotsOfData(data){ |
| // | var d = new dojo.Deferred(); |
| // | try{ |
| // | for(var x in data){ |
| // | renderDataitem(data[x]); |
| // | } |
| // | d.callback(true); |
| // | }catch(e){ |
| // | d.errback(new Error("rendering failed")); |
| // | } |
| // | return d; |
| // | } |
| // |
| // | // using Deferred style |
| // | renderLotsOfData(someDataObj).addErrback(function(){ |
| // | promptUserToRecover(); |
| // | }); |
| // | // NOTE: addErrback and addCallback both return the Deferred |
| // | // again, so we could chain adding callbacks or save the |
| // | // deferred for later should we need to be notified again. |
| // example: |
| // In this example, renderLotsOfData is syncrhonous and so both |
| // versions are pretty artificial. Putting the data display on a |
| // timeout helps show why Deferreds rock: |
| // |
| // | // Deferred style and async func |
| // | function renderLotsOfData(data){ |
| // | var d = new dojo.Deferred(); |
| // | setTimeout(function(){ |
| // | try{ |
| // | for(var x in data){ |
| // | renderDataitem(data[x]); |
| // | } |
| // | d.callback(true); |
| // | }catch(e){ |
| // | d.errback(new Error("rendering failed")); |
| // | } |
| // | }, 100); |
| // | return d; |
| // | } |
| // |
| // | // using Deferred style |
| // | renderLotsOfData(someDataObj).addErrback(function(){ |
| // | promptUserToRecover(); |
| // | }); |
| // |
| // Note that the caller doesn't have to change his code at all to |
| // handle the asynchronous case. |
| |
| this.chain = []; |
| this.id = this._nextId(); |
| this.fired = -1; |
| this.paused = 0; |
| this.results = [null, null]; |
| this.canceller = canceller; |
| this.silentlyCancelled = false; |
| }; |
| |
| dojo.extend(dojo.Deferred, { |
| /* |
| makeCalled: function(){ |
| // summary: |
| // returns a new, empty deferred, which is already in the called |
| // state. Calling callback() or errback() on this deferred will |
| // yeild an error and adding new handlers to it will result in |
| // them being called immediately. |
| var deferred = new dojo.Deferred(); |
| deferred.callback(); |
| return deferred; |
| }, |
| |
| toString: function(){ |
| var state; |
| if(this.fired == -1){ |
| state = 'unfired'; |
| }else{ |
| state = this.fired ? 'success' : 'error'; |
| } |
| return 'Deferred(' + this.id + ', ' + state + ')'; |
| }, |
| */ |
| |
| _nextId: (function(){ |
| var n = 1; |
| return function(){ return n++; }; |
| })(), |
| |
| cancel: function(){ |
| // summary: |
| // Cancels a Deferred that has not yet received a value, or is |
| // waiting on another Deferred as its value. |
| // description: |
| // If a canceller is defined, the canceller is called. If the |
| // canceller did not return an error, or there was no canceller, |
| // then the errback chain is started. |
| var err; |
| if(this.fired == -1){ |
| if(this.canceller){ |
| err = this.canceller(this); |
| }else{ |
| this.silentlyCancelled = true; |
| } |
| if(this.fired == -1){ |
| if(!(err instanceof Error)){ |
| var res = err; |
| err = new Error("Deferred Cancelled"); |
| err.dojoType = "cancel"; |
| err.cancelResult = res; |
| } |
| this.errback(err); |
| } |
| }else if( (this.fired == 0) && |
| (this.results[0] instanceof dojo.Deferred) |
| ){ |
| this.results[0].cancel(); |
| } |
| }, |
| |
| |
| _resback: function(res){ |
| // summary: |
| // The private primitive that means either callback or errback |
| this.fired = ((res instanceof Error) ? 1 : 0); |
| this.results[this.fired] = res; |
| this._fire(); |
| }, |
| |
| _check: function(){ |
| if(this.fired != -1){ |
| if(!this.silentlyCancelled){ |
| throw new Error("already called!"); |
| } |
| this.silentlyCancelled = false; |
| return; |
| } |
| }, |
| |
| callback: function(res){ |
| // summary: Begin the callback sequence with a non-error value. |
| |
| /* |
| callback or errback should only be called once on a given |
| Deferred. |
| */ |
| this._check(); |
| this._resback(res); |
| }, |
| |
| errback: function(/*Error*/res){ |
| // summary: |
| // Begin the callback sequence with an error result. |
| this._check(); |
| if(!(res instanceof Error)){ |
| res = new Error(res); |
| } |
| this._resback(res); |
| }, |
| |
| addBoth: function(/*Function||Object*/cb, /*Optional, String*/cbfn){ |
| // summary: |
| // Add the same function as both a callback and an errback as the |
| // next element on the callback sequence. This is useful for code |
| // that you want to guarantee to run, e.g. a finalizer. |
| var enclosed = dojo.hitch(cb, cbfn); |
| if(arguments.length > 2){ |
| enclosed = dojo.partial(enclosed, arguments, 2); |
| } |
| return this.addCallbacks(enclosed, enclosed); |
| }, |
| |
| addCallback: function(cb, cbfn){ |
| // summary: |
| // Add a single callback to the end of the callback sequence. |
| var enclosed = dojo.hitch(cb, cbfn); |
| if(arguments.length > 2){ |
| enclosed = dojo.partial(enclosed, arguments, 2); |
| } |
| return this.addCallbacks(enclosed, null); |
| }, |
| |
| addErrback: function(cb, cbfn){ |
| // summary: |
| // Add a single callback to the end of the callback sequence. |
| var enclosed = dojo.hitch(cb, cbfn); |
| if(arguments.length > 2){ |
| enclosed = dojo.partial(enclosed, arguments, 2); |
| } |
| return this.addCallbacks(null, enclosed); |
| }, |
| |
| addCallbacks: function(cb, eb){ |
| // summary: |
| // Add separate callback and errback to the end of the callback |
| // sequence. |
| this.chain.push([cb, eb]) |
| if(this.fired >= 0){ |
| this._fire(); |
| } |
| return this; |
| }, |
| |
| _fire: function(){ |
| // summary: |
| // Used internally to exhaust the callback sequence when a result |
| // is available. |
| var chain = this.chain; |
| var fired = this.fired; |
| var res = this.results[fired]; |
| var self = this; |
| var cb = null; |
| while( |
| (chain.length > 0) && |
| (this.paused == 0) |
| ){ |
| // Array |
| var f = chain.shift()[fired]; |
| if(!f){ continue; } |
| try{ |
| res = f(res); |
| fired = ((res instanceof Error) ? 1 : 0); |
| if(res instanceof dojo.Deferred){ |
| cb = function(res){ |
| self._resback(res); |
| // inlined from _pause() |
| self.paused--; |
| if( |
| (self.paused == 0) && |
| (self.fired >= 0) |
| ){ |
| self._fire(); |
| } |
| } |
| // inlined from _unpause |
| this.paused++; |
| } |
| }catch(err){ |
| console.debug(err); |
| fired = 1; |
| res = err; |
| } |
| } |
| this.fired = fired; |
| this.results[fired] = res; |
| if((cb)&&(this.paused)){ |
| // this is for "tail recursion" in case the dependent |
| // deferred is already fired |
| res.addBoth(cb); |
| } |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.json"] = true; |
| dojo.provide("dojo._base.json"); |
| |
| dojo.fromJson = function(/*String*/ json){ |
| // summary: |
| // evaluates the passed string-form of a JSON object |
| // json: |
| // a string literal of a JSON item, for instance: |
| // '{ "foo": [ "bar", 1, { "baz": "thud" } ] }' |
| // return: |
| // An object, the result of the evaluation |
| |
| // FIXME: should this accept mozilla's optional second arg? |
| try { |
| return eval("(" + json + ")"); |
| }catch(e){ |
| console.debug(e); |
| return json; //FIXME: peller: we should document this behavior and/or throw instead. I prefer the latter. |
| } |
| } |
| |
| dojo._escapeString = function(/*String*/str){ |
| //summary: |
| // Adds escape sequences for non-visual characters, double quote and |
| // backslash and surrounds with double quotes to form a valid string |
| // literal. |
| return ('"' + str.replace(/(["\\])/g, '\\$1') + '"' |
| ).replace(/[\f]/g, "\\f" |
| ).replace(/[\b]/g, "\\b" |
| ).replace(/[\n]/g, "\\n" |
| ).replace(/[\t]/g, "\\t" |
| ).replace(/[\r]/g, "\\r"); // string |
| } |
| |
| dojo.toJsonIndentStr = "\t"; |
| dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){ |
| // summary: |
| // Create a JSON serialization of an object. |
| // Note that this doesn't check for infinite recursion, so don't do that! |
| // |
| // it: |
| // an object to be serialized. Objects may define their own |
| // serialization via a special "__json__" or "json" function |
| // property. If a specialized serializer has been defined, it will |
| // be used as a fallback. |
| // |
| // prettyPrint: |
| // if true, we indent objects and arrays to make the output prettier. |
| // The variable dojo.toJsonIndentStr is used as the indent string |
| // -- to use something other than the default (tab), |
| // change that variable before calling dojo.toJson(). |
| // |
| // _indentStr: |
| // private variable for recursive calls when pretty printing, do not use. |
| // |
| // return: |
| // a String representing the serialized version of the passed object. |
| |
| _indentStr = _indentStr || ""; |
| var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : ""; |
| var newLine = prettyPrint ? "\n" : ""; |
| var objtype = typeof it; |
| if(objtype == "undefined"){ |
| return "undefined"; |
| } |
| if(objtype == "number" || objtype == "boolean"){ |
| return it + ""; |
| } |
| if(it === null){ |
| return "null"; |
| } |
| if(dojo.isString(it)){ |
| return dojo._escapeString(it); |
| } |
| if(it.nodeType && it.cloneNode){ // isNode |
| return ""; // FIXME: would something like outerHTML be better here? |
| } |
| // recurse |
| var recurse = arguments.callee; |
| // short-circuit for objects that support "json" serialization |
| // if they return "self" then just pass-through... |
| var newObj; |
| if(typeof it.__json__ == "function"){ |
| newObj = it.__json__(); |
| if(it !== newObj){ |
| return recurse(newObj, prettyPrint, nextIndent); |
| } |
| } |
| if(typeof it.json == "function"){ |
| newObj = it.json(); |
| if(it !== newObj){ |
| return recurse(newObj, prettyPrint, nextIndent); |
| } |
| } |
| |
| var sep = prettyPrint ? " " : ""; |
| |
| // array |
| if(dojo.isArray(it)){ |
| var res = dojo.map(it, function(obj){ |
| var val = recurse(obj, prettyPrint, nextIndent); |
| if(typeof val != "string"){ |
| val = "undefined"; |
| } |
| return newLine + nextIndent + val; |
| }); |
| return "[" + res.join("," + sep) + newLine + _indentStr + "]"; |
| } |
| /* |
| // look in the registry |
| try { |
| window.o = it; |
| newObj = dojo.json.jsonRegistry.match(it); |
| return recurse(newObj, prettyPrint, nextIndent); |
| }catch(e){ |
| // console.debug(e); |
| } |
| // it's a function with no adapter, skip it |
| */ |
| if(objtype == "function"){ |
| return null; |
| } |
| // generic object code path |
| var output = []; |
| for(var key in it){ |
| var keyStr; |
| if(typeof key == "number"){ |
| keyStr = '"' + key + '"'; |
| }else if(typeof key == "string"){ |
| keyStr = dojo._escapeString(key); |
| }else{ |
| // skip non-string or number keys |
| continue; |
| } |
| val = recurse(it[key], prettyPrint, nextIndent); |
| if(typeof val != "string"){ |
| // skip non-serializable values |
| continue; |
| } |
| // FIXME: use += on Moz!! |
| // MOW NOTE: using += is a pain because you have to account for the dangling comma... |
| output.push(newLine + nextIndent + keyStr + ":" + sep + val); |
| } |
| return "{" + output.join("," + sep) + newLine + _indentStr + "}"; |
| } |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.array"] = true; |
| |
| dojo.provide("dojo._base.array"); |
| |
| (function(){ |
| var _getParts = function(arr, obj, cb){ |
| return [ |
| (dojo.isString(arr) ? arr.split("") : arr), |
| (obj||dojo.global), |
| // FIXME: cache the anonymous functions we create here? |
| (dojo.isString(cb) ? (new Function("item", "index", "array", cb)) : cb) |
| ]; |
| } |
| |
| dojo.mixin(dojo, { |
| indexOf: function( /*Array*/ array, |
| /*Object*/ value, |
| /*Integer?*/ fromIndex, |
| /*Boolean?*/ findLast){ |
| // summary: |
| // locates the first index of the provided value in the |
| // passed array. If the value is not found, -1 is returned. |
| // description: |
| // For details on this method, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf |
| |
| var i = 0, step = 1, end = array.length; |
| if(findLast){ |
| i = end - 1; |
| step = end = -1; |
| } |
| for(i = fromIndex || i; i != end; i += step){ |
| if(array[i] == value){ return i; } |
| } |
| return -1; // Number |
| }, |
| |
| lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){ |
| // summary: |
| // locates the last index of the provided value in the passed array. |
| // If the value is not found, -1 is returned. |
| // description: |
| // For details on this method, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf |
| return dojo.indexOf(array, value, fromIndex, true); // Number |
| }, |
| |
| forEach: function(/*Array*/arr, /*Function*/callback, /*Object?*/obj){ |
| // summary: |
| // for every item in arr, call callback with that item as its |
| // only parameter. |
| // description: |
| // Return values are ignored. This function |
| // corresponds (and wraps) the JavaScript 1.6 forEach method. For |
| // more details, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach |
| |
| // match the behavior of the built-in forEach WRT empty arrs |
| if(!arr || !arr.length){ return; } |
| |
| // FIXME: there are several ways of handilng thisObject. Is |
| // dojo.global always the default context? |
| var _p = _getParts(arr, obj, callback); arr = _p[0]; |
| for(var i=0,l=_p[0].length; i<l; i++){ |
| _p[2].call(_p[1], arr[i], i, arr); |
| } |
| }, |
| |
| _everyOrSome: function(/*Boolean*/every, /*Array*/arr, /*Function*/callback, /*Object?*/obj){ |
| var _p = _getParts(arr, obj, callback); arr = _p[0]; |
| for(var i = 0, l = arr.length; i < l; i++){ |
| var result = !!_p[2].call(_p[1], arr[i], i, arr); |
| if(every ^ result){ |
| return result; // Boolean |
| } |
| } |
| return every; // Boolean |
| }, |
| |
| every: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){ |
| // summary: |
| // Determines whether or not every item in the array satisfies the |
| // condition implemented by callback. |
| // description: |
| // The parameter thisObject may be used to |
| // scope the call to callback. The function signature is derived |
| // from the JavaScript 1.6 Array.every() function. More |
| // information on this can be found here: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every |
| // example: |
| // | dojo.every([1, 2, 3, 4], function(item){ return item>1; }); |
| // returns false |
| // example: |
| // | dojo.every([1, 2, 3, 4], function(item){ return item>0; }); |
| // returns true |
| return this._everyOrSome(true, arr, callback, thisObject); // Boolean |
| }, |
| |
| some: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){ |
| // summary: |
| // Determines whether or not any item in the array satisfies the |
| // condition implemented by callback. |
| // description: |
| // The parameter thisObject may be used to |
| // scope the call to callback. The function signature is derived |
| // from the JavaScript 1.6 Array.some() function. More |
| // information on this can be found here: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some |
| // example: |
| // | dojo.some([1, 2, 3, 4], function(item){ return item>1; }); |
| // returns true |
| // example: |
| // | dojo.some([1, 2, 3, 4], function(item){ return item<1; }); |
| // returns false |
| return this._everyOrSome(false, arr, callback, thisObject); // Boolean |
| }, |
| |
| map: function(/*Array*/arr, /*Function*/func, /*Function?*/obj){ |
| // summary: |
| // applies a function to each element of an Array and creates |
| // an Array with the results |
| // description: |
| // Returns a new array constituted from the return values of |
| // passing each element of arr into unary_func. The obj parameter |
| // may be passed to enable the passed function to be called in |
| // that scope. In environments that support JavaScript 1.6, this |
| // function is a passthrough to the built-in map() function |
| // provided by Array instances. For details on this, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map |
| // example: |
| // | dojo.map([1, 2, 3, 4], function(item){ return item+1 }); |
| // returns [2, 3, 4, 5] |
| var _p = _getParts(arr, obj, func); arr = _p[0]; |
| var outArr = ((arguments[3]) ? (new arguments[3]()) : []); |
| for(var i=0;i<arr.length;++i){ |
| outArr.push(_p[2].call(_p[1], arr[i], i, arr)); |
| } |
| return outArr; // Array |
| }, |
| |
| filter: function(/*Array*/arr, /*Function*/callback, /*Object?*/obj){ |
| // summary: |
| // Returns a new Array with those items from arr that match the |
| // condition implemented by callback. ob may be used to |
| // scope the call to callback. The function signature is derived |
| // from the JavaScript 1.6 Array.filter() function. |
| // |
| // More information on the JS 1.6 API can be found here: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter |
| // example: |
| // | dojo.filter([1, 2, 3, 4], function(item){ return item>1; }); |
| // returns [2, 3, 4] |
| |
| var _p = _getParts(arr, obj, callback); arr = _p[0]; |
| var outArr = []; |
| for(var i = 0; i < arr.length; i++){ |
| if(_p[2].call(_p[1], arr[i], i, arr)){ |
| outArr.push(arr[i]); |
| } |
| } |
| return outArr; // Array |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.Color"] = true; |
| dojo.provide("dojo._base.Color"); |
| |
| |
| |
| dojo.Color = function(/*Array|String|Object*/ color){ |
| // summary: |
| // takes a named string, hex string, array of rgb or rgba values, |
| // an object with r, g, b, and a properties, or another dojo.Color object |
| if(color){ this.setColor(color); } |
| }; |
| |
| // FIXME: there's got to be a more space-efficient way to encode or discover these!! Use hex? |
| dojo.Color.named = { |
| black: [0,0,0], |
| silver: [192,192,192], |
| gray: [128,128,128], |
| white: [255,255,255], |
| maroon: [128,0,0], |
| red: [255,0,0], |
| purple: [128,0,128], |
| fuchsia: [255,0,255], |
| green: [0,128,0], |
| lime: [0,255,0], |
| olive: [128,128,0], |
| yellow: [255,255,0], |
| navy: [0,0,128], |
| blue: [0,0,255], |
| teal: [0,128,128], |
| aqua: [0,255,255] |
| }; |
| |
| |
| dojo.extend(dojo.Color, { |
| r: 255, g: 255, b: 255, a: 1, |
| _set: function(r, g, b, a){ |
| var t = this; t.r = r; t.g = g; t.b = b; t.a = a; |
| }, |
| setColor: function(/*Array|String|Object*/ color){ |
| // summary: |
| // takes a named string, hex string, array of rgb or rgba values, |
| // an object with r, g, b, and a properties, or another dojo.Color object |
| var d = dojo; |
| if(d.isString(color)){ |
| d.colorFromString(color, this); |
| }else if(d.isArray(color)){ |
| d.colorFromArray(color, this); |
| }else{ |
| this._set(color.r, color.g, color.b, color.a); |
| if(!(color instanceof d.Color)){ this.sanitize(); } |
| } |
| return this; // dojo.Color |
| }, |
| sanitize: function(){ |
| // summary: |
| // makes sure that the object has correct attributes |
| // description: |
| // the default implementation does nothing, include dojo.colors to |
| // augment it to real checks |
| return this; // dojo.Color |
| }, |
| toRgb: function(){ |
| // summary: returns 3 component array of rgb values |
| var t = this; |
| return [t.r, t.g, t.b]; // Array |
| }, |
| toRgba: function(){ |
| // summary: returns a 4 component array of rgba values |
| var t = this; |
| return [t.r, t.g, t.b, t.a]; // Array |
| }, |
| toHex: function(){ |
| // summary: returns a css color string in hexadecimal representation |
| var arr = dojo.map(["r", "g", "b"], function(x){ |
| var s = this[x].toString(16); |
| return s.length < 2 ? "0" + s : s; |
| }, this); |
| return "#" + arr.join(""); // String |
| }, |
| toCss: function(/*Boolean?*/ includeAlpha){ |
| // summary: returns a css color string in rgb(a) representation |
| var t = this, rgb = t.r + ", " + t.g + ", " + t.b; |
| return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String |
| }, |
| toString: function(){ |
| // summary: returns a visual representation of the color |
| return this.toCss(true); // String |
| } |
| }); |
| |
| dojo.blendColors = function( |
| /*dojo.Color*/ start, |
| /*dojo.Color*/ end, |
| /*Number*/ weight, |
| /*dojo.Color?*/ obj |
| ){ |
| // summary: |
| // blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend, |
| // can reuse a previously allocated dojo.Color object for the result |
| var d = dojo, t = obj || new dojo.Color(); |
| d.forEach(["r", "g", "b", "a"], function(x){ |
| t[x] = start[x] + (end[x] - start[x]) * weight; |
| if(x != "a"){ t[x] = Math.round(t[x]); } |
| }); |
| return t.sanitize(); // dojo.Color |
| }; |
| |
| dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){ |
| // summary: get rgb(a) array from css-style color declarations |
| var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/); |
| return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color |
| }; |
| |
| dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){ |
| // summary: converts a hex string with a '#' prefix to a color object. |
| // Supports 12-bit #rgb shorthand. |
| var d = dojo, t = obj || new d.Color(), |
| bits = (color.length == 4) ? 4 : 8, |
| mask = (1 << bits) - 1; |
| color = Number("0x" + color.substr(1)); |
| if(isNaN(color)){ |
| return null; // dojo.Color |
| } |
| d.forEach(["b", "g", "r"], function(x){ |
| var c = color & mask; |
| color >>= bits; |
| t[x] = bits == 4 ? 17 * c : c; |
| }); |
| t.a = 1; |
| return t; // dojo.Color |
| }; |
| |
| dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){ |
| // summary: builds a color from 1, 2, 3, or 4 element array |
| var t = obj || new dojo.Color(); |
| t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3])); |
| if(isNaN(t.a)){ t.a = 1; } |
| return t.sanitize(); // dojo.Color |
| }; |
| |
| dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){ |
| // summary: |
| // parses str for a color value. |
| // description: |
| // Acceptable input values for str may include arrays of any form |
| // accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or |
| // rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10, |
| // 10, 50)" |
| // returns: |
| // a dojo.Color object. If obj is passed, it will be the return value. |
| var a = dojo.Color.named[str]; |
| return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj); |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base"] = true; |
| dojo.provide("dojo._base"); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| if(djConfig.require){ |
| for(var x=0; x<djConfig.require.length; x++){ |
| dojo["require"](djConfig.require[x]); |
| } |
| } |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.window"] = true; |
| dojo.provide("dojo._base.window"); |
| |
| dojo._gearsObject = function(){ |
| // summary: |
| // factory method to get a Google Gears plugin instance to |
| // expose in the browser runtime environment, if present |
| var factory; |
| var results; |
| |
| var gearsObj = dojo.getObject("google.gears"); |
| if(gearsObj){ return gearsObj; } // already defined elsewhere |
| |
| if(typeof GearsFactory != "undefined"){ // Firefox |
| factory = new GearsFactory(); |
| }else{ |
| if(dojo.isIE){ |
| // IE |
| try{ |
| factory = new ActiveXObject("Gears.Factory"); |
| }catch(e){ |
| // ok to squelch; there's no gears factory. move on. |
| } |
| }else if(navigator.mimeTypes["application/x-googlegears"]){ |
| // Safari? |
| factory = document.createElement("object"); |
| factory.setAttribute("type", "application/x-googlegears"); |
| factory.setAttribute("width", 0); |
| factory.setAttribute("height", 0); |
| factory.style.display = "none"; |
| document.documentElement.appendChild(factory); |
| } |
| } |
| |
| // still nothing? |
| if(!factory){ return null; } |
| |
| // define the global objects now; don't overwrite them though if they |
| // were somehow set internally by the Gears plugin, which is on their |
| // dev roadmap for the future |
| dojo.setObject("google.gears.factory", factory); |
| return dojo.getObject("google.gears"); |
| }; |
| |
| /*===== |
| dojo.isGears = { |
| // summary: True if client is using Google Gears |
| }; |
| =====*/ |
| // see if we have Google Gears installed, and if |
| // so, make it available in the runtime environment |
| // and in the Google standard 'google.gears' global object |
| dojo.isGears = (!!dojo._gearsObject())||0; |
| |
| /*===== |
| dojo.doc = { |
| // summary: |
| // Alias for the current document. 'dojo.doc' can be modified |
| // for temporary context shifting. Also see dojo.withDoc(). |
| // description: |
| // Refer to dojo.doc rather |
| // than referring to 'window.document' to ensure your code runs |
| // correctly in managed contexts. |
| // example: |
| // n.appendChild(dojo.doc.createElement('div')); |
| } |
| =====*/ |
| dojo.doc = window["document"] || null; |
| |
| dojo.body = function(){ |
| // summary: |
| // Return the body element of the document |
| // return the body object associated with dojo.doc |
| // example: |
| // dojo.body().appendChild(dojo.doc.createElement('div')); |
| |
| // Note: document.body is not defined for a strict xhtml document |
| // Would like to memoize this, but dojo.doc can change vi dojo.withDoc(). |
| return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node |
| } |
| |
| dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){ |
| // summary: |
| // changes the behavior of many core Dojo functions that deal with |
| // namespace and DOM lookup, changing them to work in a new global |
| // context. The varibles dojo.global and dojo.doc |
| // are modified as a result of calling this function. |
| dojo.global = globalObject; |
| dojo.doc = globalDocument; |
| }; |
| |
| dojo._fireCallback = function(callback, context, cbArguments){ |
| // FIXME: should migrate to using "dojo.isString"! |
| if(context && dojo.isString(callback)){ |
| callback = context[callback]; |
| } |
| return (context ? callback.apply(context, cbArguments || [ ]) : callback()); |
| } |
| |
| dojo.withGlobal = function( /*Object*/globalObject, |
| /*Function*/callback, |
| /*Object?*/thisObject, |
| /*Array?*/cbArguments){ |
| // summary: |
| // Call callback with globalObject as dojo.global and |
| // globalObject.document as dojo.doc. If provided, globalObject |
| // will be executed in the context of object thisObject |
| // description: |
| // When callback() returns or throws an error, the dojo.global |
| // and dojo.doc will be restored to its previous state. |
| var rval; |
| var oldGlob = dojo.global; |
| var oldDoc = dojo.doc; |
| try{ |
| dojo.setContext(globalObject, globalObject.document); |
| rval = dojo._fireCallback(callback, thisObject, cbArguments); |
| }finally{ |
| dojo.setContext(oldGlob, oldDoc); |
| } |
| return rval; |
| } |
| |
| dojo.withDoc = function( /*Object*/documentObject, |
| /*Function*/callback, |
| /*Object?*/thisObject, |
| /*Array?*/cbArguments){ |
| // summary: |
| // Call callback with documentObject as dojo.doc. If provided, |
| // callback will be executed in the context of object thisObject |
| // description: |
| // When callback() returns or throws an error, the dojo.doc will |
| // be restored to its previous state. |
| var rval; |
| var oldDoc = dojo.doc; |
| try{ |
| dojo.doc = documentObject; |
| rval = dojo._fireCallback(callback, thisObject, cbArguments); |
| }finally{ |
| dojo.doc = oldDoc; |
| } |
| return rval; |
| }; |
| |
| //Register any module paths set up in djConfig. Need to do this |
| //in the hostenvs since hostenv_browser can read djConfig from a |
| //script tag's attribute. |
| (function(){ |
| var mp = djConfig["modulePaths"]; |
| if(mp){ |
| for(var param in mp){ |
| dojo.registerModulePath(param, mp[param]); |
| } |
| } |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.event"] = true; |
| dojo.provide("dojo._base.event"); |
| |
| |
| // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA |
| |
| (function(){ |
| // DOM event listener machinery |
| var del = (dojo._event_listener = { |
| add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){ |
| if(!node){return;} |
| name = del._normalizeEventName(name); |
| |
| fp = del._fixCallback(name, fp); |
| |
| var oname = name; |
| if(!dojo.isIE && (name == "mouseenter")||(name == "mouseleave")){ |
| var oname = name; |
| var ofp = fp; |
| name = (name == "mouseenter") ? "mouseover" : "mouseout"; |
| fp = function(e){ |
| // thanks ben! |
| var id = dojo.isDescendant(e.relatedTarget, node); |
| if(id == false){ |
| // e.type = oname; // FIXME: doesn't take? |
| return ofp.call(this, e); |
| } |
| } |
| } |
| |
| node.addEventListener(name, fp, false); |
| return fp; /*Handle*/ |
| }, |
| remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){ |
| // summary: |
| // clobbers the listener from the node |
| // node: |
| // DOM node to attach the event to |
| // event: |
| // the name of the handler to remove the function from |
| // handle: |
| // the handle returned from add |
| node && node.removeEventListener(del._normalizeEventName(event), handle, false); |
| }, |
| _normalizeEventName: function(/*String*/name){ |
| // Generally, name should be lower case, unless it is special |
| // somehow (e.g. a Mozilla DOM event). |
| // Remove 'on'. |
| return name.slice(0,2) =="on" ? name.slice(2) : name; |
| }, |
| _fixCallback: function(/*String*/name, fp){ |
| // By default, we only invoke _fixEvent for 'keypress' |
| // If code is added to _fixEvent for other events, we have |
| // to revisit this optimization. |
| // This also applies to _fixEvent overrides for Safari and Opera |
| // below. |
| return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); }; |
| }, |
| _fixEvent: function(evt, sender){ |
| // _fixCallback only attaches us to keypress. |
| // Switch on evt.type anyway because we might |
| // be called directly from dojo.fixEvent. |
| switch(evt.type){ |
| case "keypress": |
| del._setKeyChar(evt); |
| break; |
| } |
| return evt; |
| }, |
| _setKeyChar: function(evt){ |
| evt.keyChar = (evt.charCode ? String.fromCharCode(evt.charCode) : ''); |
| } |
| }); |
| |
| // DOM events |
| |
| dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){ |
| // summary: |
| // normalizes properties on the event object including event |
| // bubbling methods, keystroke normalization, and x/y positions |
| // evt: Event |
| // native event object |
| // sender: DOMNode |
| // node to treat as "currentTarget" |
| return del._fixEvent(evt, sender); |
| } |
| |
| dojo.stopEvent = function(/*Event*/evt){ |
| // summary: |
| // prevents propagation and clobbers the default action of the |
| // passed event |
| // evt: Event |
| // The event object. If omitted, window.event is used on IE. |
| evt.preventDefault(); |
| evt.stopPropagation(); |
| // NOTE: below, this method is overridden for IE |
| } |
| |
| // the default listener to use on dontFix nodes, overriden for IE |
| var node_listener = dojo._listener; |
| |
| // Unify connect and event listeners |
| dojo._connect = function(obj, event, context, method, dontFix){ |
| // FIXME: need a more strict test |
| var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener); |
| // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node |
| // we need the third option to provide leak prevention on broken browsers (IE) |
| var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid]; |
| // create a listener |
| var h = l.add(obj, event, dojo.hitch(context, method)); |
| // formerly, the disconnect package contained "l" directly, but if client code |
| // leaks the disconnect package (by connecting it to a node), referencing "l" |
| // compounds the problem. |
| // instead we return a listener id, which requires custom _disconnect below. |
| // return disconnect package |
| return [ obj, event, h, lid ]; |
| } |
| |
| dojo._disconnect = function(obj, event, handle, listener){ |
| ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle); |
| } |
| |
| // Constants |
| |
| // Public: client code should test |
| // keyCode against these named constants, as the |
| // actual codes can vary by browser. |
| dojo.keys = { |
| // summary: definitions for common key values |
| BACKSPACE: 8, |
| TAB: 9, |
| CLEAR: 12, |
| ENTER: 13, |
| SHIFT: 16, |
| CTRL: 17, |
| ALT: 18, |
| PAUSE: 19, |
| CAPS_LOCK: 20, |
| ESCAPE: 27, |
| SPACE: 32, |
| PAGE_UP: 33, |
| PAGE_DOWN: 34, |
| END: 35, |
| HOME: 36, |
| LEFT_ARROW: 37, |
| UP_ARROW: 38, |
| RIGHT_ARROW: 39, |
| DOWN_ARROW: 40, |
| INSERT: 45, |
| DELETE: 46, |
| HELP: 47, |
| LEFT_WINDOW: 91, |
| RIGHT_WINDOW: 92, |
| SELECT: 93, |
| NUMPAD_0: 96, |
| NUMPAD_1: 97, |
| NUMPAD_2: 98, |
| NUMPAD_3: 99, |
| NUMPAD_4: 100, |
| NUMPAD_5: 101, |
| NUMPAD_6: 102, |
| NUMPAD_7: 103, |
| NUMPAD_8: 104, |
| NUMPAD_9: 105, |
| NUMPAD_MULTIPLY: 106, |
| NUMPAD_PLUS: 107, |
| NUMPAD_ENTER: 108, |
| NUMPAD_MINUS: 109, |
| NUMPAD_PERIOD: 110, |
| NUMPAD_DIVIDE: 111, |
| F1: 112, |
| F2: 113, |
| F3: 114, |
| F4: 115, |
| F5: 116, |
| F6: 117, |
| F7: 118, |
| F8: 119, |
| F9: 120, |
| F10: 121, |
| F11: 122, |
| F12: 123, |
| F13: 124, |
| F14: 125, |
| F15: 126, |
| NUM_LOCK: 144, |
| SCROLL_LOCK: 145 |
| }; |
| |
| // IE event normalization |
| if(dojo.isIE){ |
| var _trySetKeyCode = function(e, code){ |
| try{ |
| // squelch errors when keyCode is read-only |
| // (e.g. if keyCode is ctrl or shift) |
| return (e.keyCode = code); |
| }catch(e){ |
| return 0; |
| } |
| } |
| |
| // by default, use the standard listener |
| var iel = dojo._listener; |
| // dispatcher tracking property |
| if(!djConfig._allow_leaks){ |
| // custom listener that handles leak protection for DOM events |
| node_listener = iel = dojo._ie_listener = { |
| // support handler indirection: event handler functions are |
| // referenced here. Event dispatchers hold only indices. |
| handlers: [], |
| // add a listener to an object |
| add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){ |
| source = source || dojo.global; |
| var f = source[method]; |
| if(!f||!f._listeners){ |
| var d = dojo._getIeDispatcher(); |
| // original target function is special |
| d.target = f && (ieh.push(f) - 1); |
| // dispatcher holds a list of indices into handlers table |
| d._listeners = []; |
| // redirect source to dispatcher |
| f = source[method] = d; |
| } |
| return f._listeners.push(ieh.push(listener) - 1) ; /*Handle*/ |
| }, |
| // remove a listener from an object |
| remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){ |
| var f = (source||dojo.global)[method], l = f&&f._listeners; |
| if(f && l && handle--){ |
| delete ieh[l[handle]]; |
| delete l[handle]; |
| } |
| } |
| }; |
| // alias used above |
| var ieh = iel.handlers; |
| } |
| |
| dojo.mixin(del, { |
| add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){ |
| if(!node){return;} // undefined |
| event = del._normalizeEventName(event); |
| if(event=="onkeypress"){ |
| // we need to listen to onkeydown to synthesize |
| // keypress events that otherwise won't fire |
| // on IE |
| var kd = node.onkeydown; |
| if(!kd||!kd._listeners||!kd._stealthKeydown){ |
| // we simply ignore this connection when disconnecting |
| // because it's side-effects are harmless |
| del.add(node, "onkeydown", del._stealthKeyDown); |
| // we only want one stealth listener per node |
| node.onkeydown._stealthKeydown = true; |
| } |
| } |
| return iel.add(node, event, del._fixCallback(fp)); |
| }, |
| remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){ |
| iel.remove(node, del._normalizeEventName(event), handle); |
| }, |
| _normalizeEventName: function(/*String*/eventName){ |
| // Generally, eventName should be lower case, unless it is |
| // special somehow (e.g. a Mozilla event) |
| // ensure 'on' |
| return (eventName.slice(0,2)!="on" ? "on"+eventName : eventName); |
| }, |
| _nop: function(){}, |
| _fixEvent: function(/*Event*/evt, /*DOMNode*/sender){ |
| // summary: |
| // normalizes properties on the event object including event |
| // bubbling methods, keystroke normalization, and x/y positions |
| // evt: native event object |
| // sender: node to treat as "currentTarget" |
| if(!evt){ |
| var w = (sender)&&((sender.ownerDocument || sender.document || sender).parentWindow)||window; |
| evt = w.event; |
| } |
| if(!evt){return(evt);} |
| evt.target = evt.srcElement; |
| evt.currentTarget = (sender || evt.srcElement); |
| evt.layerX = evt.offsetX; |
| evt.layerY = evt.offsetY; |
| // FIXME: scroll position query is duped from dojo.html to |
| // avoid dependency on that entire module. Now that HTML is in |
| // Base, we should convert back to something similar there. |
| var se = evt.srcElement, doc = (se && se.ownerDocument) || document; |
| // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used |
| // here rather than document.body |
| var docBody = ((dojo.isIE<6)||(doc["compatMode"]=="BackCompat")) ? doc.body : doc.documentElement; |
| var offset = dojo._getIeDocumentElementOffset(); |
| evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x; |
| evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y; |
| if(evt.type == "mouseover"){ |
| evt.relatedTarget = evt.fromElement; |
| } |
| if(evt.type == "mouseout"){ |
| evt.relatedTarget = evt.toElement; |
| } |
| evt.stopPropagation = del._stopPropagation; |
| evt.preventDefault = del._preventDefault; |
| return del._fixKeys(evt); |
| }, |
| _fixKeys: function(evt){ |
| switch(evt.type){ |
| case "keypress": |
| var c = ("charCode" in evt ? evt.charCode : evt.keyCode); |
| if (c==10){ |
| // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla |
| c=0; |
| evt.keyCode = 13; |
| }else if(c==13||c==27){ |
| c=0; // Mozilla considers ENTER and ESC non-printable |
| }else if(c==3){ |
| c=99; // Mozilla maps CTRL-BREAK to CTRL-c |
| } |
| // Mozilla sets keyCode to 0 when there is a charCode |
| // but that stops the event on IE. |
| evt.charCode = c; |
| del._setKeyChar(evt); |
| break; |
| } |
| return evt; |
| }, |
| // some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE |
| // we map those virtual key codes to ascii here |
| // not valid for all (non-US) keyboards, so maybe we shouldn't bother |
| _punctMap: { |
| 106:42, |
| 111:47, |
| 186:59, |
| 187:43, |
| 188:44, |
| 189:45, |
| 190:46, |
| 191:47, |
| 192:96, |
| 219:91, |
| 220:92, |
| 221:93, |
| 222:39 |
| }, |
| _stealthKeyDown: function(evt){ |
| // IE doesn't fire keypress for most non-printable characters. |
| // other browsers do, we simulate it here. |
| var kp = evt.currentTarget.onkeypress; |
| // only works if kp exists and is a dispatcher |
| if(!kp || !kp._listeners){ return; } |
| // munge key/charCode |
| var k=evt.keyCode; |
| // These are Windows Virtual Key Codes |
| // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp |
| var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222); |
| // synthesize keypress for most unprintables and CTRL-keys |
| if(unprintable||evt.ctrlKey){ |
| var c = (unprintable ? 0 : k); |
| if(evt.ctrlKey){ |
| if(k==3 || k==13){ |
| return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively |
| }else if(c>95 && c<106){ |
| c -= 48; // map CTRL-[numpad 0-9] to ASCII |
| }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ |
| c += 32; // map CTRL-[A-Z] to lowercase |
| }else{ |
| c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII |
| } |
| } |
| // simulate a keypress event |
| var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c}); |
| kp.call(evt.currentTarget, faux); |
| evt.cancelBubble = faux.cancelBubble; |
| evt.returnValue = faux.returnValue; |
| _trySetKeyCode(evt, faux.keyCode); |
| } |
| }, |
| // Called in Event scope |
| _stopPropagation: function(){ |
| this.cancelBubble = true; |
| }, |
| _preventDefault: function(){ |
| // Setting keyCode to 0 is the only way to prevent certain keypresses (namely |
| // ctrl-combinations that correspond to menu accelerator keys). |
| // Otoh, it prevents upstream listeners from getting this information |
| // Try to split the difference here by clobbering keyCode only for ctrl |
| // combinations. If you still need to access the key upstream, bubbledKeyCode is |
| // provided as a workaround. |
| this.bubbledKeyCode = this.keyCode; |
| if(this.ctrlKey){_trySetKeyCode(this, 0);} |
| this.returnValue = false; |
| } |
| }); |
| |
| // override stopEvent for IE |
| dojo.stopEvent = function(evt){ |
| evt = evt || window.event; |
| del._stopPropagation.call(evt); |
| del._preventDefault.call(evt); |
| } |
| } |
| |
| del._synthesizeEvent = function(evt, props){ |
| var faux = dojo.mixin({}, evt, props); |
| del._setKeyChar(faux); |
| // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault); |
| // but it throws an error when preventDefault is invoked on Safari |
| // does Event.preventDefault not support "apply" on Safari? |
| faux.preventDefault = function(){ evt.preventDefault(); }; |
| faux.stopPropagation = function(){ evt.stopPropagation(); }; |
| return faux; |
| } |
| |
| // Opera event normalization |
| if(dojo.isOpera){ |
| dojo.mixin(del, { |
| _fixEvent: function(evt, sender){ |
| switch(evt.type){ |
| case "keypress": |
| var c = evt.which; |
| if(c==3){ |
| c=99; // Mozilla maps CTRL-BREAK to CTRL-c |
| } |
| // can't trap some keys at all, like INSERT and DELETE |
| // there is no differentiating info between DELETE and ".", or INSERT and "-" |
| c = ((c<41)&&(!evt.shiftKey) ? 0 : c); |
| if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){ |
| // lowercase CTRL-[A-Z] keys |
| c += 32; |
| } |
| return del._synthesizeEvent(evt, { charCode: c }); |
| } |
| return evt; |
| } |
| }); |
| } |
| |
| // Safari event normalization |
| if(dojo.isSafari){ |
| dojo.mixin(del, { |
| _fixEvent: function(evt, sender){ |
| switch(evt.type){ |
| case "keypress": |
| var c = evt.charCode, s = evt.shiftKey, k = evt.keyCode; |
| // FIXME: This is a hack, suggest we rethink keyboard strategy. |
| // Arrow and page keys have 0 "keyCode" in keypress events.on Safari for Windows |
| k = k || identifierMap[evt.keyIdentifier] || 0; |
| if(evt.keyIdentifier=="Enter"){ |
| c = 0; // differentiate Enter from CTRL-m (both code 13) |
| }else if((evt.ctrlKey)&&(c>0)&&(c<27)){ |
| c += 96; // map CTRL-[A-Z] codes to ASCII |
| } else if (c==dojo.keys.SHIFT_TAB) { |
| c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: true |
| s = true; |
| } else { |
| c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables |
| } |
| return del._synthesizeEvent(evt, {charCode: c, shiftKey: s, keyCode: k}); |
| } |
| return evt; |
| } |
| }); |
| |
| dojo.mixin(dojo.keys, { |
| SHIFT_TAB: 25, |
| UP_ARROW: 63232, |
| DOWN_ARROW: 63233, |
| LEFT_ARROW: 63234, |
| RIGHT_ARROW: 63235, |
| F1: 63236, |
| F2: 63237, |
| F3: 63238, |
| F4: 63239, |
| F5: 63240, |
| F6: 63241, |
| F7: 63242, |
| F8: 63243, |
| F9: 63244, |
| F10: 63245, |
| F11: 63246, |
| F12: 63247, |
| PAUSE: 63250, |
| DELETE: 63272, |
| HOME: 63273, |
| END: 63275, |
| PAGE_UP: 63276, |
| PAGE_DOWN: 63277, |
| INSERT: 63302, |
| PRINT_SCREEN: 63248, |
| SCROLL_LOCK: 63249, |
| NUM_LOCK: 63289 |
| }); |
| var dk = dojo.keys, identifierMap = { "Up": dk.UP_ARROW, "Down": dk.DOWN_ARROW, "Left": dk.LEFT_ARROW, "Right": dk.RIGHT_ARROW, "PageUp": dk.PAGE_UP, "PageDown": dk.PAGE_DOWN }; |
| } |
| })(); |
| |
| if(dojo.isIE){ |
| // keep this out of the closure |
| // closing over 'iel' or 'ieh' b0rks leak prevention |
| // ls[i] is an index into the master handler array |
| dojo._getIeDispatcher = function(){ |
| return function(){ |
| var ap=Array.prototype, h=dojo._ie_listener.handlers, c=arguments.callee, ls=c._listeners, t=h[c.target]; |
| // return value comes from original target function |
| var r = t && t.apply(this, arguments); |
| // invoke listeners after target function |
| for(var i in ls){ |
| if(!(i in ap)){ |
| h[ls[i]].apply(this, arguments); |
| } |
| } |
| return r; |
| } |
| } |
| // keep this out of the closure to reduce RAM allocation |
| dojo._event_listener._fixCallback = function(fp){ |
| var f = dojo._event_listener._fixEvent; |
| return function(e){ return fp.call(this, f(e, this)); }; |
| } |
| } |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.html"] = true; |
| |
| dojo.provide("dojo._base.html"); |
| |
| // FIXME: need to add unit tests for all the semi-public methods |
| |
| try{ |
| document.execCommand("BackgroundImageCache", false, true); |
| }catch(e){ |
| // sane browsers don't have cache "issues" |
| } |
| |
| // ============================= |
| // DOM Functions |
| // ============================= |
| |
| /*===== |
| dojo.byId = function(id, doc){ |
| // summary: |
| // similar to other library's "$" function, takes a |
| // string representing a DOM id or a DomNode |
| // and returns the corresponding DomNode. If a Node is |
| // passed, this function is a no-op. Returns a |
| // single DOM node or null, working around several |
| // browser-specific bugs to do so. |
| // id: String|DOMNode |
| // DOM id or DOM Node |
| // doc: DocumentElement |
| // Document to work in. Defaults to the current value of |
| // dojo.doc. Can be used to retreive |
| // node references from other documents. |
| =====*/ |
| if(dojo.isIE || dojo.isOpera){ |
| dojo.byId = function(id, doc){ |
| if(dojo.isString(id)){ |
| var _d = doc || dojo.doc; |
| var te = _d.getElementById(id); |
| // attributes.id.value is better than just id in case the |
| // user has a name=id inside a form |
| if(te && te.attributes.id.value == id){ |
| return te; |
| }else{ |
| var eles = _d.all[id]; |
| if(!eles){ return; } |
| if(!eles.length){ return eles; } |
| // if more than 1, choose first with the correct id |
| var i=0; |
| while((te=eles[i++])){ |
| if(te.attributes.id.value == id){ return te; } |
| } |
| } |
| }else{ |
| return id; // DomNode |
| } |
| } |
| }else{ |
| dojo.byId = function(id, doc){ |
| if(dojo.isString(id)){ |
| return (doc || dojo.doc).getElementById(id); |
| }else{ |
| return id; // DomNode |
| } |
| } |
| } |
| /*===== |
| } |
| =====*/ |
| |
| (function(){ |
| /* |
| dojo.createElement = function(obj, parent, position){ |
| // TODO: need to finish this! |
| } |
| */ |
| |
| var _destroyContainer = null; |
| dojo._destroyElement = function(/*String||DomNode*/node){ |
| // summary: |
| // removes node from its parent, clobbers it and all of its |
| // children. |
| // node: |
| // the element to be destroyed, either as an ID or a reference |
| |
| node = dojo.byId(node); |
| try{ |
| if(!_destroyContainer){ |
| _destroyContainer = document.createElement("div"); |
| } |
| _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); |
| // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature |
| _destroyContainer.innerHTML = ""; |
| }catch(e){ |
| /* squelch */ |
| } |
| }; |
| |
| dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ |
| // summary: |
| // Returns true if node is a descendant of ancestor |
| // node: id or node reference to test |
| // ancestor: id or node reference of potential parent to test against |
| try{ |
| node = dojo.byId(node); |
| ancestor = dojo.byId(ancestor); |
| while(node){ |
| if(node === ancestor){ |
| return true; // Boolean |
| } |
| node = node.parentNode; |
| } |
| }catch(e){ return -1; /* squelch */ } |
| return false; // Boolean |
| }; |
| |
| dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){ |
| // summary: enable or disable selection on a node |
| // node: |
| // id or reference to node |
| // selectable: |
| node = dojo.byId(node); |
| if(dojo.isMozilla){ |
| node.style.MozUserSelect = selectable ? "" : "none"; |
| }else if(dojo.isKhtml){ |
| node.style.KhtmlUserSelect = selectable ? "auto" : "none"; |
| }else if(dojo.isIE){ |
| node.unselectable = selectable ? "" : "on"; |
| dojo.query("*", node).forEach(function(descendant){ |
| descendant.unselectable = selectable ? "" : "on"; |
| }); |
| } |
| //FIXME: else? Opera? |
| }; |
| |
| var _insertBefore = function(/*Node*/node, /*Node*/ref){ |
| ref.parentNode.insertBefore(node, ref); |
| return true; // boolean |
| } |
| |
| var _insertAfter = function(/*Node*/node, /*Node*/ref){ |
| // summary: |
| // Try to insert node after ref |
| var pn = ref.parentNode; |
| if(ref == pn.lastChild){ |
| pn.appendChild(node); |
| }else{ |
| return _insertBefore(node, ref.nextSibling); // boolean |
| } |
| return true; // boolean |
| } |
| |
| dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String|Number*/position){ |
| // summary: |
| // attempt to insert node in relation to ref based on position |
| // node: |
| // id or reference to node to place relative to refNode |
| // refNode: |
| // id or reference of node to use as basis for placement |
| // position: |
| // string noting the position of node relative to refNode or a |
| // number indicating the location in the childNodes collection of |
| // refNode. Accepted string values are: |
| // * before |
| // * after |
| // * first |
| // * last |
| // "first" and "last" indicate positions as children of refNode. |
| |
| // FIXME: need to write tests for this!!!! |
| if(!node || !refNode || position === undefined){ |
| return false; // boolean |
| } |
| node = dojo.byId(node); |
| refNode = dojo.byId(refNode); |
| if(typeof position == "number"){ |
| var cn = refNode.childNodes; |
| if((position == 0 && cn.length == 0) || |
| cn.length == position){ |
| refNode.appendChild(node); return true; |
| } |
| if(position == 0){ |
| return _insertBefore(node, refNode.firstChild); |
| } |
| return _insertAfter(node, cn[position-1]); |
| } |
| switch(position.toLowerCase()){ |
| case "before": |
| return _insertBefore(node, refNode); // boolean |
| case "after": |
| return _insertAfter(node, refNode); // boolean |
| case "first": |
| if(refNode.firstChild){ |
| return _insertBefore(node, refNode.firstChild); // boolean |
| }else{ |
| refNode.appendChild(node); |
| return true; // boolean |
| } |
| break; |
| default: // aka: last |
| refNode.appendChild(node); |
| return true; // boolean |
| } |
| } |
| |
| // Box functions will assume this model. |
| // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode. |
| // Can be set to change behavior of box setters. |
| |
| // can be either: |
| // "border-box" |
| // "content-box" (default) |
| dojo.boxModel = "content-box"; |
| |
| // We punt per-node box mode testing completely. |
| // If anybody cares, we can provide an additional (optional) unit |
| // that overrides existing code to include per-node box sensitivity. |
| |
| // Opera documentation claims that Opera 9 uses border-box in BackCompat mode. |
| // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box. |
| // IIRC, earlier versions of Opera did in fact use border-box. |
| // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault. |
| |
| if(dojo.isIE /*|| dojo.isOpera*/){ |
| var _dcm = document.compatMode; |
| // client code may have to adjust if compatMode varies across iframes |
| dojo.boxModel = (_dcm=="BackCompat")||(_dcm=="QuirksMode")||(dojo.isIE<6) ? "border-box" : "content-box"; |
| } |
| |
| // ============================= |
| // Style Functions |
| // ============================= |
| |
| // getComputedStyle drives most of the style code. |
| // Wherever possible, reuse the returned object. |
| // |
| // API functions below that need to access computed styles accept an |
| // optional computedStyle parameter. |
| // |
| // If this parameter is omitted, the functions will call getComputedStyle themselves. |
| // |
| // This way, calling code can access computedStyle once, and then pass the reference to |
| // multiple API functions. |
| // |
| // This is a faux declaration to take pity on the doc tool |
| |
| /*===== |
| dojo.getComputedStyle = function(node){ |
| // summary: |
| // Returns a "computed style" object. |
| // description: |
| // get "computed style" object which can be used to gather |
| // information about the current state of the rendered node. |
| // |
| // Note that this may behave differently on different browsers. |
| // Values may have different formats and value encodings across |
| // browsers. |
| // |
| // Use the dojo.style() method for more consistent (pixelized) |
| // return values. |
| // node: DOMNode |
| // a reference to a DOM node. Does NOT support taking an |
| // ID string for speed reasons. |
| // example: |
| // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth; |
| return; // CSS2Properties |
| } |
| =====*/ |
| |
| var gcs, dv = document.defaultView; |
| if(dojo.isSafari){ |
| gcs = function(/*DomNode*/node){ |
| var s = dv.getComputedStyle(node, null); |
| if(!s && node.style){ |
| node.style.display = ""; |
| s = dv.getComputedStyle(node, null); |
| } |
| return s || {}; |
| }; |
| }else if(dojo.isIE){ |
| gcs = function(node){ |
| return node.currentStyle; |
| }; |
| }else{ |
| gcs = function(node){ |
| return dv.getComputedStyle(node, null); |
| }; |
| } |
| dojo.getComputedStyle = gcs; |
| |
| if(!dojo.isIE){ |
| dojo._toPixelValue = function(element, value){ |
| // style values can be floats, client code may want |
| // to round for integer pixels. |
| return parseFloat(value) || 0; |
| } |
| }else{ |
| dojo._toPixelValue = function(element, avalue){ |
| if(!avalue){ return 0; } |
| // on IE7, medium is usually 4 pixels |
| if(avalue=="medium"){ return 4; } |
| // style values can be floats, client code may |
| // want to round this value for integer pixels. |
| if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); } |
| with(element){ |
| var sLeft = style.left; |
| var rsLeft = runtimeStyle.left; |
| runtimeStyle.left = currentStyle.left; |
| try{ |
| // 'avalue' may be incompatible with style.left, which can cause IE to throw |
| // this has been observed for border widths using "thin", "medium", "thick" constants |
| // those particular constants could be trapped by a lookup |
| // but perhaps there are more |
| style.left = avalue; |
| avalue = style.pixelLeft; |
| }catch(e){ |
| avalue = 0; |
| } |
| style.left = sLeft; |
| runtimeStyle.left = rsLeft; |
| } |
| return avalue; |
| } |
| } |
| |
| // FIXME: there opacity quirks on FF that we haven't ported over. Hrm. |
| /*===== |
| dojo._getOpacity = function(node){ |
| // summary: |
| // Returns the current opacity of the passed node as a |
| // floating-point value between 0 and 1. |
| // node: DomNode |
| // a reference to a DOM node. Does NOT support taking an |
| // ID string for speed reasons. |
| // return: Number between 0 and 1 |
| } |
| =====*/ |
| |
| dojo._getOpacity = (dojo.isIE ? function(node){ |
| try{ |
| return (node.filters.alpha.opacity / 100); // Number |
| }catch(e){ |
| return 1; // Number |
| } |
| } : function(node){ |
| return dojo.getComputedStyle(node).opacity; |
| } |
| ); |
| |
| /*===== |
| dojo._setOpacity = function(node, opacity){ |
| // summary: |
| // set the opacity of the passed node portably. Returns the |
| // new opacity of the node. |
| // node: DOMNode |
| // a reference to a DOM node. Does NOT support taking an |
| // ID string for performance reasons. |
| // opacity: Number |
| // A Number between 0 and 1. 0 specifies transparent. |
| // return: Number between 0 and 1 |
| } |
| =====*/ |
| |
| dojo._setOpacity = (dojo.isIE ? function(/*DomNode*/node, /*Number*/opacity){ |
| if(opacity == 1){ |
| // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so remove it altogether (bug #2661) |
| node.style.cssText = node.style.cssText.replace(/FILTER:[^;]*;?/i, ""); |
| if(node.nodeName.toLowerCase() == "tr"){ |
| dojo.query("> td", node).forEach(function(i){ |
| i.style.cssText = i.style.cssText.replace(/FILTER:[^;]*;?/i, ""); |
| }); |
| } |
| }else{ |
| var o = "Alpha(Opacity="+(opacity*100)+")"; |
| node.style.filter = o; |
| } |
| if(node.nodeName.toLowerCase() == "tr"){ |
| dojo.query("> td", node).forEach(function(i){ |
| i.style.filter = o; |
| }); |
| } |
| return opacity; |
| } : function(node, opacity){ |
| return node.style.opacity = opacity; |
| } |
| ); |
| |
| var _pixelNamesCache = { |
| width: true, height: true, left: true, top: true |
| }; |
| var _toStyleValue = function(node, type, value){ |
| type = type.toLowerCase(); |
| if(_pixelNamesCache[type] === true){ |
| return dojo._toPixelValue(node, value) |
| }else if(_pixelNamesCache[type] === false){ |
| return value; |
| }else{ |
| if(dojo.isOpera && type == "cssText"){ |
| // FIXME: add workaround for #2855 here |
| } |
| if( |
| (type.indexOf("margin") >= 0) || |
| // (type.indexOf("border") >= 0) || |
| (type.indexOf("padding") >= 0) || |
| (type.indexOf("width") >= 0) || |
| (type.indexOf("height") >= 0) || |
| (type.indexOf("max") >= 0) || |
| (type.indexOf("min") >= 0) || |
| (type.indexOf("offset") >= 0) |
| ){ |
| _pixelNamesCache[type] = true; |
| return dojo._toPixelValue(node, value) |
| }else{ |
| _pixelNamesCache[type] = false; |
| return value; |
| } |
| } |
| } |
| |
| // public API |
| |
| dojo.style = function(/*DomNode|String*/ node, /*String*/style, /*String?*/value){ |
| // summary: |
| // gets or sets a style property on node. If 2 arguments are |
| // passed, acts as a getter. If value is passed, acts as a setter |
| // for the property. |
| // node: |
| // id or reference to node to get/set style for |
| // style: |
| // the style property to set in DOM-accessor format |
| // ("borderWidth", not "border-width"). |
| // value: |
| // optional. If passed, sets value on the node for style, handling |
| // cross-browser concerns. |
| var n=dojo.byId(node), args=arguments.length, op=(style=="opacity"); |
| if(args==3){ |
| return op ? dojo._setOpacity(n, value) : n.style[style] = value; /*Number*/ |
| } |
| if(args==2 && op){ |
| return dojo._getOpacity(n); |
| } |
| var s = dojo.getComputedStyle(n); |
| return (args == 1) ? s : _toStyleValue(n, style, s[style]); /* CSS2Properties||String||Number */ |
| } |
| |
| // ============================= |
| // Box Functions |
| // ============================= |
| |
| dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){ |
| // summary: |
| // Returns object with special values specifically useful for node |
| // fitting. |
| // l/t = left/top padding (respectively) |
| // w = the total of the left and right padding |
| // h = the total of the top and bottom padding |
| // If 'node' has position, l/t forms the origin for child nodes. |
| // The w/h are used for calculating boxes. |
| // Normally application code will not need to invoke this |
| // directly, and will use the ...box... functions instead. |
| var |
| s=computedStyle||gcs(n), |
| px=dojo._toPixelValue, |
| l=px(n, s.paddingLeft), |
| t=px(n, s.paddingTop); |
| return { |
| l: l, |
| t: t, |
| w: l+px(n, s.paddingRight), |
| h: t+px(n, s.paddingBottom) |
| }; |
| } |
| |
| dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){ |
| // summary: |
| // returns an object with properties useful for noting the border |
| // dimensions. |
| // l/t = the sum of left/top border (respectively) |
| // w = the sum of the left and right border |
| // h = the sum of the top and bottom border |
| // The w/h are used for calculating boxes. |
| // Normally application code will not need to invoke this |
| // directly, and will use the ...box... functions instead. |
| var |
| ne='none', |
| px=dojo._toPixelValue, |
| s=computedStyle||gcs(n), |
| bl=(s.borderLeftStyle!=ne ? px(n, s.borderLeftWidth) : 0), |
| bt=(s.borderTopStyle!=ne ? px(n, s.borderTopWidth) : 0); |
| return { |
| l: bl, |
| t: bt, |
| w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0), |
| h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0) |
| }; |
| } |
| |
| dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){ |
| // summary: |
| // returns object with properties useful for box fitting with |
| // regards to padding. |
| // l/t = the sum of left/top padding and left/top border (respectively) |
| // w = the sum of the left and right padding and border |
| // h = the sum of the top and bottom padding and border |
| // The w/h are used for calculating boxes. |
| // Normally application code will not need to invoke this |
| // directly, and will use the ...box... functions instead. |
| var |
| s=computedStyle||gcs(n), |
| p=dojo._getPadExtents(n, s), |
| b=dojo._getBorderExtents(n, s); |
| return { |
| l: p.l + b.l, |
| t: p.t + b.t, |
| w: p.w + b.w, |
| h: p.h + b.h |
| }; |
| } |
| |
| dojo._getMarginExtents = function(n, computedStyle){ |
| // summary: |
| // returns object with properties useful for box fitting with |
| // regards to box margins (i.e., the outer-box). |
| // l/t = marginLeft, marginTop, respectively |
| // w = total width, margin inclusive |
| // h = total height, margin inclusive |
| // The w/h are used for calculating boxes. |
| // Normally application code will not need to invoke this |
| // directly, and will use the ...box... functions instead. |
| var |
| s=computedStyle||gcs(n), |
| px=dojo._toPixelValue, |
| l=px(n, s.marginLeft), |
| t=px(n, s.marginTop), |
| r=px(n, s.marginRight), |
| b=px(n, s.marginBottom); |
| if (dojo.isSafari && (s.position != "absolute")){ |
| // FIXME: Safari's version of the computed right margin |
| // is the space between our right edge and the right edge |
| // of our offsetParent. |
| // What we are looking for is the actual margin value as |
| // determined by CSS. |
| // Hack solution is to assume left/right margins are the same. |
| r = l; |
| } |
| return { |
| l: l, |
| t: t, |
| w: l+r, |
| h: t+b |
| }; |
| } |
| |
| // Box getters work in any box context because offsetWidth/clientWidth |
| // are invariant wrt box context |
| // |
| // They do *not* work for display: inline objects that have padding styles |
| // because the user agent ignores padding (it's bogus styling in any case) |
| // |
| // Be careful with IMGs because they are inline or block depending on |
| // browser and browser mode. |
| |
| // Although it would be easier to read, there are not separate versions of |
| // _getMarginBox for each browser because: |
| // 1. the branching is not expensive |
| // 2. factoring the shared code wastes cycles (function call overhead) |
| // 3. duplicating the shared code wastes bytes |
| |
| dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){ |
| // summary: |
| // returns an object that encodes the width, height, left and top |
| // positions of the node's margin box. |
| var s = computedStyle||gcs(node), me = dojo._getMarginExtents(node, s); |
| var l = node.offsetLeft - me.l, t = node.offsetTop - me.t; |
| if(dojo.isMoz){ |
| // Mozilla: |
| // If offsetParent has a computed overflow != visible, the offsetLeft is decreased |
| // by the parent's border. |
| // We don't want to compute the parent's style, so instead we examine node's |
| // computed left/top which is more stable. |
| var sl = parseFloat(s.left), st = parseFloat(s.top); |
| if(!isNaN(sl) && !isNaN(st)){ |
| l = sl, t = st; |
| }else{ |
| // If child's computed left/top are not parseable as a number (e.g. "auto"), we |
| // have no choice but to examine the parent's computed style. |
| var p = node.parentNode; |
| if(p && p.style){ |
| var pcs = gcs(p); |
| if(pcs.overflow != "visible"){ |
| var be = dojo._getBorderExtents(p, pcs); |
| l += be.l, t += be.t; |
| } |
| } |
| } |
| }else if(dojo.isOpera){ |
| // On Opera, offsetLeft includes the parent's border |
| var p = node.parentNode; |
| if(p){ |
| var be = dojo._getBorderExtents(p); |
| l -= be.l, t -= be.t; |
| } |
| } |
| return { |
| l: l, |
| t: t, |
| w: node.offsetWidth + me.w, |
| h: node.offsetHeight + me.h |
| }; |
| } |
| |
| dojo._getContentBox = function(node, computedStyle){ |
| // summary: |
| // Returns an object that encodes the width, height, left and top |
| // positions of the node's content box, irrespective of the |
| // current box model. |
| |
| // clientWidth/Height are important since the automatically account for scrollbars |
| // fallback to offsetWidth/Height for special cases (see #3378) |
| var s=computedStyle||gcs(node), pe=dojo._getPadExtents(node, s), be=dojo._getBorderExtents(node, s), w=node.clientWidth, h; |
| if(!w){ |
| w=node.offsetWidth, h=node.offsetHeight; |
| }else{ |
| h=node.clientHeight, be.w = be.h = 0; |
| } |
| // On Opera, offsetLeft includes the parent's border |
| if(dojo.isOpera){ pe.l += be.l; pe.t += be.t; }; |
| return { |
| l: pe.l, |
| t: pe.t, |
| w: w - pe.w - be.w, |
| h: h - pe.h - be.h |
| }; |
| } |
| |
| dojo._getBorderBox = function(node, computedStyle){ |
| var s=computedStyle||gcs(node), pe=dojo._getPadExtents(node, s), cb=dojo._getContentBox(node, s); |
| return { |
| l: cb.l - pe.l, |
| t: cb.t - pe.t, |
| w: cb.w + pe.w, |
| h: cb.h + pe.h |
| }; |
| } |
| |
| // Box setters depend on box context because interpretation of width/height styles |
| // vary wrt box context. |
| // |
| // The value of dojo.boxModel is used to determine box context. |
| // dojo.boxModel can be set directly to change behavior. |
| // |
| // Beware of display: inline objects that have padding styles |
| // because the user agent ignores padding (it's a bogus setup anyway) |
| // |
| // Be careful with IMGs because they are inline or block depending on |
| // browser and browser mode. |
| // |
| // Elements other than DIV may have special quirks, like built-in |
| // margins or padding, or values not detectable via computedStyle. |
| // In particular, margins on TABLE do not seems to appear |
| // at all in computedStyle on Mozilla. |
| |
| dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){ |
| // summary: |
| // sets width/height/left/top in the current (native) box-model |
| // dimentions. Uses the unit passed in u. |
| // node: DOM Node reference. Id string not supported for performance reasons. |
| // l: optional. left offset from parent. |
| // t: optional. top offset from parent. |
| // w: optional. width in current box model. |
| // h: optional. width in current box model. |
| // u: optional. unit measure to use for other measures. Defaults to "px". |
| u = u || "px"; |
| with(node.style){ |
| if(!isNaN(l)){ left = l+u; } |
| if(!isNaN(t)){ top = t+u; } |
| if(w>=0){ width = w+u; } |
| if(h>=0){ height = h+u; } |
| } |
| } |
| |
| dojo._usesBorderBox = function(/*DomNode*/node){ |
| // summary: |
| // True if the node uses border-box layout. |
| |
| // We could test the computed style of node to see if a particular box |
| // has been specified, but there are details and we choose not to bother. |
| var n = node.tagName; |
| // For whatever reason, TABLE and BUTTON are always border-box by default. |
| // If you have assigned a different box to either one via CSS then |
| // box functions will break. |
| return dojo.boxModel=="border-box" || n=="TABLE" || n=="BUTTON"; // boolean |
| } |
| |
| dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){ |
| // summary: |
| // Sets the size of the node's contents, irrespective of margins, |
| // padding, or borders. |
| var bb = dojo._usesBorderBox(node); |
| if(bb){ |
| var pb = dojo._getPadBorderExtents(node, computedStyle); |
| if(widthPx>=0){ widthPx += pb.w; } |
| if(heightPx>=0){ heightPx += pb.h; } |
| } |
| dojo._setBox(node, NaN, NaN, widthPx, heightPx); |
| } |
| |
| dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx, |
| /*Number?*/widthPx, /*Number?*/heightPx, |
| /*Object*/computedStyle){ |
| // summary: |
| // sets the size of the node's margin box and placement |
| // (left/top), irrespective of box model. Think of it as a |
| // passthrough to dojo._setBox that handles box-model vagaries for |
| // you. |
| |
| var s = computedStyle || dojo.getComputedStyle(node); |
| // Some elements have special padding, margin, and box-model settings. |
| // To use box functions you may need to set padding, margin explicitly. |
| // Controlling box-model is harder, in a pinch you might set dojo.boxModel. |
| var bb=dojo._usesBorderBox(node), |
| pb=bb ? _nilExtents : dojo._getPadBorderExtents(node, s), |
| mb=dojo._getMarginExtents(node, s); |
| if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); } |
| if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); } |
| dojo._setBox(node, leftPx, topPx, widthPx, heightPx); |
| } |
| |
| var _nilExtents = { l:0, t:0, w:0, h:0 }; |
| |
| // public API |
| |
| dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){ |
| // summary: |
| // getter/setter for the margin-box of node. |
| // description: |
| // Returns an object in the expected format of box (regardless |
| // if box is passed). The object might look like: |
| // { l: 50, t: 200, w: 300: h: 150 } |
| // for a node offset from its parent 50px to the left, 200px from |
| // the top with a margin width of 300px and a margin-height of |
| // 150px. |
| // node: |
| // id or reference to DOM Node to get/set box for |
| // box: |
| // optional. If passed, denotes that dojo.marginBox() should |
| // update/set the margin box for node. Box is an object in the |
| // above format. All properties are optional if passed. |
| var n=dojo.byId(node), s=gcs(n), b=box; |
| return !b ? dojo._getMarginBox(n, s) : dojo._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object |
| } |
| |
| dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){ |
| // summary: |
| // getter/setter for the content-box of node. |
| // description: |
| // Returns an object in the expected format of box (regardless if box is passed). |
| // The object might look like: |
| // { l: 50, t: 200, w: 300: h: 150 } |
| // for a node offset from its parent 50px to the left, 200px from |
| // the top with a content width of 300px and a content-height of |
| // 150px. Note that the content box may have a much larger border |
| // or margin box, depending on the box model currently in use and |
| // CSS values set/inherited for node. |
| // node: |
| // id or reference to DOM Node to get/set box for |
| // box: |
| // optional. If passed, denotes that dojo.contentBox() should |
| // update/set the content box for node. Box is an object in the |
| // above format. All properties are optional if passed. |
| var n=dojo.byId(node), s=gcs(n), b=box; |
| return !b ? dojo._getContentBox(n, s) : dojo._setContentSize(n, b.w, b.h, s); // Object |
| } |
| |
| // ============================= |
| // Positioning |
| // ============================= |
| |
| var _sumAncestorProperties = function(node, prop){ |
| if(!(node = (node||0).parentNode)){return 0}; |
| var val, retVal = 0, _b = dojo.body(); |
| while(node && node.style){ |
| if(gcs(node).position == "fixed"){ |
| return 0; |
| } |
| val = node[prop]; |
| if(val){ |
| retVal += val - 0; |
| // opera and khtml #body & #html has the same values, we only |
| // need one value |
| if(node == _b){ break; } |
| } |
| node = node.parentNode; |
| } |
| return retVal; // integer |
| } |
| |
| dojo._docScroll = function(){ |
| var _b = dojo.body(); |
| var _w = dojo.global; |
| var de = dojo.doc.documentElement; |
| return { |
| y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0), |
| x: (_w.pageXOffset || dojo._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0) |
| }; |
| }; |
| |
| dojo._isBodyLtr = function(){ |
| //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values |
| return !("_bodyLtr" in dojo) ? |
| dojo._bodyLtr = dojo.getComputedStyle(dojo.body()).direction == "ltr" : |
| dojo._bodyLtr; // Boolean |
| } |
| |
| dojo._getIeDocumentElementOffset = function(){ |
| // summary |
| // The following values in IE contain an offset: |
| // event.clientX |
| // event.clientY |
| // node.getBoundingClientRect().left |
| // node.getBoundingClientRect().top |
| // But other position related values do not contain this offset, such as |
| // node.offsetLeft, node.offsetTop, node.style.left and node.style.top. |
| // The offset is always (2, 2) in LTR direction. When the body is in RTL |
| // direction, the offset counts the width of left scroll bar's width. |
| // This function computes the actual offset. |
| |
| //NOTE: assumes we're being called in an IE browser |
| |
| var de = dojo.doc.documentElement; |
| if(dojo.isIE >= 7){ |
| return {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}; // Object |
| }else{ |
| // IE 6.0 |
| return {x: dojo._isBodyLtr() || window.parent == window ? |
| de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft, |
| y: de.clientTop}; // Object |
| } |
| }; |
| |
| dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){ |
| // In RTL direction, scrollLeft should be a negative value, but IE |
| // returns a positive one. All codes using documentElement.scrollLeft |
| // must call this function to fix this error, otherwise the position |
| // will offset to right when there is a horizontal scrollbar. |
| if(dojo.isIE && !dojo._isBodyLtr()){ |
| var de = dojo.doc.documentElement; |
| return scrollLeft + de.clientWidth - de.scrollWidth; // Integer |
| } |
| return scrollLeft; // Integer |
| } |
| |
| dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){ |
| // summary: |
| // Gets the absolute position of the passed element based on the |
| // document itself. Returns an object of the form: |
| // { x: 100, y: 300 } |
| // if includeScroll is passed, the x and y values will include any |
| // document offsets that may affect the position relative to the |
| // viewport. |
| |
| // FIXME: need to decide in the brave-new-world if we're going to be |
| // margin-box or border-box. |
| var ownerDocument = node.ownerDocument; |
| var ret = { |
| x: 0, |
| y: 0 |
| }; |
| var hasScroll = false; |
| |
| // targetBoxType == "border-box" |
| var db = dojo.body(); |
| if(dojo.isIE){ |
| var client = node.getBoundingClientRect(); |
| var offset = dojo._getIeDocumentElementOffset(); |
| ret.x = client.left - offset.x; |
| ret.y = client.top - offset.y; |
| }else if(ownerDocument["getBoxObjectFor"]){ |
| // mozilla |
| var bo = ownerDocument.getBoxObjectFor(node); |
| ret.x = bo.x - _sumAncestorProperties(node, "scrollLeft"); |
| ret.y = bo.y - _sumAncestorProperties(node, "scrollTop"); |
| }else{ |
| if(node["offsetParent"]){ |
| hasScroll = true; |
| var endNode; |
| // in Safari, if the node is an absolutely positioned child of |
| // the body and the body has a margin the offset of the child |
| // and the body contain the body's margins, so we need to end |
| // at the body |
| // FIXME: getting contrary results to the above in latest WebKit. |
| if(dojo.isSafari && |
| //(node.style.getPropertyValue("position") == "absolute") && |
| (gcs(node).position == "absolute") && |
| (node.parentNode == db)){ |
| endNode = db; |
| }else{ |
| endNode = db.parentNode; |
| } |
| if(node.parentNode != db){ |
| var nd = node; |
| if(dojo.isOpera || (dojo.isSafari >= 3)){ nd = db; } |
| ret.x -= _sumAncestorProperties(nd, "scrollLeft"); |
| ret.y -= _sumAncestorProperties(nd, "scrollTop"); |
| } |
| var curnode = node; |
| do{ |
| var n = curnode["offsetLeft"]; |
| //FIXME: ugly hack to workaround the submenu in |
| //popupmenu2 does not shown up correctly in opera. |
| //Someone have a better workaround? |
| if(!dojo.isOpera || n>0){ |
| ret.x += isNaN(n) ? 0 : n; |
| } |
| var m = curnode["offsetTop"]; |
| ret.y += isNaN(m) ? 0 : m; |
| curnode = curnode.offsetParent; |
| }while((curnode != endNode)&&curnode); |
| }else if(node["x"]&&node["y"]){ |
| ret.x += isNaN(node.x) ? 0 : node.x; |
| ret.y += isNaN(node.y) ? 0 : node.y; |
| } |
| } |
| // account for document scrolling |
| // if offsetParent is used, ret value already includes scroll position |
| // so we may have to actually remove that value if !includeScroll |
| if(hasScroll || includeScroll){ |
| var scroll = dojo._docScroll(); |
| var m = hasScroll ? (!includeScroll ? -1 : 0) : 1; |
| ret.y += m*scroll.y; |
| ret.x += m*scroll.x; |
| } |
| |
| return ret; // object |
| } |
| |
| // FIXME: need a setter for coords or a moveTo!! |
| dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){ |
| // summary: |
| // Returns an object that measures margin box width/height and |
| // absolute positioning data from dojo._abs(). Return value will |
| // be in the form: |
| // { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 } |
| // does not act as a setter. If includeScroll is passed, the x and |
| // y params are affected as one would expect in dojo._abs(). |
| var n=dojo.byId(node), s=gcs(n), mb=dojo._getMarginBox(n, s); |
| var abs = dojo._abs(n, includeScroll); |
| mb.x = abs.x; |
| mb.y = abs.y; |
| return mb; |
| } |
| |
| // ============================= |
| // Element attribute Functions |
| // ============================= |
| |
| var _fixAttrName = function(/*String*/name){ |
| switch(name.toLowerCase()){ |
| case "tabindex": |
| // Internet Explorer will only set or remove tabindex |
| // if it is spelled "tabIndex" |
| return dojo.isIE ? "tabIndex" : "tabindex"; |
| default: |
| return name; |
| } |
| } |
| |
| // non-deprecated HTML4 attributes with default values |
| // http://www.w3.org/TR/html401/index/attributes.html |
| // FF and Safari will return the default values if you |
| // access the attributes via a property but not |
| // via getAttribute() |
| var _attrProps = { |
| colspan: "colSpan", |
| enctype: "enctype", |
| frameborder: "frameborder", |
| method: "method", |
| rowspan: "rowSpan", |
| scrolling: "scrolling", |
| shape: "shape", |
| span: "span", |
| type: "type", |
| valuetype: "valueType" |
| } |
| |
| var _hasAttr = function(/*DomNode*/node, /*String*/name){ |
| var attr = node.getAttributeNode(name); |
| return attr ? attr.specified : false; |
| } |
| |
| dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){ |
| // summary: |
| // Returns true if the requested attribute is specified on the |
| // given element, and false otherwise. |
| // node: |
| // id or reference to the element to check |
| // name: |
| // the name of the attribute |
| // returns: |
| // true if the requested attribute is specified on the |
| // given element, and false otherwise |
| return _hasAttr(dojo.byId(node), _fixAttrName(name)); // boolean |
| } |
| |
| dojo.attr = function(/*DomNode|String*/node, /*String*/name, /*String?*/value){ |
| // summary: |
| // Gets or sets an attribute on an HTML element. |
| // description: |
| // If 2 arguments are passed, acts as a getter. |
| // If a third argument is passed, acts as a setter. |
| // node: |
| // id or reference to the element to get or set the attribute on |
| // name: |
| // the name of the attribute to get or set |
| // value: |
| // the value for the attribute (optional) |
| // returns: |
| // when used as a getter, the value of the requested attribute |
| // or null if that attribute does not have a specified or |
| // default value; |
| // when user as a setter, undefined |
| node = dojo.byId(node); |
| name = _fixAttrName(name); |
| if(arguments.length == 3){ |
| node.setAttribute(name, value); |
| return undefined; |
| }else{ |
| // should we access this attribute via a property or |
| // via getAttribute()? |
| var prop = _attrProps[name.toLowerCase()]; |
| if(prop){ |
| return node[prop]; |
| }else{ |
| return _hasAttr(node, name) ? node.getAttribute(name) : null; |
| } |
| } |
| } |
| |
| dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){ |
| // summary: |
| // Removes an attribute from an HTML element. |
| // node: |
| // id or reference to the element to remove the attribute from |
| // name: |
| // the name of the attribute to remove |
| dojo.byId(node).removeAttribute(_fixAttrName(name)); |
| } |
| })(); |
| |
| // ============================= |
| // (CSS) Class Functions |
| // ============================= |
| |
| dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){ |
| // summary: |
| // Returns whether or not the specified classes are a portion of the |
| // class list currently applied to the node. |
| return ((" "+dojo.byId(node).className+" ").indexOf(" "+classStr+" ") >= 0); // Boolean |
| }; |
| |
| dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){ |
| // summary: |
| // Adds the specified classes to the end of the class list on the |
| // passed node. |
| node = dojo.byId(node); |
| var cls = node.className; |
| if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){ |
| node.className = cls + (cls ? ' ' : '') + classStr; |
| } |
| }; |
| |
| dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){ |
| // summary: Removes the specified classes from node. |
| node = dojo.byId(node); |
| var t = dojo.trim((" " + node.className + " ").replace(" " + classStr + " ", " ")); |
| if(node.className != t){ node.className = t; } |
| }; |
| |
| dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){ |
| // summary: |
| // Adds a class to node if not present, or removes if present. |
| // Pass a boolean condition if you want to explicitly add or remove. |
| // condition: |
| // If passed, true means to add the class, false means to remove. |
| if(condition === undefined){ |
| condition = !dojo.hasClass(node, classStr); |
| } |
| dojo[condition ? "addClass" : "removeClass"](node, classStr); |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.NodeList"] = true; |
| dojo.provide("dojo._base.NodeList"); |
| |
| |
| |
| (function(){ |
| |
| var d = dojo; |
| |
| var tnl = function(arr){ |
| arr.constructor = dojo.NodeList; |
| dojo._mixin(arr, dojo.NodeList.prototype); |
| return arr; |
| } |
| |
| dojo.NodeList = function(){ |
| // summary: |
| // dojo.NodeList is as subclass of Array which adds syntactic |
| // sugar for chaining, common iteration operations, animation, |
| // and node manipulation. NodeLists are most often returned as |
| // the result of dojo.query() calls. |
| // example: |
| // create a node list from a node |
| // | new dojo.NodeList(dojo.byId("foo")); |
| |
| return tnl(Array.apply(null, arguments)); |
| } |
| |
| dojo.NodeList._wrap = tnl; |
| |
| dojo.extend(dojo.NodeList, { |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods |
| |
| // FIXME: handle return values for #3244 |
| // http://trac.dojotoolkit.org/ticket/3244 |
| |
| // FIXME: |
| // need to wrap or implement: |
| // join (perhaps w/ innerHTML/outerHTML overload for toString() of items?) |
| // reduce |
| // reduceRight |
| |
| slice: function(/*===== begin, end =====*/){ |
| // summary: |
| // Returns a new NodeList, maintaining this one in place |
| // description: |
| // This method behaves exactly like the Array.slice method |
| // with the caveat that it returns a dojo.NodeList and not a |
| // raw Array. For more details, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice |
| // begin: Integer |
| // Can be a positive or negative integer, with positive |
| // integers noting the offset to begin at, and negative |
| // integers denoting an offset from the end (i.e., to the left |
| // of the end) |
| // end: Integer? |
| // Optional parameter to describe what position relative to |
| // the NodeList's zero index to end the slice at. Like begin, |
| // can be positive or negative. |
| var a = dojo._toArray(arguments); |
| return tnl(a.slice.apply(this, a)); |
| }, |
| |
| splice: function(/*===== index, howmany, item =====*/){ |
| // summary: |
| // Returns a new NodeList, manipulating this NodeList based on |
| // the arguments passed, potentially splicing in new elements |
| // at an offset, optionally deleting elements |
| // description: |
| // This method behaves exactly like the Array.splice method |
| // with the caveat that it returns a dojo.NodeList and not a |
| // raw Array. For more details, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice |
| // index: Integer |
| // begin can be a positive or negative integer, with positive |
| // integers noting the offset to begin at, and negative |
| // integers denoting an offset from the end (i.e., to the left |
| // of the end) |
| // howmany: Integer? |
| // Optional parameter to describe what position relative to |
| // the NodeList's zero index to end the slice at. Like begin, |
| // can be positive or negative. |
| // item: Object...? |
| // Any number of optional parameters may be passed in to be |
| // spliced into the NodeList |
| // returns: |
| // dojo.NodeList |
| var a = dojo._toArray(arguments); |
| return tnl(a.splice.apply(this, a)); |
| }, |
| |
| concat: function(/*===== item =====*/){ |
| // summary: |
| // Returns a new NodeList comprised of items in this NodeList |
| // as well as items passed in as parameters |
| // description: |
| // This method behaves exactly like the Array.concat method |
| // with the caveat that it returns a dojo.NodeList and not a |
| // raw Array. For more details, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat |
| // item: Object...? |
| // Any number of optional parameters may be passed in to be |
| // spliced into the NodeList |
| // returns: |
| // dojo.NodeList |
| var a = dojo._toArray(arguments, 0, [this]); |
| return tnl(a.concat.apply([], a)); |
| }, |
| |
| indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){ |
| // summary: |
| // see dojo.indexOf(). The primary difference is that the acted-on |
| // array is implicitly this NodeList |
| // value: |
| // The value to search for. |
| // fromIndex: |
| // The loction to start searching from. Optional. Defaults to 0. |
| // description: |
| // For more details on the behavior of indexOf, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf |
| // returns: |
| // Positive Integer or 0 for a match, -1 of not found. |
| return d.indexOf(this, value, fromIndex); // Integer |
| }, |
| |
| lastIndexOf: function(/*===== value, fromIndex =====*/){ |
| // summary: |
| // see dojo.lastIndexOf(). The primary difference is that the |
| // acted-on array is implicitly this NodeList |
| // description: |
| // For more details on the behavior of lastIndexOf, see: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf |
| // value: Object |
| // The value to search for. |
| // fromIndex: Integer? |
| // The loction to start searching from. Optional. Defaults to 0. |
| // returns: |
| // Positive Integer or 0 for a match, -1 of not found. |
| return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer |
| }, |
| |
| every: function(/*Function*/callback, /*Object?*/thisObject){ |
| // summary: |
| // see dojo.every() and: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every |
| // Takes the same structure of arguments and returns as |
| // dojo.every() with the caveat that the passed array is |
| // implicitly this NodeList |
| return d.every(this, callback, thisObject); // Boolean |
| }, |
| |
| some: function(/*Function*/callback, /*Object?*/thisObject){ |
| // summary: |
| // see dojo.some() and: |
| // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some |
| // Takes the same structure of arguments and returns as |
| // dojo.some() with the caveat that the passed array is |
| // implicitly this NodeList |
| return d.some(this, callback, thisObject); // Boolean |
| }, |
| |
| map: function(/*Function*/ func, /*Function?*/ obj){ |
| // summary: |
| // see dojo.map(). The primary difference is that the acted-on |
| // array is implicitly this NodeList and the return is a |
| // dojo.NodeList (a subclass of Array) |
| |
| return d.map(this, func, obj, d.NodeList); // dojo.NodeList |
| }, |
| |
| forEach: function(callback, thisObj){ |
| // summary: |
| // see dojo.forEach(). The primary difference is that the acted-on |
| // array is implicitly this NodeList |
| |
| d.forEach(this, callback, thisObj); |
| return this; // dojo.NodeList non-standard return to allow easier chaining |
| }, |
| |
| // custom methods |
| |
| coords: function(){ |
| // summary: |
| // Returns the box objects all elements in a node list as |
| // an Array (*not* a NodeList) |
| |
| return d.map(this, d.coords); |
| }, |
| |
| style: function(/*===== property, value =====*/){ |
| // summary: |
| // gets or sets the CSS property for every element in the NodeList |
| // property: String |
| // the CSS property to get/set, in JavaScript notation |
| // ("lineHieght" instead of "line-height") |
| // value: String? |
| // optional. The value to set the property to |
| // return: |
| // if no value is passed, the result is an array of strings. |
| // If a value is passed, the return is this NodeList |
| var aa = d._toArray(arguments, 0, [null]); |
| var s = this.map(function(i){ |
| aa[0] = i; |
| return d.style.apply(d, aa); |
| }); |
| return (arguments.length > 1) ? this : s; // String||dojo.NodeList |
| }, |
| |
| styles: function(/*===== property, value =====*/){ |
| // summary: |
| // Deprecated. Use NodeList.style instead. Will be removed in |
| // Dojo 1.1. Gets or sets the CSS property for every element |
| // in the NodeList |
| // property: String |
| // the CSS property to get/set, in JavaScript notation |
| // ("lineHieght" instead of "line-height") |
| // value: String? |
| // optional. The value to set the property to |
| // return: |
| // if no value is passed, the result is an array of strings. |
| // If a value is passed, the return is this NodeList |
| d.deprecated("NodeList.styles", "use NodeList.style instead", "1.1"); |
| return this.style.apply(this, arguments); |
| }, |
| |
| addClass: function(/*String*/ className){ |
| // summary: |
| // adds the specified class to every node in the list |
| // |
| this.forEach(function(i){ d.addClass(i, className); }); |
| return this; |
| }, |
| |
| removeClass: function(/*String*/ className){ |
| this.forEach(function(i){ d.removeClass(i, className); }); |
| return this; |
| }, |
| |
| // FIXME: toggleClass()? connectPublisher()? connectRunOnce()? |
| |
| place: function(/*String||Node*/ queryOrNode, /*String*/ position){ |
| // summary: |
| // places elements of this node list relative to the first element matched |
| // by queryOrNode. Returns the original NodeList. |
| // queryOrNode: |
| // may be a string representing any valid CSS3 selector or a DOM node. |
| // In the selector case, only the first matching element will be used |
| // for relative positioning. |
| // position: |
| // can be one of: |
| // "last"||"end" (default) |
| // "first||"start" |
| // "before" |
| // "after" |
| // or an offset in the childNodes property |
| var item = d.query(queryOrNode)[0]; |
| position = position||"last"; |
| |
| for(var x=0; x<this.length; x++){ |
| d.place(this[x], item, position); |
| } |
| return this; // dojo.NodeList |
| }, |
| |
| connect: function(/*String*/ methodName, /*Object||Function||String*/ objOrFunc, /*String?*/ funcName){ |
| // summary: |
| // attach event handlers to every item of the NodeList. Uses dojo.connect() |
| // so event properties are normalized |
| // methodName: |
| // the name of the method to attach to. For DOM events, this should be |
| // the lower-case name of the event |
| // objOrFunc: |
| // if 2 arguments are passed (methodName, objOrFunc), objOrFunc should |
| // reference a function or be the name of the function in the global |
| // namespace to attach. If 3 arguments are provided |
| // (methodName, objOrFunc, funcName), objOrFunc must be the scope to |
| // locate the bound function in |
| // funcName: |
| // optional. A string naming the function in objOrFunc to bind to the |
| // event. May also be a function reference. |
| // example: |
| // add an onclick handler to every button on the page |
| // | dojo.query("onclick", function(e){ |
| // | console.debug("clicked!"); |
| // | }); |
| // example: |
| // attach foo.bar() to every odd div's onmouseover |
| // | dojo.query("div:nth-child(odd)").onclick("onmouseover", foo, "bar"); |
| this.forEach(function(item){ |
| d.connect(item, methodName, objOrFunc, funcName); |
| }); |
| return this; // dojo.NodeList |
| }, |
| |
| orphan: function(/*String?*/ simpleFilter){ |
| // summary: |
| // removes elements in this list that match the simple |
| // filter from their parents and returns them as a new |
| // NodeList. |
| // simpleFilter: single-expression CSS filter |
| // return: a dojo.NodeList of all of the elements orpahned |
| var orphans = (simpleFilter) ? d._filterQueryResult(this, simpleFilter) : this; |
| orphans.forEach(function(item){ |
| if(item["parentNode"]){ |
| item.parentNode.removeChild(item); |
| } |
| }); |
| return orphans; // dojo.NodeList |
| }, |
| |
| adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){ |
| // summary: |
| // places any/all elements in queryOrListOrNode at a |
| // position relative to the first element in this list. |
| // Returns a dojo.NodeList of the adopted elements. |
| // queryOrListOrNode: |
| // a DOM node or a query string or a query result. |
| // Represents the nodes to be adopted relative to the |
| // first element of this NodeList. |
| // position: |
| // optional. One of: |
| // "last"||"end" (default) |
| // "first||"start" |
| // "before" |
| // "after" |
| // or an offset in the childNodes property |
| var item = this[0]; |
| return d.query(queryOrListOrNode).forEach(function(ai){ d.place(ai, item, (position||"last")); }); // dojo.NodeList |
| }, |
| |
| // FIXME: do we need this? |
| query: function(/*String*/ queryStr){ |
| // summary: |
| // Returns a new, flattened NodeList. Elements of the new list |
| // satisfy the passed query but use elements of the |
| // current NodeList as query roots. |
| |
| queryStr = queryStr||""; |
| |
| // FIXME: probably slow |
| var ret = d.NodeList(); |
| this.forEach(function(item){ |
| d.query(queryStr, item).forEach(function(subItem){ |
| if(typeof subItem != "undefined"){ |
| ret.push(subItem); |
| } |
| }); |
| }); |
| return ret; // dojo.NodeList |
| }, |
| |
| filter: function(/*String*/ simpleQuery){ |
| // summary: |
| // "masks" the built-in javascript filter() method to support |
| // passing a simple string filter in addition to supporting |
| // filtering function objects. |
| // example: |
| // "regular" JS filter syntax as exposed in dojo.filter: |
| // | dojo.query("*").filter(function(item){ |
| // | // highlight every paragraph |
| // | return (item.nodeName == "p"); |
| // | }).styles("backgroundColor", "yellow"); |
| // example: |
| // the same filtering using a CSS selector |
| // | dojo.query("*").filter("p").styles("backgroundColor", "yellow"); |
| |
| var items = this; |
| var _a = arguments; |
| var r = d.NodeList(); |
| var rp = function(t){ |
| if(typeof t != "undefined"){ |
| r.push(t); |
| } |
| } |
| if(d.isString(simpleQuery)){ |
| items = d._filterQueryResult(this, _a[0]); |
| if(_a.length == 1){ |
| // if we only got a string query, pass back the filtered results |
| return items; // dojo.NodeList |
| } |
| // if we got a callback, run it over the filtered items |
| d.forEach(d.filter(items, _a[1], _a[2]), rp); |
| return r; // dojo.NodeList |
| } |
| // handle the (callback, [thisObject]) case |
| d.forEach(d.filter(items, _a[0], _a[1]), rp); |
| return r; // dojo.NodeList |
| |
| }, |
| |
| /* |
| // FIXME: should this be "copyTo" and include parenting info? |
| clone: function(){ |
| // summary: |
| // creates node clones of each element of this list |
| // and returns a new list containing the clones |
| }, |
| */ |
| |
| addContent: function(/*String*/ content, /*String||Integer?*/ position){ |
| // summary: |
| // add a node or some HTML as a string to every item in the list. |
| // Returns the original list. |
| // content: |
| // the HTML in string format to add at position to every item |
| // position: |
| // One of: |
| // "last"||"end" (default) |
| // "first||"start" |
| // "before" |
| // "after" |
| // or an integer offset in the childNodes property |
| var ta = d.doc.createElement("span"); |
| if(d.isString(content)){ |
| ta.innerHTML = content; |
| }else{ |
| ta.appendChild(content); |
| } |
| var ct = ((position == "first")||(position == "after")) ? "lastChild" : "firstChild"; |
| this.forEach(function(item){ |
| var tn = ta.cloneNode(true); |
| while(tn[ct]){ |
| d.place(tn[ct], item, position); |
| } |
| }); |
| return this; // dojo.NodeList |
| } |
| }); |
| |
| // syntactic sugar for DOM events |
| d.forEach([ |
| "blur", "click", "keydown", "keypress", "keyup", "mousedown", "mouseenter", |
| "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup" |
| ], function(evt){ |
| var _oe = "on"+evt; |
| dojo.NodeList.prototype[_oe] = function(a, b){ |
| return this.connect(_oe, a, b); |
| } |
| // FIXME: should these events trigger publishes? |
| /* |
| return (a ? this.connect(_oe, a, b) : |
| this.forEach(function(n){ |
| // FIXME: |
| // listeners get buried by |
| // addEventListener and can't be dug back |
| // out to be triggered externally. |
| // see: |
| // http://developer.mozilla.org/en/docs/DOM:element |
| |
| console.debug(n, evt, _oe); |
| |
| // FIXME: need synthetic event support! |
| var _e = { target: n, faux: true, type: evt }; |
| // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt }); |
| try{ n[evt](_e); }catch(e){ console.debug(e); } |
| try{ n[_oe](_e); }catch(e){ console.debug(e); } |
| }) |
| ); |
| } |
| */ |
| } |
| ); |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.query"] = true; |
| dojo.provide("dojo._base.query"); |
| |
| |
| /* |
| dojo.query() architectural overview: |
| |
| dojo.query is a relatively full-featured CSS3 query library. It is |
| designed to take any valid CSS3 selector and return the nodes matching |
| the selector. To do this quickly, it processes queries in several |
| steps, applying caching where profitable. |
| |
| The steps (roughly in reverse order of the way they appear in the code): |
| 1.) check to see if we already have a "query dispatcher" |
| - if so, use that with the given parameterization. Skip to step 4. |
| 2.) attempt to determine which branch to dispatch the query to: |
| - JS (optimized DOM iteration) |
| - xpath (for browsers that support it and where it's fast) |
| - native (not available in any browser yet) |
| 3.) tokenize and convert to executable "query dispatcher" |
| - this is where the lion's share of the complexity in the |
| system lies. In the DOM version, the query dispatcher is |
| assembled as a chain of "yes/no" test functions pertaining to |
| a section of a simple query statement (".blah:nth-child(odd)" |
| but not "div div", which is 2 simple statements). Individual |
| statement dispatchers are cached (to prevent re-definition) |
| as are entire dispatch chains (to make re-execution of the |
| same query fast) |
| - in the xpath path, tokenization yeilds a concatenation of |
| parameterized xpath selectors. As with the DOM version, both |
| simple selector blocks and overall evaluators are cached to |
| prevent re-defintion |
| 4.) the resulting query dispatcher is called in the passed scope (by default the top-level document) |
| - for DOM queries, this results in a recursive, top-down |
| evaluation of nodes based on each simple query section |
| - xpath queries can, thankfully, be executed in one shot |
| 5.) matched nodes are pruned to ensure they are unique |
| */ |
| |
| /*===== |
| // summary: |
| // returns nodes which match the given CSS3 selector, searching the |
| // entire document by default but optionally taking a node to scope |
| // the search by. Returns an instance of dojo.NodeList. |
| // description: |
| // dojo.query() is the swiss army knife of DOM node manipulation in |
| // Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's |
| // "$" function, dojo.query provides robust, high-performance |
| // CSS-based node selector support with the option of scoping searches |
| // to a particular sub-tree of a document. |
| // |
| // Supported Selectors: |
| // -------------------- |
| // |
| // dojo.query() supports a rich set of CSS3 selectors, including: |
| // |
| // * class selectors (e.g., ".foo") |
| // * node type selectors like "span" |
| // * " " descendant selectors |
| // * ">" child element selectors |
| // * "#foo" style ID selectors |
| // * "*" universal selector |
| // * attribute queries: |
| // * "[foo]" attribute presence selector |
| // * "[foo='bar']" attribute value exact match |
| // * "[foo~='bar']" attribute value list item match |
| // * "[foo^='bar']" attribute start match |
| // * "[foo$='bar']" attribute end match |
| // * "[foo*='bar']" attribute substring match |
| // * ":first-child", ":last-child" positional selectors |
| // * ":nth-child(n)", ":nth-child(2n+1)" style positional calculations |
| // * ":nth-child(even)", ":nth-child(odd)" positional selectors |
| // * ":not(...)" negation pseudo selectors |
| // |
| // Any legal combination of those selector types as per the CSS 3 sepc |
| // will work with dojo.query(), including compound selectors ("," |
| // delimited). Very complex and useful searches can be constructed |
| // with this palette of selectors and when combined with functions for |
| // maniplation presented by dojo.NodeList, many types of DOM |
| // manipulation operations become very straightforward. |
| // |
| // Unsupported Selectors: |
| // -------------------- |
| // |
| // While dojo.query handles many CSS3 selectors, some fall outside of |
| // what's resaonable for a programmatic node querying engine to |
| // handle. Currently unsupported selectors include: |
| // |
| // * namespace-differentiated selectors of any form |
| // * "~", the immediately preceeded-by sibling selector |
| // * "+", the preceeded-by sibling selector |
| // * all "::" pseduo-element selectors |
| // * certain pseduo-selectors which don't get a lot of day-to-day use: |
| // * :root, :lang(), :target, :focus |
| // * all visual and state selectors: |
| // * :root, :active, :hover, :visisted, :link, :enabled, :disabled, :checked |
| // * :*-of-type pseudo selectors |
| // |
| // dojo.query and XML Documents: |
| // ----------------------------- |
| // FIXME |
| // |
| // NOTE: elementsById is not currently supported |
| // NOTE: ignores xpath-ish queries for now |
| // |
| // query: String |
| // The CSS3 expression to match against. For details on the syntax of |
| // CSS3 selectors, see: |
| // http://www.w3.org/TR/css3-selectors/#selectors |
| // root: String|DOMNode? |
| // A node (or string ID of a node) to scope the search from. Optional. |
| // returns: |
| // An instance of dojo.NodeList. Many methods are available on |
| // NodeLists for searching, iterating, manipulating, and handling |
| // events on the matched nodes in the returned list. |
| =====*/ |
| |
| ;(function(){ |
| // define everything in a closure for compressability reasons. "d" is an |
| // alias to "dojo" since it's so frequently used. This seems a |
| // transformation that the build system could perform on a per-file basis. |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Utility code |
| //////////////////////////////////////////////////////////////////////// |
| |
| var d = dojo; |
| var childNodesName = dojo.isIE ? "children" : "childNodes"; |
| |
| var getQueryParts = function(query){ |
| // summary: state machine for query tokenization |
| if(query.charAt(query.length-1) == ">"){ |
| query += " *" |
| } |
| query += " "; // ensure that we terminate the state machine |
| |
| var ts = function(s, e){ |
| return d.trim(query.slice(s, e)); |
| } |
| |
| // the overall data graph of the full query, as represented by queryPart objects |
| var qparts = []; |
| // state keeping vars |
| var inBrackets = -1; |
| var inParens = -1; |
| var inMatchFor = -1; |
| var inPseudo = -1; |
| var inClass = -1; |
| var inId = -1; |
| var inTag = -1; |
| var lc = ""; // the last character |
| var cc = ""; // the current character |
| var pStart; |
| // iteration vars |
| var x = 0; // index in the query |
| var ql = query.length; |
| var currentPart = null; // data structure representing the entire clause |
| var _cp = null; // the current pseudo or attr matcher |
| |
| var endTag = function(){ |
| if(inTag >= 0){ |
| var tv = (inTag == x) ? null : ts(inTag, x).toLowerCase(); |
| currentPart[ (">~+".indexOf(tv) < 0)? "tag" : "oper" ] = tv; |
| inTag = -1; |
| } |
| } |
| |
| var endId = function(){ |
| if(inId >= 0){ |
| currentPart.id = ts(inId, x).replace(/\\/g, ""); |
| inId = -1; |
| } |
| } |
| |
| var endClass = function(){ |
| if(inClass >= 0){ |
| currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, "")); |
| inClass = -1; |
| } |
| } |
| |
| var endAll = function(){ |
| endId(); endTag(); endClass(); |
| } |
| |
| for(; lc=cc, cc=query.charAt(x),x<ql; x++){ |
| if(lc == "\\"){ continue; } |
| if(!currentPart){ |
| // NOTE: I hate all this alloc, but it's shorter than writing tons of if's |
| pStart = x; |
| currentPart = { |
| query: null, |
| pseudos: [], |
| attrs: [], |
| classes: [], |
| tag: null, |
| oper: null, |
| id: null |
| }; |
| inTag = x; |
| } |
| |
| if(inBrackets >= 0){ |
| // look for a the close first |
| if(cc == "]"){ |
| if(!_cp.attr){ |
| _cp.attr = ts(inBrackets+1, x); |
| }else{ |
| _cp.matchFor = ts((inMatchFor||inBrackets+1), x); |
| } |
| var cmf = _cp.matchFor; |
| if(cmf){ |
| if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){ |
| _cp.matchFor = cmf.substring(1, cmf.length-1); |
| } |
| } |
| currentPart.attrs.push(_cp); |
| _cp = null; // necessaray? |
| inBrackets = inMatchFor = -1; |
| }else if(cc == "="){ |
| var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : ""; |
| _cp.type = addToCc+cc; |
| _cp.attr = ts(inBrackets+1, x-addToCc.length); |
| inMatchFor = x+1; |
| } |
| // now look for other clause parts |
| }else if(inParens >= 0){ |
| if(cc == ")"){ |
| if(inPseudo >= 0){ |
| _cp.value = ts(inParens+1, x); |
| } |
| inPseudo = inParens = -1; |
| } |
| }else if(cc == "#"){ |
| endAll(); |
| inId = x+1; |
| }else if(cc == "."){ |
| endAll(); |
| inClass = x; |
| }else if(cc == ":"){ |
| endAll(); |
| inPseudo = x; |
| }else if(cc == "["){ |
| endAll(); |
| inBrackets = x; |
| _cp = { |
| /*===== |
| attr: null, type: null, matchFor: null |
| =====*/ |
| }; |
| }else if(cc == "("){ |
| if(inPseudo >= 0){ |
| _cp = { |
| name: ts(inPseudo+1, x), |
| value: null |
| } |
| currentPart.pseudos.push(_cp); |
| } |
| inParens = x; |
| }else if(cc == " " && lc != cc){ |
| // note that we expect the string to be " " terminated |
| endAll(); |
| if(inPseudo >= 0){ |
| currentPart.pseudos.push({ name: ts(inPseudo+1, x) }); |
| } |
| currentPart.hasLoops = ( |
| currentPart.pseudos.length || |
| currentPart.attrs.length || |
| currentPart.classes.length ); |
| currentPart.query = ts(pStart, x); |
| currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*"); |
| qparts.push(currentPart); |
| currentPart = null; |
| } |
| } |
| return qparts; |
| }; |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| // XPath query code |
| //////////////////////////////////////////////////////////////////////// |
| |
| // this array is a lookup used to generate an attribute matching function. |
| // There is a similar lookup/generator list for the DOM branch with similar |
| // calling semantics. |
| var xPathAttrs = { |
| "*=": function(attr, value){ |
| return "[contains(@"+attr+", '"+ value +"')]"; |
| }, |
| "^=": function(attr, value){ |
| return "[starts-with(@"+attr+", '"+ value +"')]"; |
| }, |
| "$=": function(attr, value){ |
| return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']"; |
| }, |
| "~=": function(attr, value){ |
| return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]"; |
| }, |
| "|=": function(attr, value){ |
| return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]"; |
| }, |
| "=": function(attr, value){ |
| return "[@"+attr+"='"+ value +"']"; |
| } |
| }; |
| |
| // takes a list of attribute searches, the overall query, a function to |
| // generate a default matcher, and a closure-bound method for providing a |
| // matching function that generates whatever type of yes/no distinguisher |
| // the query method needs. The method is a bit tortured and hard to read |
| // because it needs to be used in both the XPath and DOM branches. |
| var handleAttrs = function( attrList, |
| query, |
| getDefault, |
| handleMatch){ |
| d.forEach(query.attrs, function(attr){ |
| var matcher; |
| // type, attr, matchFor |
| if(attr.type && attrList[attr.type]){ |
| matcher = attrList[attr.type](attr.attr, attr.matchFor); |
| }else if(attr.attr.length){ |
| matcher = getDefault(attr.attr); |
| } |
| if(matcher){ handleMatch(matcher); } |
| }); |
| } |
| |
| var buildPath = function(query){ |
| var xpath = "."; |
| var qparts = getQueryParts(d.trim(query)); |
| while(qparts.length){ |
| var tqp = qparts.shift(); |
| var prefix; |
| // FIXME: need to add support for ~ and + |
| if(tqp.oper == ">"){ |
| prefix = "/"; |
| // prefix = "/child::node()"; |
| tqp = qparts.shift(); |
| }else{ |
| prefix = "//"; |
| // prefix = "/descendant::node()" |
| } |
| |
| // get the tag name (if any) |
| |
| xpath += prefix + tqp.tag; |
| |
| // check to see if it's got an id. Needs to come first in xpath. |
| if(tqp.id){ |
| xpath += "[@id='"+tqp.id+"'][1]"; |
| } |
| |
| d.forEach(tqp.classes, function(cn){ |
| var cnl = cn.length; |
| var padding = " "; |
| if(cn.charAt(cnl-1) == "*"){ |
| padding = ""; cn = cn.substr(0, cnl-1); |
| } |
| xpath += |
| "[contains(concat(' ',@class,' '), ' "+ |
| cn + padding + "')]"; |
| }); |
| |
| handleAttrs(xPathAttrs, tqp, |
| function(condition){ |
| return "[@"+condition+"]"; |
| }, |
| function(matcher){ |
| xpath += matcher; |
| } |
| ); |
| |
| // FIXME: need to implement pseudo-class checks!! |
| }; |
| return xpath; |
| }; |
| |
| var _xpathFuncCache = {}; |
| var getXPathFunc = function(path){ |
| if(_xpathFuncCache[path]){ |
| return _xpathFuncCache[path]; |
| } |
| |
| var doc = d.doc; |
| // var parent = d.body(); // FIXME |
| // FIXME: don't need to memoize. The closure scope handles it for us. |
| var xpath = buildPath(path); |
| |
| var tf = function(parent){ |
| // XPath query strings are memoized. |
| var ret = []; |
| var xpathResult; |
| try{ |
| xpathResult = doc.evaluate(xpath, parent, null, |
| // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null); |
| XPathResult.ANY_TYPE, null); |
| }catch(e){ |
| console.debug("failure in exprssion:", xpath, "under:", parent); |
| console.debug(e); |
| } |
| var result = xpathResult.iterateNext(); |
| while(result){ |
| ret.push(result); |
| result = xpathResult.iterateNext(); |
| } |
| return ret; |
| } |
| return _xpathFuncCache[path] = tf; |
| }; |
| |
| /* |
| d.xPathMatch = function(query){ |
| // XPath based DOM query system. Handles a small subset of CSS |
| // selectors, subset is identical to the non-XPath version of this |
| // function. |
| |
| // FIXME: need to add support for alternate roots |
| return getXPathFunc(query)(); |
| } |
| */ |
| |
| //////////////////////////////////////////////////////////////////////// |
| // DOM query code |
| //////////////////////////////////////////////////////////////////////// |
| |
| var _filtersCache = {}; |
| var _simpleFiltersCache = {}; |
| |
| // the basic building block of the yes/no chaining system. agree(f1, f2) |
| // generates a new function which returns the boolean results of both of |
| // the passed functions to a single logical-anded result. |
| var agree = function(first, second){ |
| if(!first){ return second; } |
| if(!second){ return first; } |
| |
| return function(){ |
| return first.apply(window, arguments) && second.apply(window, arguments); |
| } |
| } |
| |
| var _filterDown = function(element, queryParts, matchArr, idx){ |
| var nidx = idx+1; |
| var isFinal = (queryParts.length == nidx); |
| var tqp = queryParts[idx]; |
| |
| // see if we can constrain our next level to direct children |
| if(tqp.oper == ">"){ |
| var ecn = element[childNodesName]; |
| if(!ecn || !ecn.length){ |
| return; |
| } |
| nidx++; |
| isFinal = (queryParts.length == nidx); |
| // kinda janky, too much array alloc |
| var tf = getFilterFunc(queryParts[idx+1]); |
| // for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){ |
| for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){ |
| if(tf(te)){ |
| if(isFinal){ |
| matchArr.push(te); |
| }else{ |
| _filterDown(te, queryParts, matchArr, nidx); |
| } |
| } |
| /* |
| if(x==0){ |
| break; |
| } |
| */ |
| } |
| } |
| |
| // otherwise, keep going down, unless we'er at the end |
| var candidates = getElementsFunc(tqp)(element); |
| if(isFinal){ |
| while(candidates.length){ |
| matchArr.push(candidates.shift()); |
| } |
| /* |
| candidates.unshift(0, matchArr.length-1); |
| matchArr.splice.apply(matchArr, candidates); |
| */ |
| }else{ |
| // if we're not yet at the bottom, keep going! |
| while(candidates.length){ |
| _filterDown(candidates.shift(), queryParts, matchArr, nidx); |
| } |
| } |
| } |
| |
| var filterDown = function(elements, queryParts){ |
| var ret = []; |
| |
| // for every root, get the elements that match the descendant selector |
| // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){ |
| var x = elements.length - 1, te; |
| while(te = elements[x--]){ |
| _filterDown(te, queryParts, ret, 0); |
| } |
| return ret; |
| } |
| |
| var getFilterFunc = function(q){ |
| // note: query can't have spaces! |
| if(_filtersCache[q.query]){ |
| return _filtersCache[q.query]; |
| } |
| var ff = null; |
| |
| // does it have a tagName component? |
| if(q.tag){ |
| if(q.tag == "*"){ |
| ff = agree(ff, |
| function(elem){ |
| return (elem.nodeType == 1); |
| } |
| ); |
| }else{ |
| // tag name match |
| ff = agree(ff, |
| function(elem){ |
| return ( |
| (elem.nodeType == 1) && |
| (q.tag == elem.tagName.toLowerCase()) |
| ); |
| // return isTn; |
| } |
| ); |
| } |
| } |
| |
| // does the node have an ID? |
| if(q.id){ |
| ff = agree(ff, |
| function(elem){ |
| return ( |
| (elem.nodeType == 1) && |
| (elem.id == q.id) |
| ); |
| } |
| ); |
| } |
| |
| if(q.hasLoops){ |
| // if we have other query param parts, make sure we add them to the |
| // filter chain |
| ff = agree(ff, getSimpleFilterFunc(q)); |
| } |
| |
| return _filtersCache[q.query] = ff; |
| } |
| |
| var getNodeIndex = function(node){ |
| // NOTE: |
| // we could have a more accurate caching mechanism by invalidating |
| // caches after the query has finished, but I think that'd lead to |
| // significantly more cache churn than the cache would provide |
| // value for in the common case. Generally, we're more |
| // conservative (and therefore, more accurate) than jQuery and |
| // DomQuery WRT node node indexes, but there may be corner cases |
| // in which we fall down. How much we care about them is TBD. |
| |
| var pn = node.parentNode; |
| var pnc = pn.childNodes; |
| |
| // check to see if we can trust the cache. If not, re-key the whole |
| // thing and return our node match from that. |
| |
| var nidx = -1; |
| var child = pn.firstChild; |
| if(!child){ |
| return nidx; |
| } |
| |
| var ci = node["__cachedIndex"]; |
| var cl = pn["__cachedLength"]; |
| |
| // only handle cache building if we've gone out of sync |
| if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){ |
| // rip though the whole set, building cache indexes as we go |
| pn["__cachedLength"] = pnc.length; |
| var idx = 1; |
| do{ |
| // we only assign indexes for nodes with nodeType == 1, as per: |
| // http://www.w3.org/TR/css3-selectors/#nth-child-pseudo |
| // only elements are counted in the search order, and they |
| // begin at 1 for the first child's index |
| |
| if(child === node){ |
| nidx = idx; |
| } |
| if(child.nodeType == 1){ |
| child["__cachedIndex"] = idx; |
| idx++; |
| } |
| child = child.nextSibling; |
| }while(child); |
| }else{ |
| // NOTE: |
| // could be incorrect in some cases (node swaps involving the |
| // passed node, etc.), but we ignore those due to the relative |
| // unlikelihood of that occuring |
| nidx = ci; |
| } |
| return nidx; |
| } |
| |
| var firedCount = 0; |
| |
| var blank = ""; |
| var _getAttr = function(elem, attr){ |
| if(attr == "class"){ |
| return elem.className || blank; |
| } |
| if(attr == "for"){ |
| return elem.htmlFor || blank; |
| } |
| return elem.getAttribute(attr, 2) || blank; |
| } |
| |
| var attrs = { |
| "*=": function(attr, value){ |
| return function(elem){ |
| // E[foo*="bar"] |
| // an E element whose "foo" attribute value contains |
| // the substring "bar" |
| return (_getAttr(elem, attr).indexOf(value)>=0); |
| } |
| }, |
| "^=": function(attr, value){ |
| // E[foo^="bar"] |
| // an E element whose "foo" attribute value begins exactly |
| // with the string "bar" |
| return function(elem){ |
| return (_getAttr(elem, attr).indexOf(value)==0); |
| } |
| }, |
| "$=": function(attr, value){ |
| // E[foo$="bar"] |
| // an E element whose "foo" attribute value ends exactly |
| // with the string "bar" |
| var tval = " "+value; |
| return function(elem){ |
| var ea = " "+_getAttr(elem, attr); |
| return (ea.lastIndexOf(value)==(ea.length-value.length)); |
| } |
| }, |
| "~=": function(attr, value){ |
| // E[foo~="bar"] |
| // an E element whose "foo" attribute value is a list of |
| // space-separated values, one of which is exactly equal |
| // to "bar" |
| |
| // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]"; |
| var tval = " "+value+" "; |
| return function(elem){ |
| var ea = " "+_getAttr(elem, attr)+" "; |
| return (ea.indexOf(tval)>=0); |
| } |
| }, |
| "|=": function(attr, value){ |
| // E[hreflang|="en"] |
| // an E element whose "hreflang" attribute has a |
| // hyphen-separated list of values beginning (from the |
| // left) with "en" |
| var valueDash = " "+value+"-"; |
| return function(elem){ |
| var ea = " "+(elem.getAttribute(attr, 2) || ""); |
| return ( |
| (ea == value) || |
| (ea.indexOf(valueDash)==0) |
| ); |
| } |
| }, |
| "=": function(attr, value){ |
| return function(elem){ |
| return (_getAttr(elem, attr) == value); |
| } |
| } |
| }; |
| |
| var pseudos = { |
| "first-child": function(name, condition){ |
| return function(elem){ |
| if(elem.nodeType != 1){ return false; } |
| // check to see if any of the previous siblings are elements |
| var fc = elem.previousSibling; |
| while(fc && (fc.nodeType != 1)){ |
| fc = fc.previousSibling; |
| } |
| return (!fc); |
| } |
| }, |
| "last-child": function(name, condition){ |
| return function(elem){ |
| if(elem.nodeType != 1){ return false; } |
| // check to see if any of the next siblings are elements |
| var nc = elem.nextSibling; |
| while(nc && (nc.nodeType != 1)){ |
| nc = nc.nextSibling; |
| } |
| return (!nc); |
| } |
| }, |
| "empty": function(name, condition){ |
| return function(elem){ |
| // DomQuery and jQuery get this wrong, oddly enough. |
| // The CSS 3 selectors spec is pretty explicit about |
| // it, too. |
| var cn = elem.childNodes; |
| var cnl = elem.childNodes.length; |
| // if(!cnl){ return true; } |
| for(var x=cnl-1; x >= 0; x--){ |
| var nt = cn[x].nodeType; |
| if((nt == 1)||(nt == 3)){ return false; } |
| } |
| return true; |
| } |
| }, |
| /* non standard! |
| "contains": function(name, condition){ |
| return function(elem){ |
| // FIXME: I dislike this version of "contains", as |
| // whimsical attribute could set it off. An inner-text |
| // based version might be more accurate, but since |
| // jQuery and DomQuery also potentially get this wrong, |
| // I'm leaving it for now. |
| return (elem.innerHTML.indexOf(condition) >= 0); |
| } |
| }, |
| */ |
| "not": function(name, condition){ |
| var ntf = getFilterFunc(getQueryParts(condition)[0]); |
| return function(elem){ |
| return (!ntf(elem)); |
| } |
| }, |
| "nth-child": function(name, condition){ |
| var pi = parseInt; |
| if(condition == "odd"){ |
| return function(elem){ |
| return ( |
| ((getNodeIndex(elem)) % 2) == 1 |
| ); |
| } |
| }else if((condition == "2n")|| |
| (condition == "even")){ |
| return function(elem){ |
| return ((getNodeIndex(elem) % 2) == 0); |
| } |
| }else if(condition.indexOf("0n+") == 0){ |
| var ncount = pi(condition.substr(3)); |
| return function(elem){ |
| return (elem.parentNode[childNodesName][ncount-1] === elem); |
| } |
| }else if( (condition.indexOf("n+") > 0) && |
| (condition.length > 3) ){ |
| var tparts = condition.split("n+", 2); |
| var pred = pi(tparts[0]); |
| var idx = pi(tparts[1]); |
| return function(elem){ |
| return ((getNodeIndex(elem) % pred) == idx); |
| } |
| }else if(condition.indexOf("n") == -1){ |
| var ncount = pi(condition); |
| return function(elem){ |
| return (getNodeIndex(elem) == ncount); |
| } |
| } |
| } |
| }; |
| |
| var defaultGetter = (d.isIE) ? function(cond){ |
| var clc = cond.toLowerCase(); |
| return function(elem){ |
| return elem[cond]||elem[clc]; |
| } |
| } : function(cond){ |
| return function(elem){ |
| return (elem && elem.getAttribute && elem.hasAttribute(cond)); |
| } |
| }; |
| |
| var getSimpleFilterFunc = function(query){ |
| |
| var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]); |
| if(fcHit){ return fcHit; } |
| |
| var ff = null; |
| |
| // the only case where we'll need the tag name is if we came from an ID query |
| if(query.id){ // do we have an ID component? |
| if(query.tag != "*"){ |
| ff = agree(ff, function(elem){ |
| return (elem.tagName.toLowerCase() == query.tag); |
| }); |
| } |
| } |
| |
| // if there's a class in our query, generate a match function for it |
| d.forEach(query.classes, function(cname, idx, arr){ |
| // get the class name |
| var isWildcard = cname.charAt(cname.length-1) == "*"; |
| if(isWildcard){ |
| cname = cname.substr(0, cname.length-1); |
| } |
| // I dislike the regex thing, even if memozied in a cache, but it's VERY short |
| var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)"); |
| ff = agree(ff, function(elem){ |
| return re.test(elem.className); |
| }); |
| ff.count = idx; |
| }); |
| |
| d.forEach(query.pseudos, function(pseudo){ |
| if(pseudos[pseudo.name]){ |
| ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value)); |
| } |
| }); |
| |
| handleAttrs(attrs, query, defaultGetter, |
| function(tmatcher){ ff = agree(ff, tmatcher); } |
| ); |
| if(!ff){ |
| ff = function(){ return true; }; |
| } |
| return _simpleFiltersCache[query.query] = ff; |
| } |
| |
| var _getElementsFuncCache = { }; |
| |
| var getElementsFunc = function(query, root){ |
| var fHit = _getElementsFuncCache[query.query]; |
| if(fHit){ return fHit; } |
| |
| // NOTE: this function is in the fast path! not memoized!!! |
| |
| // the query doesn't contain any spaces, so there's only so many |
| // things it could be |
| |
| if(query.id && !query.hasLoops && !query.tag){ |
| // ID-only query. Easy. |
| return _getElementsFuncCache[query.query] = function(root){ |
| // FIXME: if root != document, check for parenting! |
| return [ d.byId(query.id) ]; |
| } |
| } |
| |
| var filterFunc = getSimpleFilterFunc(query); |
| |
| var retFunc; |
| if(query.tag && query.id && !query.hasLoops){ |
| // we got a filtered ID search (e.g., "h4#thinger") |
| retFunc = function(root){ |
| var te = d.byId(query.id); |
| if(filterFunc(te)){ |
| return [ te ]; |
| } |
| } |
| }else{ |
| var tret; |
| |
| if(!query.hasLoops){ |
| // it's just a plain-ol elements-by-tag-name query from the root |
| retFunc = function(root){ |
| var ret = []; |
| var te, x=0, tret = root.getElementsByTagName(query.tag); |
| while(te=tret[x++]){ |
| ret.push(te); |
| } |
| return ret; |
| } |
| }else{ |
| retFunc = function(root){ |
| var ret = []; |
| var te, x=0, tret = root.getElementsByTagName(query.tag); |
| while(te=tret[x++]){ |
| if(filterFunc(te)){ |
| ret.push(te); |
| } |
| } |
| return ret; |
| } |
| } |
| } |
| return _getElementsFuncCache[query.query] = retFunc; |
| } |
| |
| var _partsCache = {}; |
| |
| //////////////////////////////////////////////////////////////////////// |
| // the query runner |
| //////////////////////////////////////////////////////////////////////// |
| |
| // this is the second level of spliting, from full-length queries (e.g., |
| // "div.foo .bar") into simple query expressions (e.g., ["div.foo", |
| // ".bar"]) |
| var _queryFuncCache = { |
| "*": d.isIE ? |
| function(root){ |
| return root.all; |
| } : |
| function(root){ |
| return root.getElementsByTagName("*"); |
| }, |
| ">": function(root){ |
| var ret = []; |
| var te, x=0, tret = root[childNodesName]; |
| while(te=tret[x++]){ |
| if(te.nodeType == 1){ ret.push(te); } |
| } |
| return ret; |
| } |
| }; |
| |
| var getStepQueryFunc = function(query){ |
| // if it's trivial, get a fast-path dispatcher |
| var qparts = getQueryParts(d.trim(query)); |
| // if(query[query.length-1] == ">"){ query += " *"; } |
| if(qparts.length == 1){ |
| var tt = getElementsFunc(qparts[0]); |
| tt.nozip = true; |
| return tt; |
| } |
| |
| // otherwise, break it up and return a runner that iterates over the parts recursively |
| var sqf = function(root){ |
| var localQueryParts = qparts.slice(0); // clone the src arr |
| var candidates; |
| if(localQueryParts[0].oper == ">"){ |
| candidates = [ root ]; |
| // root = document; |
| }else{ |
| candidates = getElementsFunc(localQueryParts.shift())(root); |
| } |
| return filterDown(candidates, localQueryParts); |
| } |
| return sqf; |
| } |
| |
| // a specialized method that implements our primoridal "query optimizer". |
| // This allows us to dispatch queries to the fastest subsystem we can get. |
| var _getQueryFunc = ( |
| // NOTE: |
| // XPath on the Webkit nighlies is slower than it's DOM iteration |
| // for most test cases |
| // FIXME: |
| // we should try to capture some runtime speed data for each query |
| // function to determine on the fly if we should stick w/ the |
| // potentially optimized variant or if we should try something |
| // new. |
| (document["evaluate"] && !d.isSafari) ? |
| function(query){ |
| // has xpath support that's faster than DOM |
| var qparts = query.split(" "); |
| // can we handle it? |
| if( (document["evaluate"])&& |
| (query.indexOf(":") == -1)&& |
| ( |
| (true) // || |
| // (query.indexOf("[") == -1) || |
| // (query.indexOf("=") == -1) |
| ) |
| ){ |
| // dojo.debug(query); |
| // should we handle it? |
| |
| // kind of a lame heuristic, but it works |
| if( |
| // a "div div div" style query |
| ((qparts.length > 2)&&(query.indexOf(">") == -1))|| |
| // or something else with moderate complexity. kinda janky |
| (qparts.length > 3)|| |
| (query.indexOf("[")>=0)|| |
| // or if it's a ".thinger" query |
| ((1 == qparts.length)&&(0 <= query.indexOf("."))) |
| |
| ){ |
| // use get and cache a xpath runner for this selector |
| return getXPathFunc(query); |
| } |
| } |
| |
| // fallthrough |
| return getStepQueryFunc(query); |
| } : getStepQueryFunc |
| ); |
| // uncomment to disable XPath for testing and tuning the DOM path |
| // _getQueryFunc = getStepQueryFunc; |
| |
| // FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything |
| |
| // uncomment to disable DOM queries for testing and tuning XPath |
| // _getQueryFunc = getXPathFunc; |
| |
| // this is the primary caching for full-query results. The query dispatcher |
| // functions are generated here and then pickled for hash lookup in the |
| // future |
| var getQueryFunc = function(query){ |
| // return a cached version if one is available |
| if(_queryFuncCache[query]){ return _queryFuncCache[query]; } |
| if(0 > query.indexOf(",")){ |
| // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher |
| return _queryFuncCache[query] = _getQueryFunc(query); |
| }else{ |
| // if it's a complex query, break it up into it's constituent parts |
| // and return a dispatcher that will merge the parts when run |
| |
| // var parts = query.split(", "); |
| var parts = query.split(/\s*,\s*/); |
| var tf = function(root){ |
| var pindex = 0; // avoid array alloc for every invocation |
| var ret = []; |
| var tp; |
| while(tp = parts[pindex++]){ |
| ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root)); |
| } |
| return ret; |
| } |
| // ...cache and return |
| return _queryFuncCache[query] = tf; |
| } |
| } |
| |
| // FIXME: |
| // Dean's new Base2 uses a system whereby queries themselves note if |
| // they'll need duplicate filtering. We need to get on that plan!! |
| |
| // attempt to efficiently determine if an item in a list is a dupe, |
| // returning a list of "uniques", hopefully in doucment order |
| var _zipIdx = 0; |
| var _zip = function(arr){ |
| if(arr && arr.nozip){ return d.NodeList._wrap(arr); } |
| var ret = new d.NodeList(); |
| if(!arr){ return ret; } |
| if(arr[0]){ |
| ret.push(arr[0]); |
| } |
| if(arr.length < 2){ return ret; } |
| _zipIdx++; |
| arr[0]["_zipIdx"] = _zipIdx; |
| for(var x=1, te; te = arr[x]; x++){ |
| if(arr[x]["_zipIdx"] != _zipIdx){ |
| ret.push(te); |
| } |
| te["_zipIdx"] = _zipIdx; |
| } |
| // FIXME: should we consider stripping these properties? |
| return ret; |
| } |
| |
| // the main executor |
| d.query = function(query, root){ |
| // see dojo.query for docs |
| |
| if(query.constructor == d.NodeList){ |
| return query; |
| } |
| if(!d.isString(query)){ |
| return new d.NodeList(query); // dojo.NodeList |
| } |
| if(d.isString(root)){ |
| root = d.byId(root); |
| } |
| |
| // FIXME: should support more methods on the return than the stock array. |
| return _zip(getQueryFunc(query)(root||d.doc)); |
| } |
| |
| /* |
| // exposing these was a mistake |
| d.query.attrs = attrs; |
| d.query.pseudos = pseudos; |
| */ |
| |
| // one-off function for filtering a NodeList based on a simple selector |
| d._filterQueryResult = function(nodeList, simpleFilter){ |
| var tnl = new d.NodeList(); |
| var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; }; |
| for(var x=0, te; te = nodeList[x]; x++){ |
| if(ff(te)){ tnl.push(te); } |
| } |
| return tnl; |
| } |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.xhr"] = true; |
| dojo.provide("dojo._base.xhr"); |
| |
| |
| |
| |
| |
| (function(){ |
| var _d = dojo; |
| function setValue(/*Object*/obj, /*String*/name, /*String*/value){ |
| //summary: |
| // For the nameed property in object, set the value. If a value |
| // already exists and it is a string, convert the value to be an |
| // array of values. |
| var val = obj[name]; |
| if(_d.isString(val)){ |
| obj[name] = [val, value]; |
| }else if(_d.isArray(val)){ |
| val.push(value); |
| }else{ |
| obj[name] = value; |
| } |
| } |
| |
| dojo.formToObject = function(/*DOMNode||String*/ formNode){ |
| // summary: |
| // dojo.formToObject returns the values encoded in an HTML form as |
| // string properties in an object which it then returns. Disabled form |
| // elements, buttons, and other non-value form elements are skipped. |
| // Multi-select elements are returned as an array of string values. |
| // description: |
| // This form: |
| // |
| // <form id="test_form"> |
| // <input type="text" name="blah" value="blah"> |
| // <input type="text" name="no_value" value="blah" disabled> |
| // <input type="button" name="no_value2" value="blah"> |
| // <select type="select" multiple name="multi" size="5"> |
| // <option value="blah">blah</option> |
| // <option value="thud" selected>thud</option> |
| // <option value="thonk" selected>thonk</option> |
| // </select> |
| // </form> |
| // |
| // yields this object structure as the result of a call to |
| // formToObject(): |
| // |
| // { |
| // blah: "blah", |
| // multi: [ |
| // "thud", |
| // "thonk" |
| // ] |
| // }; |
| |
| var ret = {}; |
| var iq = "input:not([type=file]):not([type=submit]):not([type=image]):not([type=reset]):not([type=button]), select, textarea"; |
| _d.query(iq, formNode).filter(function(node){ |
| return !node.disabled; |
| }).forEach(function(item){ |
| var _in = item.name; |
| var type = (item.type||"").toLowerCase(); |
| if(type == "radio" || type == "checkbox"){ |
| if(item.checked){ setValue(ret, _in, item.value); } |
| }else if(item.multiple){ |
| ret[_in] = []; |
| _d.query("option", item).forEach(function(opt){ |
| if(opt.selected){ |
| setValue(ret, _in, opt.value); |
| } |
| }); |
| }else{ |
| setValue(ret, _in, item.value); |
| if(type == "image"){ |
| ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0; |
| } |
| } |
| }); |
| return ret; // Object |
| } |
| |
| dojo.objectToQuery = function(/*Object*/ map){ |
| // summary: |
| // takes a name/value mapping object and returns a string representing |
| // a URL-encoded version of that object. |
| // example: |
| // this object: |
| // |
| // | { |
| // | blah: "blah", |
| // | multi: [ |
| // | "thud", |
| // | "thonk" |
| // | ] |
| // | }; |
| // |
| // yields the following query string: |
| // |
| // | "blah=blah&multi=thud&multi=thonk" |
| |
| // FIXME: need to implement encodeAscii!! |
| var enc = encodeURIComponent; |
| var pairs = []; |
| var backstop = {}; |
| for(var name in map){ |
| var value = map[name]; |
| if(value != backstop[name]){ |
| var assign = enc(name) + "="; |
| if(_d.isArray(value)){ |
| for(var i=0; i < value.length; i++){ |
| pairs.push(assign + enc(value[i])); |
| } |
| }else{ |
| pairs.push(assign + enc(value)); |
| } |
| } |
| } |
| return pairs.join("&"); // String |
| } |
| |
| dojo.formToQuery = function(/*DOMNode||String*/ formNode){ |
| // summary: |
| // return URL-encoded string representing the form passed as either a |
| // node or string ID identifying the form to serialize |
| return _d.objectToQuery(_d.formToObject(formNode)); // String |
| } |
| |
| dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){ |
| // summary: |
| // return a serialized JSON string from a form node or string |
| // ID identifying the form to serialize |
| return _d.toJson(_d.formToObject(formNode), prettyPrint); // String |
| } |
| |
| dojo.queryToObject = function(/*String*/ str){ |
| // summary: |
| // returns an object representing a de-serialized query section of a |
| // URL. Query keys with multiple values are returned in an array. |
| // description: |
| // This string: |
| // |
| // "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&" |
| // |
| // returns this object structure: |
| // |
| // { |
| // foo: [ "bar", "baz" ], |
| // thinger: " spaces =blah", |
| // zonk: "blarg" |
| // } |
| // |
| // Note that spaces and other urlencoded entities are correctly |
| // handled. |
| |
| // FIXME: should we grab the URL string if we're not passed one? |
| var ret = {}; |
| var qp = str.split("&"); |
| var dec = decodeURIComponent; |
| _d.forEach(qp, function(item){ |
| if(item.length){ |
| var parts = item.split("="); |
| var name = dec(parts.shift()); |
| var val = dec(parts.join("=")); |
| if(_d.isString(ret[name])){ |
| ret[name] = [ret[name]]; |
| } |
| if(_d.isArray(ret[name])){ |
| ret[name].push(val); |
| }else{ |
| ret[name] = val; |
| } |
| } |
| }); |
| return ret; // Object |
| } |
| |
| /* |
| from refactor.txt: |
| |
| all bind() replacement APIs take the following argument structure: |
| |
| { |
| url: "blah.html", |
| |
| // all below are optional, but must be supported in some form by |
| // every IO API |
| timeout: 1000, // milliseconds |
| handleAs: "text", // replaces the always-wrong "mimetype" |
| content: { |
| key: "value" |
| }, |
| |
| // browser-specific, MAY be unsupported |
| sync: true, // defaults to false |
| form: dojo.byId("someForm") |
| } |
| */ |
| |
| // need to block async callbacks from snatching this thread as the result |
| // of an async callback might call another sync XHR, this hangs khtml forever |
| // must checked by watchInFlight() |
| |
| dojo._blockAsync = false; |
| |
| dojo._contentHandlers = { |
| "text": function(xhr){ return xhr.responseText; }, |
| "json": function(xhr){ |
| if(!djConfig.usePlainJson){ |
| console.warn("Consider using mimetype:text/json-comment-filtered" |
| + " to avoid potential security issues with JSON endpoints" |
| + " (use djConfig.usePlainJson=true to turn off this message)"); |
| } |
| return _d.fromJson(xhr.responseText); |
| }, |
| "json-comment-filtered": function(xhr){ |
| // NOTE: we provide the json-comment-filtered option as one solution to |
| // the "JavaScript Hijacking" issue noted by Fortify and others. It is |
| // not appropriate for all circumstances. |
| |
| var value = xhr.responseText; |
| var cStartIdx = value.indexOf("\/*"); |
| var cEndIdx = value.lastIndexOf("*\/"); |
| if(cStartIdx == -1 || cEndIdx == -1){ |
| throw new Error("JSON was not comment filtered"); |
| } |
| return _d.fromJson(value.substring(cStartIdx+2, cEndIdx)); |
| }, |
| "javascript": function(xhr){ |
| // FIXME: try Moz and IE specific eval variants? |
| return _d.eval(xhr.responseText); |
| }, |
| "xml": function(xhr){ |
| var result = xhr.responseXML; |
| if(_d.isIE && (!result || window.location.protocol == "file:")){ |
| _d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){ |
| try{ |
| var dom = new ActiveXObject(prefix + ".XMLDOM"); |
| dom.async = false; |
| dom.loadXML(xhr.responseText); |
| result = dom; |
| }catch(e){ /* Not available. Squelch and try next one. */ } |
| }); |
| } |
| return result; // DOMDocument |
| } |
| }; |
| |
| dojo._contentHandlers["json-comment-optional"] = function(xhr){ |
| var handlers = _d._contentHandlers; |
| try{ |
| return handlers["json-comment-filtered"](xhr); |
| }catch(e){ |
| return handlers["json"](xhr); |
| } |
| }; |
| |
| /*===== |
| dojo.__ioArgs = function(kwArgs){ |
| // url: String |
| // URL to server endpoint. |
| // content: Object? |
| // Contains properties with string values. These |
| // properties will be serialized as name1=value2 and |
| // passed in the request. |
| // timeout: Integer? |
| // Milliseconds to wait for the response. If this time |
| // passes, the then error callbacks are called. |
| // form: DOMNode? |
| // DOM node for a form. Used to extract the form values |
| // and send to the server. |
| // preventCache: Boolean? |
| // Default is false. If true, then a |
| // "dojo.preventCache" parameter is sent in the request |
| // with a value that changes with each request |
| // (timestamp). Useful only with GET-type requests. |
| // handleAs: String? |
| // Acceptable values depend on the type of IO |
| // transport (see specific IO calls for more information). |
| // load: Function? |
| // function(response, ioArgs){}. response is an Object, ioArgs |
| // is of type dojo.__ioCallbackArgs. The load function will be |
| // called on a successful response. |
| // error: Function? |
| // function(response, ioArgs){}. response is an Object, ioArgs |
| // is of type dojo.__ioCallbackArgs. The error function will |
| // be called in an error case. |
| // handle: Function |
| // function(response, ioArgs){}. response is an Object, ioArgs |
| // is of type dojo.__ioCallbackArgs. The handle function will |
| // be called in either the successful or error case. For |
| // the load, error and handle functions, the ioArgs object |
| // will contain the following properties: |
| } |
| =====*/ |
| |
| /*===== |
| dojo.__ioCallbackArgs = function(kwArgs){ |
| // args: Object |
| // the original object argument to the IO call. |
| // xhr: XMLHttpRequest |
| // For XMLHttpRequest calls only, the |
| // XMLHttpRequest object that was used for the |
| // request. |
| // url: String |
| // The final URL used for the call. Many times it |
| // will be different than the original args.url |
| // value. |
| // query: String |
| // For non-GET requests, the |
| // name1=value1&name2=value2 parameters sent up in |
| // the request. |
| // handleAs: String |
| // The final indicator on how the response will be |
| // handled. |
| // id: String |
| // For dojo.io.script calls only, the internal |
| // script ID used for the request. |
| // canDelete: Boolean |
| // For dojo.io.script calls only, indicates |
| // whether the script tag that represents the |
| // request can be deleted after callbacks have |
| // been called. Used internally to know when |
| // cleanup can happen on JSONP-type requests. |
| // json: Object |
| // For dojo.io.script calls only: holds the JSON |
| // response for JSONP-type requests. Used |
| // internally to hold on to the JSON responses. |
| // You should not need to access it directly -- |
| // the same object should be passed to the success |
| // callbacks directly. |
| } |
| =====*/ |
| |
| |
| |
| dojo._ioSetArgs = function(/*dojo.__ioArgs*/args, |
| /*Function*/canceller, |
| /*Function*/okHandler, |
| /*Function*/errHandler){ |
| // summary: |
| // sets up the Deferred and ioArgs property on the Deferred so it |
| // can be used in an io call. |
| // args: |
| // The args object passed into the public io call. Recognized properties on |
| // the args object are: |
| // canceller: |
| // The canceller function used for the Deferred object. The function |
| // will receive one argument, the Deferred object that is related to the |
| // canceller. |
| // okHandler: |
| // The first OK callback to be registered with Deferred. It has the opportunity |
| // to transform the OK response. It will receive one argument -- the Deferred |
| // object returned from this function. |
| // errHandler: |
| // The first error callback to be registered with Deferred. It has the opportunity |
| // to do cleanup on an error. It will receive two arguments: error (the |
| // Error object) and dfd, the Deferred object returned from this function. |
| |
| var ioArgs = {args: args, url: args.url}; |
| |
| //Get values from form if requestd. |
| var formObject = null; |
| if(args.form){ |
| var form = _d.byId(args.form); |
| //IE requires going through getAttributeNode instead of just getAttribute in some form cases, |
| //so use it for all. See #2844 |
| var actnNode = form.getAttributeNode("action"); |
| ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null); |
| formObject = _d.formToObject(form); |
| } |
| |
| // set up the query params |
| var miArgs = [{}]; |
| |
| if(formObject){ |
| // potentially over-ride url-provided params w/ form values |
| miArgs.push(formObject); |
| } |
| if(args.content){ |
| // stuff in content over-rides what's set by form |
| miArgs.push(args.content); |
| } |
| if(args.preventCache){ |
| miArgs.push({"dojo.preventCache": new Date().valueOf()}); |
| } |
| ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs)); |
| |
| // .. and the real work of getting the deferred in order, etc. |
| ioArgs.handleAs = args.handleAs || "text"; |
| var d = new _d.Deferred(canceller); |
| d.addCallbacks(okHandler, function(error){ |
| return errHandler(error, d); |
| }); |
| |
| //Support specifying load, error and handle callback functions from the args. |
| //For those callbacks, the "this" object will be the args object. |
| //The callbacks will get the deferred result value as the |
| //first argument and the ioArgs object as the second argument. |
| var ld = args.load; |
| if(ld && _d.isFunction(ld)){ |
| d.addCallback(function(value){ |
| return ld.call(args, value, ioArgs); |
| }); |
| } |
| var err = args.error; |
| if(err && _d.isFunction(err)){ |
| d.addErrback(function(value){ |
| return err.call(args, value, ioArgs); |
| }); |
| } |
| var handle = args.handle; |
| if(handle && _d.isFunction(handle)){ |
| d.addBoth(function(value){ |
| return handle.call(args, value, ioArgs); |
| }); |
| } |
| |
| d.ioArgs = ioArgs; |
| |
| // FIXME: need to wire up the xhr object's abort method to something |
| // analagous in the Deferred |
| return d; |
| } |
| |
| var _deferredCancel = function(/*Deferred*/dfd){ |
| //summary: canceller function for dojo._ioSetArgs call. |
| |
| dfd.canceled = true; |
| var xhr = dfd.ioArgs.xhr; |
| var _at = typeof xhr.abort; |
| if(_at == "function" || _at == "unknown"){ |
| xhr.abort(); |
| } |
| var err = new Error("xhr cancelled"); |
| err.dojoType = "cancel"; |
| return err; |
| } |
| var _deferredOk = function(/*Deferred*/dfd){ |
| //summary: okHandler function for dojo._ioSetArgs call. |
| |
| return _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr); |
| } |
| var _deferError = function(/*Error*/error, /*Deferred*/dfd){ |
| //summary: errHandler function for dojo._ioSetArgs call. |
| |
| // console.debug("xhr error in:", dfd.ioArgs.xhr); |
| console.debug(error); |
| return error; |
| } |
| |
| var _makeXhrDeferred = function(/*dojo.__xhrArgs*/args){ |
| //summary: makes the Deferred object for this xhr request. |
| var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError); |
| //Pass the args to _xhrObj, to allow xhr iframe proxy interceptions. |
| dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args); |
| return dfd; |
| } |
| |
| // avoid setting a timer per request. It degrades performance on IE |
| // something fierece if we don't use unified loops. |
| var _inFlightIntvl = null; |
| var _inFlight = []; |
| var _watchInFlight = function(){ |
| //summary: |
| // internal method that checks each inflight XMLHttpRequest to see |
| // if it has completed or if the timeout situation applies. |
| |
| var now = (new Date()).getTime(); |
| // make sure sync calls stay thread safe, if this callback is called |
| // during a sync call and this results in another sync call before the |
| // first sync call ends the browser hangs |
| if(!_d._blockAsync){ |
| // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating |
| // note: the second clause is an assigment on purpose, lint may complain |
| for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){ |
| var dfd = tif.dfd; |
| try{ |
| if(!dfd || dfd.canceled || !tif.validCheck(dfd)){ |
| _inFlight.splice(i--, 1); |
| }else if(tif.ioCheck(dfd)){ |
| _inFlight.splice(i--, 1); |
| tif.resHandle(dfd); |
| }else if(dfd.startTime){ |
| //did we timeout? |
| if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){ |
| _inFlight.splice(i--, 1); |
| var err = new Error("timeout exceeded"); |
| err.dojoType = "timeout"; |
| dfd.errback(err); |
| //Cancel the request so the io module can do appropriate cleanup. |
| dfd.cancel(); |
| } |
| } |
| }catch(e){ |
| // FIXME: make sure we errback! (fixed? remove console.debug?) |
| console.debug(e); |
| dfd.errback(new Error("_watchInFlightError!")); |
| } |
| } |
| } |
| |
| if(!_inFlight.length){ |
| clearInterval(_inFlightIntvl); |
| _inFlightIntvl = null; |
| return; |
| } |
| |
| } |
| |
| dojo._ioCancelAll = function(){ |
| //summary: Cancels all pending IO requests, regardless of IO type |
| //(xhr, script, iframe). |
| try{ |
| _d.forEach(_inFlight, function(i){ |
| i.dfd.cancel(); |
| }); |
| }catch(e){/*squelch*/} |
| } |
| |
| //Automatically call cancel all io calls on unload |
| //in IE for trac issue #2357. |
| if(_d.isIE){ |
| _d.addOnUnload(_d._ioCancelAll); |
| } |
| |
| _d._ioWatch = function(/*Deferred*/dfd, |
| /*Function*/validCheck, |
| /*Function*/ioCheck, |
| /*Function*/resHandle){ |
| //summary: watches the io request represented by dfd to see if it completes. |
| //dfd: |
| // The Deferred object to watch. |
| //validCheck: |
| // Function used to check if the IO request is still valid. Gets the dfd |
| // object as its only argument. |
| //ioCheck: |
| // Function used to check if basic IO call worked. Gets the dfd |
| // object as its only argument. |
| //resHandle: |
| // Function used to process response. Gets the dfd |
| // object as its only argument. |
| if(dfd.ioArgs.args.timeout){ |
| dfd.startTime = (new Date()).getTime(); |
| } |
| _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle}); |
| if(!_inFlightIntvl){ |
| _inFlightIntvl = setInterval(_watchInFlight, 50); |
| } |
| _watchInFlight(); // handle sync requests |
| } |
| |
| var _defaultContentType = "application/x-www-form-urlencoded"; |
| |
| var _validCheck = function(/*Deferred*/dfd){ |
| return dfd.ioArgs.xhr.readyState; //boolean |
| } |
| var _ioCheck = function(/*Deferred*/dfd){ |
| return 4 == dfd.ioArgs.xhr.readyState; //boolean |
| } |
| var _resHandle = function(/*Deferred*/dfd){ |
| var xhr = dfd.ioArgs.xhr; |
| if(_d._isDocumentOk(xhr)){ |
| dfd.callback(dfd); |
| }else{ |
| var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status); |
| err.status = xhr.status; |
| err.responseText = xhr.responseText; |
| dfd.errback(err); |
| } |
| } |
| |
| var _doIt = function(/*String*/type, /*Deferred*/dfd){ |
| // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open). |
| // workaround for IE6's apply() "issues" |
| var ioArgs = dfd.ioArgs; |
| var args = ioArgs.args; |
| ioArgs.xhr.open(type, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined); |
| if(args.headers){ |
| for(var hdr in args.headers){ |
| if(hdr.toLowerCase() === "content-type" && !args.contentType){ |
| args.contentType = args.headers[hdr]; |
| }else{ |
| ioArgs.xhr.setRequestHeader(hdr, args.headers[hdr]); |
| } |
| } |
| } |
| // FIXME: is this appropriate for all content types? |
| ioArgs.xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType); |
| // FIXME: set other headers here! |
| try{ |
| ioArgs.xhr.send(ioArgs.query); |
| }catch(e){ |
| dfd.cancel(); |
| } |
| _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle); |
| return dfd; //Deferred |
| } |
| |
| dojo._ioAddQueryToUrl = function(/*dojo.__ioCallbackArgs*/ioArgs){ |
| //summary: Adds query params discovered by the io deferred construction to the URL. |
| //Only use this for operations which are fundamentally GET-type operations. |
| if(ioArgs.query.length){ |
| ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query; |
| ioArgs.query = null; |
| } |
| } |
| |
| /*===== |
| dojo.__xhrArgs = function(kwArgs){ |
| // summary: |
| // In addition to the properties listed for the dojo.__ioArgs type, |
| // the following properties are allowed for dojo.xhr* methods. |
| // handleAs: |
| // String. Acceptable values are: |
| // "text" (default) |
| // "json" |
| // "json-comment-optional" |
| // "json-comment-filtered" |
| // "javascript" |
| // "xml" |
| // sync: |
| // Boolean. false is default. Indicates whether the request should |
| // be a synchronous (blocking) request. |
| // headers: |
| // Object. Additional HTTP headers to send in the request. |
| } |
| =====*/ |
| |
| dojo.xhrGet = function(/*dojo.__xhrArgs*/ args){ |
| // summary: |
| // Sends an HTTP GET request to the server. |
| var dfd = _makeXhrDeferred(args); |
| _d._ioAddQueryToUrl(dfd.ioArgs); |
| return _doIt("GET", dfd); // dojo.Deferred |
| } |
| |
| dojo.xhrPost = function(/*dojo.__xhrArgs*/ args){ |
| //summary: |
| // Sends an HTTP POST request to the server. |
| return _doIt("POST", _makeXhrDeferred(args)); // dojo.Deferred |
| } |
| |
| dojo.rawXhrPost = function(/*dojo.__xhrArgs*/ args){ |
| // summary: |
| // Sends an HTTP POST request to the server. In addtion to the properties |
| // listed for the dojo.__xhrArgs type, the following property is allowed: |
| // postData: |
| // String. The raw data to send in the body of the POST request. |
| var dfd = _makeXhrDeferred(args); |
| dfd.ioArgs.query = args.postData; |
| return _doIt("POST", dfd); // dojo.Deferred |
| } |
| |
| dojo.xhrPut = function(/*dojo.__xhrArgs*/ args){ |
| // summary: |
| // Sends an HTTP PUT request to the server. |
| return _doIt("PUT", _makeXhrDeferred(args)); // dojo.Deferred |
| } |
| |
| dojo.rawXhrPut = function(/*dojo.__xhrArgs*/ args){ |
| // summary: |
| // Sends an HTTP PUT request to the server. In addtion to the properties |
| // listed for the dojo.__xhrArgs type, the following property is allowed: |
| // putData: |
| // String. The raw data to send in the body of the PUT request. |
| var dfd = _makeXhrDeferred(args); |
| var ioArgs = dfd.ioArgs; |
| if(args.putData){ |
| ioArgs.query = args.putData; |
| args.putData = null; |
| } |
| return _doIt("PUT", dfd); // dojo.Deferred |
| } |
| |
| dojo.xhrDelete = function(/*dojo.__xhrArgs*/ args){ |
| // summary: |
| // Sends an HTTP DELETE request to the server. |
| var dfd = _makeXhrDeferred(args); |
| _d._ioAddQueryToUrl(dfd.ioArgs); |
| return _doIt("DELETE", dfd); // dojo.Deferred |
| } |
| |
| /* |
| dojo.wrapForm = function(formNode){ |
| //summary: |
| // A replacement for FormBind, but not implemented yet. |
| |
| // FIXME: need to think harder about what extensions to this we might |
| // want. What should we allow folks to do w/ this? What events to |
| // set/send? |
| throw new Error("dojo.wrapForm not yet implemented"); |
| } |
| */ |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo._base.fx"] = true; |
| dojo.provide("dojo._base.fx"); |
| |
| |
| |
| |
| |
| |
| /* |
| Animation losely package based on Dan Pupius' work, contributed under CLA: |
| http://pupius.co.uk/js/Toolkit.Drawing.js |
| */ |
| |
| dojo._Line = function(/*int*/ start, /*int*/ end){ |
| // summary: |
| // dojo._Line is the object used to generate values from a start value |
| // to an end value |
| // start: int |
| // Beginning value for range |
| // end: int |
| // Ending value for range |
| this.start = start; |
| this.end = end; |
| this.getValue = function(/*float*/ n){ |
| // summary: returns the point on the line |
| // n: a floating point number greater than 0 and less than 1 |
| return ((this.end - this.start) * n) + this.start; // Decimal |
| } |
| } |
| |
| dojo.declare("dojo._Animation", null, { |
| // summary |
| // A generic animation object that fires callbacks into it's handlers |
| // object at various states |
| // |
| constructor: function(/*Object*/ args){ |
| dojo.mixin(this, args); |
| if(dojo.isArray(this.curve)){ |
| /* curve: Array |
| pId: a */ |
| this.curve = new dojo._Line(this.curve[0], this.curve[1]); |
| } |
| }, |
| |
| // duration: Integer |
| // The time in milliseonds the animation will take to run |
| duration: 1000, |
| |
| /*===== |
| // curve: dojo._Line||Array |
| // A two element array of start and end values, or a dojo._Line instance to be |
| // used in the Animation. |
| curve: null, |
| |
| // easing: Function |
| // A Function to adjust the acceleration (or deceleration) of the progress |
| // across a dojo._Line |
| easing: null, |
| =====*/ |
| |
| // repeat: Integer |
| // The number of times to loop the animation |
| repeat: 0, |
| |
| // rate: Integer |
| // the time in milliseconds to wait before advancing to next frame |
| // (used as a fps timer: rate/1000 = fps) |
| rate: 10 /* 100 fps */, |
| |
| /*===== |
| // delay: Integer |
| // The time in milliseconds to wait before starting animation after it has been .play()'ed |
| delay: null, |
| |
| // events |
| // |
| // beforeBegin: Event |
| // Synthetic event fired before a dojo._Animation begins playing (synhcronous) |
| beforeBegin: null, |
| |
| // onBegin: Event |
| // Synthetic event fired as a dojo._Animation begins playing (useful?) |
| onBegin: null, |
| |
| // onAnimate: Event |
| // Synthetic event fired at each interval of a dojo._Animation |
| onAnimate: null, |
| |
| // onEnd: Event |
| // Synthetic event fired after the final frame of a dojo._Animation |
| onEnd: null, |
| |
| // ??? |
| onPlay: null, |
| |
| // onPause: Event |
| // Synthetic event fired when a dojo._Animation is paused |
| onPause: null, |
| |
| // onStop: Event |
| // Synthetic event fires when a dojo._Animation is stopped |
| onStop: null, |
| |
| =====*/ |
| |
| _percent: 0, |
| _startRepeatCount: 0, |
| |
| fire: function(/*Event*/ evt, /*Array?*/ args){ |
| // summary: |
| // Convenience function. Fire event "evt" and pass it the |
| // arguments specified in "args". |
| // evt: |
| // The event to fire. |
| // args: |
| // The arguments to pass to the event. |
| if(this[evt]){ |
| this[evt].apply(this, args||[]); |
| } |
| return this; // dojo._Animation |
| }, |
| |
| play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ |
| // summary: |
| // Start the animation. |
| // delay: |
| // How many milliseconds to delay before starting. |
| // gotoStart: |
| // If true, starts the animation from the beginning; otherwise, |
| // starts it from its current position. |
| var _t = this; |
| if(gotoStart){ |
| _t._stopTimer(); |
| _t._active = _t._paused = false; |
| _t._percent = 0; |
| }else if(_t._active && !_t._paused){ |
| return _t; // dojo._Animation |
| } |
| |
| _t.fire("beforeBegin"); |
| |
| var d = delay||_t.delay; |
| var _p = dojo.hitch(_t, "_play", gotoStart); |
| if(d > 0){ |
| setTimeout(_p, d); |
| return _t; // dojo._Animation |
| } |
| _p(); |
| return _t; |
| }, |
| |
| _play: function(gotoStart){ |
| var _t = this; |
| _t._startTime = new Date().valueOf(); |
| if(_t._paused){ |
| _t._startTime -= _t.duration * _t._percent; |
| } |
| _t._endTime = _t._startTime + _t.duration; |
| |
| _t._active = true; |
| _t._paused = false; |
| |
| var value = _t.curve.getValue(_t._percent); |
| if(!_t._percent){ |
| if(!_t._startRepeatCount){ |
| _t._startRepeatCount = _t.repeat; |
| } |
| _t.fire("onBegin", [value]); |
| } |
| |
| _t.fire("onPlay", [value]); |
| |
| _t._cycle(); |
| return _t; // dojo._Animation |
| }, |
| |
| pause: function(){ |
| // summary: Pauses a running animation. |
| this._stopTimer(); |
| if(!this._active){ return this; /*dojo._Animation*/} |
| this._paused = true; |
| this.fire("onPause", [this.curve.getValue(this._percent)]); |
| return this; // dojo._Animation |
| }, |
| |
| gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){ |
| // summary: |
| // Sets the progress of the animation. |
| // percent: |
| // A percentage in decimal notation (between and including 0.0 and 1.0). |
| // andPlay: |
| // If true, play the animation after setting the progress. |
| this._stopTimer(); |
| this._active = this._paused = true; |
| this._percent = percent; |
| if(andPlay){ this.play(); } |
| return this; // dojo._Animation |
| }, |
| |
| stop: function(/*boolean?*/ gotoEnd){ |
| // summary: Stops a running animation. |
| // gotoEnd: If true, the animation will end. |
| if(!this._timer){ return; } |
| this._stopTimer(); |
| if(gotoEnd){ |
| this._percent = 1; |
| } |
| this.fire("onStop", [this.curve.getValue(this._percent)]); |
| this._active = this._paused = false; |
| return this; // dojo._Animation |
| }, |
| |
| status: function(){ |
| // summary: Returns a string token representation of the status of |
| // the animation, one of: "paused", "playing", "stopped" |
| if(this._active){ |
| return this._paused ? "paused" : "playing"; // String |
| } |
| return "stopped"; // String |
| }, |
| |
| _cycle: function(){ |
| var _t = this; |
| if(_t._active){ |
| var curr = new Date().valueOf(); |
| var step = (curr - _t._startTime) / (_t._endTime - _t._startTime); |
| |
| if(step >= 1){ |
| step = 1; |
| } |
| _t._percent = step; |
| |
| // Perform easing |
| if(_t.easing){ |
| step = _t.easing(step); |
| } |
| |
| _t.fire("onAnimate", [_t.curve.getValue(step)]); |
| |
| if(_t._percent < 1){ |
| _t._startTimer(); |
| }else{ |
| _t._active = false; |
| |
| if(_t.repeat > 0){ |
| _t.repeat--; |
| _t.play(null, true); |
| }else if(_t.repeat == -1){ |
| _t.play(null, true); |
| }else{ |
| if(_t._startRepeatCount){ |
| _t.repeat = _t._startRepeatCount; |
| _t._startRepeatCount = 0; |
| } |
| } |
| _t._percent = 0; |
| _t.fire("onEnd"); |
| } |
| } |
| return _t; // dojo._Animation |
| } |
| }); |
| |
| (function(){ |
| var d = dojo; |
| var ctr = 0; |
| var _globalTimerList = []; |
| var runner = { |
| run: function(){} |
| }; |
| var timer = null; |
| dojo._Animation.prototype._startTimer = function(){ |
| // this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate); |
| if(!this._timer){ |
| this._timer = dojo.connect(runner, "run", this, "_cycle"); |
| ctr++; |
| } |
| if(!timer){ |
| timer = setInterval(dojo.hitch(runner, "run"), this.rate); |
| } |
| }; |
| |
| dojo._Animation.prototype._stopTimer = function(){ |
| dojo.disconnect(this._timer); |
| this._timer = null; |
| ctr--; |
| if(!ctr){ |
| clearInterval(timer); |
| timer = null; |
| } |
| }; |
| |
| var _makeFadeable = (d.isIE) ? function(node){ |
| // only set the zoom if the "tickle" value would be the same as the |
| // default |
| var ns = node.style; |
| if(!ns.zoom.length && d.style(node, "zoom") == "normal"){ |
| // make sure the node "hasLayout" |
| // NOTE: this has been tested with larger and smaller user-set text |
| // sizes and works fine |
| ns.zoom = "1"; |
| // node.style.zoom = "normal"; |
| } |
| // don't set the width to auto if it didn't already cascade that way. |
| // We don't want to f anyones designs |
| if(!ns.width.length && d.style(node, "width") == "auto"){ |
| ns.width = "auto"; |
| } |
| } : function(){}; |
| |
| dojo._fade = function(/*Object*/ args){ |
| // summary: |
| // Returns an animation that will fade the node defined by |
| // args.node from the start to end values passed (args.start |
| // args.end) (end is mandatory, start is optional) |
| |
| args.node = d.byId(args.node); |
| var fArgs = d.mixin({ properties: {} }, args); |
| var props = (fArgs.properties.opacity = {}); |
| props.start = !("start" in fArgs) ? |
| function(){ return Number(d.style(fArgs.node, "opacity")); } : fArgs.start; |
| props.end = fArgs.end; |
| |
| var anim = d.animateProperty(fArgs); |
| d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node)); |
| |
| return anim; // dojo._Animation |
| } |
| |
| /*===== |
| dojo.__fadeArgs = function(kwArgs){ |
| // duration: Integer? |
| // Duration of the animation in milliseconds. |
| // easing: Function? |
| // An easing function. |
| } |
| =====*/ |
| |
| dojo.fadeIn = function(/*dojo.__fadeArgs*/ args){ |
| // summary: |
| // Returns an animation that will fade node defined in 'args' from |
| // its current opacity to fully opaque. |
| return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation |
| } |
| |
| dojo.fadeOut = function(/*dojo.__fadeArgs*/ args){ |
| // summary: |
| // Returns an animation that will fade node defined in 'args' |
| // from its current opacity to fully transparent. |
| return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation |
| } |
| |
| dojo._defaultEasing = function(/*Decimal?*/ n){ |
| // summary: The default easing function for dojo._Animation(s) |
| return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2); |
| } |
| |
| var PropLine = function(properties){ |
| this._properties = properties; |
| for(var p in properties){ |
| var prop = properties[p]; |
| if(prop.start instanceof d.Color){ |
| // create a reusable temp color object to keep intermediate results |
| prop.tempColor = new d.Color(); |
| } |
| } |
| this.getValue = function(r){ |
| var ret = {}; |
| for(var p in this._properties){ |
| var prop = this._properties[p]; |
| var start = prop.start; |
| if(start instanceof d.Color){ |
| ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss(); |
| }else if(!d.isArray(start)){ |
| ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : ""); |
| } |
| } |
| return ret; |
| } |
| } |
| |
| dojo.animateProperty = function(/*Object*/ args){ |
| // summary: |
| // Returns an animation that will transition the properties of |
| // node defined in 'args' depending how they are defined in |
| // 'args.properties' |
| // |
| // description: |
| // The foundation of most dojo.fx animations, dojo.AnimateProperty |
| // will take an object of "properties" corresponding to style |
| // properties, and animate them in parallel over a set duration. |
| // |
| // args.node can be a String or a DomNode reference |
| // |
| // example: |
| // | dojo.animateProperty({ node: node, duration:2000, |
| // | properties: { |
| // | width: { start: '200', end: '400', unit:"px" }, |
| // | height: { start:'200', end: '400', unit:"px" }, |
| // | paddingTop: { start:'5', end:'50', unit:"px" } |
| // | } |
| // | }).play(); |
| // |
| |
| args.node = d.byId(args.node); |
| if(!args.easing){ args.easing = d._defaultEasing; } |
| |
| var anim = new d._Animation(args); |
| d.connect(anim, "beforeBegin", anim, function(){ |
| var pm = {}; |
| for(var p in this.properties){ |
| // Make shallow copy of properties into pm because we overwrite some values below. |
| // In particular if start/end are functions we don't want to overwrite them or |
| // the functions won't be called if the animation is reused. |
| var prop = (pm[p] = d.mixin({}, this.properties[p])); |
| |
| if(d.isFunction(prop.start)){ |
| prop.start = prop.start(); |
| } |
| if(d.isFunction(prop.end)){ |
| prop.end = prop.end(); |
| } |
| |
| var isColor = (p.toLowerCase().indexOf("color") >= 0); |
| function getStyle(node, p){ |
| // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable: |
| var v = ({height: node.offsetHeight, width: node.offsetWidth})[p]; |
| if(v !== undefined){ return v; } |
| v = d.style(node, p); |
| return (p=="opacity") ? Number(v) : parseFloat(v); |
| } |
| if(!("end" in prop)){ |
| prop.end = getStyle(this.node, p); |
| }else if(!("start" in prop)){ |
| prop.start = getStyle(this.node, p); |
| } |
| |
| if(isColor){ |
| // console.debug("it's a color!"); |
| prop.start = new d.Color(prop.start); |
| prop.end = new d.Color(prop.end); |
| }else{ |
| prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start); |
| } |
| // console.debug("start:", prop.start); |
| // console.debug("end:", prop.end); |
| } |
| this.curve = new PropLine(pm); |
| }); |
| d.connect(anim, "onAnimate", anim, function(propValues){ |
| // try{ |
| for(var s in propValues){ |
| // console.debug(s, propValues[s], this.node.style[s]); |
| d.style(this.node, s, propValues[s]); |
| // this.node.style[s] = propValues[s]; |
| } |
| // }catch(e){ console.debug(dojo.toJson(e)); } |
| }); |
| return anim; // dojo._Animation |
| } |
| })(); |
| |
| } |
| |