This repository has been archived on 2020-05-27. You can view files and clone it, but cannot push or open issues/pull-requests.
grindable/public/javascripts/dojo/dojo.js.uncompressed.js

10857 lines
322 KiB
JavaScript

if(typeof dojo == "undefined"){
/**
* @file bootstrap1.js
*
* summary: First file that is loaded that 'bootstraps' the entire dojo library suite.
* note: Must run before hostenv_*.js file.
*
* @author Copyright 2004 Mark D. Anderson (mda@discerning.com)
* TODOC: should the copyright be changed to Dojo Foundation?
* @license Licensed under the Academic Free License 2.1 http://www.opensource.org/licenses/afl-2.1.php
*
* $Id: dojo.js.uncompressed.js,v 1.1 2006/09/08 05:57:55 penguinc Exp $
*/
// TODOC: HOW TO DOC THE BELOW?
// @global: 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
// - allowQueryConfig: false
// - baseScriptUri: ""
// - baseRelativePath: ""
// - libraryScriptUri: ""
// - iePreventClobber: false
// - ieClobberMinimal: true
// - locale: undefined
// - extraLocale: undefined
// - preventBackButtonFix: true
// - searchIds: []
// - parseWidgets: true
// TODOC: HOW TO DOC THESE VARIABLES?
// TODOC: IS THIS A COMPLETE LIST?
// 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.
// TODOC: is this still true? Release notes for 0.3 indicated they could be set after load.
//
//TODOC: HOW TO DOC THIS?
// @global: dj_global
// summary:
// an alias for the top-level global object in the host environment
// (e.g., the window object in a browser).
// description:
// Refer to 'dj_global' rather than referring to window to ensure your
// code runs correctly in contexts other than web browsers (eg: Rhino on a server).
// TODO: replace this with dojo._currentContext
var dj_global = this;
function dj_undef(/*String*/ name, /*Object?*/ object){
//summary: Returns true if 'name' is defined on 'object' (or globally if 'object' is null).
//description: Note that 'defined' and 'exists' are not the same concept.
//Before dojo.global() is defined, object can not be null
if(object==null){ object = dojo.global(); }
// exception if object is not an Object
return (typeof object[name] == "undefined"); // Boolean
}
// make sure djConfig is defined
if(dj_undef("djConfig", this)){
var djConfig = {};
}
//TODOC: HOW TO DOC THIS?
// dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
if(dj_undef("dojo", this)){
var dojo = {};
}
//These are private variables, and should not be used; use dojo.global() and dojo.doc() instead
//this variable should probably have a better name
dojo._currentContext = this;
if(!dj_undef("document", dojo._currentContext)){
dojo._currentDocument = this.document;
}
// Override locale setting, if specified
dojo.locale = djConfig.locale;
//TODOC: HOW TO DOC THIS?
dojo.version = {
// summary: version number of this instance of dojo.
major: 0, minor: 0, patch: 0, flag: "dev",
revision: Number("$Rev: 4898 $".match(/[0-9]+/)[0]),
toString: function(){
with(dojo.version){
return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
}
}
}
dojo.evalProp = function(/*String*/ name, /*Object*/ object, /*Boolean?*/ create){
// summary: Returns 'object[name]'. If not defined and 'create' is true, will return a new Object.
// description:
// Returns null if 'object[name]' is not defined and 'create' is not true.
// Note: 'defined' and 'exists' are not the same concept.
return (object && !dj_undef(name, object) ? object[name] : (create ? (object[name]={}) : undefined)); // mixed
}
dojo.parseObjPath = function(/*String*/ path, /*Object?*/ context, /*Boolean?*/ create){
// summary: Parse string path to an object, and return corresponding object reference and property name.
// description:
// Returns an object with two properties, 'obj' and 'prop'.
// 'obj[prop]' is the reference indicated by 'path'.
// path: Path to an object, in the form "A.B.C".
// context: Object to use as root of path. Defaults to 'dj_global'.
// create: If true, Objects will be created at any point along the 'path' that is undefined.
var object = (context != null ? context : dj_global);
var names = path.split('.');
var prop = names.pop();
for (var i=0,l=names.length;i<l && object;i++){
object = dojo.evalProp(names[i], object, create);
}
return {obj: object, prop: prop}; // Object: {obj: Object, prop: String}
}
dojo.evalObjPath = function(/*String*/ path, /*Boolean?*/ create){
// summary: Return the value of object at 'path' in the global scope, without using 'eval()'.
// path: Path to an object, in the form "A.B.C".
// create: If true, Objects will be created at any point along the 'path' that is undefined.
if(typeof path != "string"){
return dj_global;
}
// fast path for no periods
if(path.indexOf('.') == -1){
return dojo.evalProp(path, dj_global, create); // mixed
}
//MOW: old 'with' syntax was confusing and would throw an error if parseObjPath returned null.
var ref = dojo.parseObjPath(path, dj_global, create);
if(ref){
return dojo.evalProp(ref.prop, ref.obj, create); // mixed
}
return null;
}
// ****************************************************************
// global public utils
// TODOC: DO WE WANT TO NOTE THAT THESE ARE GLOBAL PUBLIC UTILS?
// ****************************************************************
dojo.global = function(){
// summary:
// return the top-level global object in the host environment
// (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 (eg: Rhino on a server).
return dojo._currentContext;
}
dojo.doc = function(){
// summary:
// return the document object associated with the dojo.global()
return dojo._currentDocument;
}
dojo.body = function(){
// summary:
// return the body object associated with dojo.doc()
// Note: document.body is not defined for a strict xhtml document
return dojo.doc().body || dojo.doc().getElementsByTagName("body")[0];
}
dojo.withGlobal = function(/*Object*/globalObject, /*Function*/callback, /*Object?*/thisObject /* ... */){
// 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 oldDoc = dojo._currentDocument;
var oldWin = dojo._currentContext;
var rval;
try{
dojo._currentContext = globalObject;
dojo._currentDocument = globalObject.document;
if(thisObject){ rval = dojo.lang.curryArguments(thisObject, callback, arguments, 3); }
else{ rval = callback(); }
} catch(e) {
dojo._currentContext = oldWin;
dojo._currentDocument = oldDoc;
throw e;
}
dojo._currentContext = oldWin;
dojo._currentDocument = oldDoc;
return rval;
}
dojo.withDoc = function (/*Object*/globalObject, /*Function*/callback, /*Object?*/thisObject /* ... */) {
// summary:
// Call callback with globalObject 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 oldDoc = this._currentDocument;
var rval;
try{
dojo._currentDocument = globalObject;
if(thisObject){ rval = dojo.lang.curryArguments(thisObject, callback, arguments, 3); }
else{ rval = callback(); }
} catch(e) {
dojo._currentDocument = oldDoc;
throw e;
}
dojo._currentDocument = oldDoc;
return rval;
}
dojo.errorToString = function(/*Error*/ exception){
// summary: Return an exception's 'message', 'description' or text.
// TODO: overriding Error.prototype.toString won't accomplish this?
// ... since natively generated Error objects do not always reflect such things?
if(!dj_undef("message", exception)){
return exception.message; // String
}else if(!dj_undef("description", exception)){
return exception.description; // String
}else{
return exception; // Error
}
}
dojo.raise = function(/*String*/ message, /*Error?*/ exception){
// summary: Throw an error message, appending text of 'exception' if provided.
// note: Also prints a message to the user using 'dojo.hostenv.println'.
if(exception){
message = message + ": "+dojo.errorToString(exception);
}
// print the message to the user if hostenv.println is defined
try { dojo.hostenv.println("FATAL: "+message); } catch (e) {}
throw Error(message);
}
//Stub functions so things don't break.
//TODOC: HOW TO DOC THESE?
dojo.debug = function(){}
dojo.debugShallow = function(obj){}
dojo.profile = { start: function(){}, end: function(){}, stop: function(){}, dump: function(){} };
function dj_eval(/*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.
return dj_global.eval ? dj_global.eval(scriptFragment) : eval(scriptFragment); // mixed
}
dojo.unimplemented = function(/*String*/ funcname, /*String?*/ extra){
// summary: Throw an exception because some function is not implemented.
// extra: Text to append to the exception message.
var message = "'" + funcname + "' not implemented";
if (extra != null) { message += " " + extra; }
dojo.raise(message);
}
dojo.deprecated = function(/*String*/ behaviour, /*String?*/ extra, /*String?*/ removal){
// summary: Log a debug message to indicate that a behavior has been deprecated.
// extra: Text to append to the message.
// removal: Text to indicate when in the future the behavior will be removed.
var message = "DEPRECATED: " + behaviour;
if(extra){ message += " " + extra; }
if(removal){ message += " -- will be removed in version: " + removal; }
dojo.debug(message);
}
dojo.inherits = function(/*Function*/ subclass, /*Function*/ superclass){
// summary: Set up inheritance between two classes.
if(typeof superclass != 'function'){
dojo.raise("dojo.inherits: superclass argument ["+superclass+"] must be a function (subclass: [" + subclass + "']");
}
subclass.prototype = new superclass();
subclass.prototype.constructor = subclass;
subclass.superclass = superclass.prototype;
// DEPRICATED: super is a reserved word, use 'superclass'
subclass['super'] = superclass.prototype;
}
dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
// summary: Adds all properties and methods of props to obj.
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.protoype
if(typeof tobj[x] == "undefined" || tobj[x] != props[x]) {
obj[x] = props[x];
}
}
// IE doesn't recognize custom toStrings in for..in
if(dojo.render.html.ie && dojo.lang.isFunction(props["toString"]) && props["toString"] != obj["toString"]) {
obj.toString = props.toString;
}
return obj;
}
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++){
dojo._mixin(obj, arguments[i]);
}
return obj; // Object
}
dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
// summary: Adds all properties and methods of props to constructors 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;
}
dojo.render = (function(){
//TODOC: HOW TO DOC THIS?
// summary: Details rendering support, OS and browser of the current environment.
// TODOC: is this something many folks will interact with? If so, we should doc the structure created...
function vscaffold(prefs, names){
var tmp = {
capable: false,
support: {
builtin: false,
plugin: false
},
prefixes: prefs
};
for(var i=0; i<names.length; i++){
tmp[names[i]] = false;
}
return tmp;
}
return {
name: "",
ver: dojo.version,
os: { win: false, linux: false, osx: false },
html: vscaffold(["html"], ["ie", "opera", "khtml", "safari", "moz"]),
svg: vscaffold(["svg"], ["corel", "adobe", "batik"]),
vml: vscaffold(["vml"], ["ie"]),
swf: vscaffold(["Swf", "Flash", "Mm"], ["mm"]),
swt: vscaffold(["Swt"], ["ibm"])
};
})();
// ****************************************************************
// dojo.hostenv methods that must be defined in hostenv_*.js
// ****************************************************************
/**
* The interface definining the interaction with the EcmaScript host environment.
*/
/*
* None of these methods should ever be called directly by library users.
* Instead public methods such as loadModule should be called instead.
*/
dojo.hostenv = (function(){
// TODOC: HOW TO DOC THIS?
// summary: Provides encapsulation of behavior that changes across different 'host environments'
// (different browsers, server via Rhino, etc).
// description: None of these methods should ever be called directly by library users.
// Use public methods such as 'loadModule' instead.
// default configuration options
var config = {
isDebug: false,
allowQueryConfig: false,
baseScriptUri: "",
baseRelativePath: "",
libraryScriptUri: "",
iePreventClobber: false,
ieClobberMinimal: true,
preventBackButtonFix: true,
searchIds: [],
parseWidgets: true
};
if (typeof djConfig == "undefined") { djConfig = config; }
else {
for (var option in config) {
if (typeof djConfig[option] == "undefined") {
djConfig[option] = config[option];
}
}
}
return {
name_: '(unset)',
version_: '(unset)',
getName: function(){
// sumary: Return the name of the host environment.
return this.name_; // String
},
getVersion: function(){
// summary: Return the version of the hostenv.
return this.version_; // String
},
getText: function(/*String*/ uri){
// summary: Read the plain/text contents at the specified 'uri'.
// description:
// If 'getText()' is not implemented, then it is necessary to override
// 'loadUri()' with an implementation that doesn't rely on it.
dojo.unimplemented('getText', "uri=" + uri);
}
};
})();
dojo.hostenv.getBaseScriptUri = function(){
// summary: Return the base script uri that other scripts are found relative to.
// TODOC: HUH? This comment means nothing to me. What other scripts? Is this the path to other dojo libraries?
// MAYBE: Return the base uri to scripts in the dojo library. ???
// return: Empty string or a path ending in '/'.
if(djConfig.baseScriptUri.length){
return djConfig.baseScriptUri;
}
// MOW: Why not:
// uri = djConfig.libraryScriptUri || djConfig.baseRelativePath
// ??? Why 'new String(...)'
var uri = new String(djConfig.libraryScriptUri||djConfig.baseRelativePath);
if (!uri) { dojo.raise("Nothing returned by getLibraryScriptUri(): " + uri); }
// MOW: uri seems to not be actually used. Seems to be hard-coding to djConfig.baseRelativePath... ???
var lastslash = uri.lastIndexOf('/'); // MOW ???
djConfig.baseScriptUri = djConfig.baseRelativePath;
return djConfig.baseScriptUri; // String
}
/*
* loader.js - runs before the hostenv_*.js file. Contains all of the package loading methods.
*/
//A semi-colon is at the start of the line because after doing a build, this function definition
//get compressed onto the same line as the last line in bootstrap1.js. That list line is just a
//curly bracket, and the browser complains about that syntax. The semicolon fixes it. Putting it
//here instead of at the end of bootstrap1.js, since it is more of an issue for this file, (using
//the closure), and bootstrap1.js could change in the future.
;(function(){
//Additional properties for dojo.hostenv
var _addHostEnv = {
pkgFileName: "__package__",
// for recursion protection
loading_modules_: {},
loaded_modules_: {},
addedToLoadingCount: [],
removedFromLoadingCount: [],
inFlightCount: 0,
// FIXME: it should be possible to pull module prefixes in from djConfig
modulePrefixes_: {
dojo: {name: "dojo", value: "src"}
},
setModulePrefix: function(module, prefix){
this.modulePrefixes_[module] = {name: module, value: prefix};
},
getModulePrefix: function(module){
var mp = this.modulePrefixes_;
if((mp[module])&&(mp[module]["name"])){
return mp[module].value;
}
return module;
},
getTextStack: [],
loadUriStack: [],
loadedUris: [],
//WARNING: This variable is referenced by packages outside of bootstrap: FloatingPane.js and undo/browser.js
post_load_: false,
//Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
modulesLoadedListeners: [],
unloadListeners: [],
loadNotifying: false
};
//Add all of these properties to dojo.hostenv
for(var param in _addHostEnv){
dojo.hostenv[param] = _addHostEnv[param];
}
})();
/**
* 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.
*
* For now, we do not have an implementation of a true search path. We
* consider only the single base script uri, as returned by getBaseScriptUri().
*
* @param relpath A relative path to a script (no leading '/', and typically
* ending in '.js').
* @param module A module whose existance to check for after loading a path.
* Can be used to determine success or failure of the load.
* @param cb a function to pass the result of evaluating the script (optional)
*/
dojo.hostenv.loadPath = function(relpath, module /*optional*/, cb /*optional*/){
var uri;
if((relpath.charAt(0) == '/')||(relpath.match(/^\w+:/))){
// dojo.raise("relpath '" + relpath + "'; must be relative");
uri = relpath;
}else{
uri = this.getBaseScriptUri() + relpath;
}
if(djConfig.cacheBust && dojo.render.html.capable){
uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,"");
}
try{
return ((!module) ? this.loadUri(uri, cb) : this.loadUriAndCheck(uri, module, cb));
}catch(e){
dojo.debug(e);
return false;
}
}
/**
* Reads the contents of the URI, and evaluates the contents.
* Returns true if it succeeded. Returns false if the URI reading failed.
* Throws if the evaluation throws.
* The result of the eval is not available to the caller TODO: now it is; was this a deliberate restriction?
*
* @param uri a uri which points at the script to be loaded
* @param cb a function to process the result of evaluating the script as an expression (optional)
*/
dojo.hostenv.loadUri = function(uri, cb /*optional*/){
if(this.loadedUris[uri]){
return 1;
}
var contents = this.getText(uri, null, true);
if(contents == null){ return 0; }
this.loadedUris[uri] = true;
if(cb){ contents = '('+contents+')'; }
var value = dj_eval(contents);
if(cb){
cb(value);
}
return 1;
}
// FIXME: probably need to add logging to this method
dojo.hostenv.loadUriAndCheck = function(uri, module, cb){
var ok = true;
try{
ok = this.loadUri(uri, cb);
}catch(e){
dojo.debug("failed loading ", uri, " with error: ", e);
}
return ((ok)&&(this.findModule(module, false))) ? true : false;
}
dojo.loaded = function(){ }
dojo.unloaded = function(){ }
dojo.hostenv.loaded = function(){
this.loadNotifying = true;
this.post_load_ = true;
var mll = this.modulesLoadedListeners;
for(var x=0; x<mll.length; x++){
mll[x]();
}
//Clear listeners so new ones can be added
//For other xdomain package loads after the initial load.
this.modulesLoadedListeners = [];
this.loadNotifying = false;
dojo.loaded();
}
dojo.hostenv.unloaded = function(){
var mll = this.unloadListeners;
while(mll.length){
(mll.pop())();
}
dojo.unloaded();
}
/*
Call styles:
dojo.addOnLoad(functionPointer)
dojo.addOnLoad(object, "functionName")
*/
dojo.addOnLoad = function(obj, fcnName) {
var dh = dojo.hostenv;
if(arguments.length == 1) {
dh.modulesLoadedListeners.push(obj);
} else if(arguments.length > 1) {
dh.modulesLoadedListeners.push(function() {
obj[fcnName]();
});
}
//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(dh.post_load_ && dh.inFlightCount == 0 && !dh.loadNotifying){
dh.callLoaded();
}
}
dojo.addOnUnload = function(obj, fcnName){
var dh = dojo.hostenv;
if(arguments.length == 1){
dh.unloadListeners.push(obj);
} else if(arguments.length > 1) {
dh.unloadListeners.push(function() {
obj[fcnName]();
});
}
}
dojo.hostenv.modulesLoaded = function(){
if(this.post_load_){ return; }
if((this.loadUriStack.length==0)&&(this.getTextStack.length==0)){
if(this.inFlightCount > 0){
dojo.debug("files still in flight!");
return;
}
dojo.hostenv.callLoaded();
}
}
dojo.hostenv.callLoaded = function(){
if(typeof setTimeout == "object"){
setTimeout("dojo.hostenv.loaded();", 0);
}else{
dojo.hostenv.loaded();
}
}
dojo.hostenv.getModuleSymbols = function(modulename) {
var syms = modulename.split(".");
for(var i = syms.length - 1; i > 0; i--){
var parentModule = syms.slice(0, i).join(".");
var parentModulePath = this.getModulePrefix(parentModule);
if(parentModulePath != parentModule){
syms.splice(0, i, parentModulePath);
break;
}
}
return syms;
}
//list of all defined namespaces
dojo._namespaces = {};
(function(){
//list of namespaces being loaded, to prevent recursion
var loadingNamespaces = {};
//list of all namespaces that were needed, but didn't have the required file in the dojo/src/namespaces folder.
//This list ensures that a namespace will only be looked for once, rather than repeatedly trying to load the namespace descriptor file
var failedNamespaces = {};
//This returns a namespace with the given short name. If the namespace has not been loaded already, it tries to load it.
dojo.getNamespace = function(nsPrefix){
if(!dojo._namespaces[nsPrefix] && !failedNamespaces[nsPrefix]){
var req = dojo.require;
var nsFile = "dojo.namespaces."+nsPrefix;
if(!loadingNamespaces[nsFile]){
loadingNamespaces[nsFile]=true;
req(nsFile, false, true);
loadingNamespaces[nsFile]=false;
if(!dojo._namespaces[nsPrefix]){
failedNamespaces[nsPrefix] = true; //only look for a namespace once
}
}
}
return dojo._namespaces[nsPrefix];
};
})();
/**
* 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,
* followed by "A.js".
*
* 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.hostenv.loadModule("A.B")) {
* ...
* }
*
* And to import just the leaf symbol:
*
* var B = dojo.hostenv.loadModule("A.B");
* ...
*
* dj_load is an alias for dojo.hostenv.loadModule
*/
dojo.hostenv._global_omit_module_check = false;
dojo.hostenv.loadModule = function(modulename, exact_only, omit_module_check){
if(!modulename){ return; }
omit_module_check = this._global_omit_module_check || omit_module_check;
var module = this.findModule(modulename, false);
if(module){
return module;
}
// protect against infinite recursion from mutual dependencies
if(dj_undef(modulename, this.loading_modules_)){
this.addedToLoadingCount.push(modulename);
}
this.loading_modules_[modulename] = 1;
// convert periods to slashes
var relpath = modulename.replace(/\./g, '/') + '.js';
var nsyms = modulename.split(".");
if(djConfig.autoLoadNamespace){ dojo.getNamespace(nsyms[0]); }
var syms = this.getModuleSymbols(modulename);
var startedRelative = ((syms[0].charAt(0) != '/')&&(!syms[0].match(/^\w+:/)));
var last = syms[syms.length - 1];
// figure out if we're looking for a full package, if so, we want to do
// things slightly diffrently
if(last=="*"){
modulename = (nsyms.slice(0, -1)).join('.');
while(syms.length){
syms.pop();
syms.push(this.pkgFileName);
relpath = syms.join("/") + '.js';
if(startedRelative && (relpath.charAt(0)=="/")){
relpath = relpath.slice(1);
}
ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null));
if(ok){ break; }
syms.pop();
}
}else{
relpath = syms.join("/") + '.js';
modulename = nsyms.join('.');
var ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null));
if((!ok)&&(!exact_only)){
syms.pop();
while(syms.length){
relpath = syms.join('/') + '.js';
ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null));
if(ok){ break; }
syms.pop();
relpath = syms.join('/') + '/'+this.pkgFileName+'.js';
if(startedRelative && (relpath.charAt(0)=="/")){
relpath = relpath.slice(1);
}
ok = this.loadPath(relpath, ((!omit_module_check) ? modulename : null));
if(ok){ break; }
}
}
if((!ok)&&(!omit_module_check)){
dojo.raise("Could not load '" + modulename + "'; last tried '" + relpath + "'");
}
}
// check that the symbol was defined
//Don't bother if we're doing xdomain (asynchronous) loading.
if(!omit_module_check && !this["isXDomain"]){
// pass in false so we can give better error
module = this.findModule(modulename, false);
if(!module){
dojo.raise("symbol '" + modulename + "' is not defined after loading '" + relpath + "'");
}
}
return module;
}
/**
* startPackage("A.B") follows the path, and at each level creates a new empty
* object or uses what already exists. It returns the result.
*/
dojo.hostenv.startPackage = function(packname){
var modref = dojo.evalObjPath((packname.split(".").slice(0, -1)).join('.'));
this.loaded_modules_[(new String(packname)).toLowerCase()] = modref;
var syms = packname.split(/\./);
if(syms[syms.length-1]=="*"){
syms.pop();
}
return dojo.evalObjPath(syms.join("."), true);
}
/**
* findModule("A.B") returns the object A.B if it exists, otherwise null.
* @param modulename A string like 'A.B'.
* @param must_exist Optional, defualt false. throw instead of returning null
* if the module does not currently exist.
*/
dojo.hostenv.findModule = function(modulename, must_exist){
// check cache
/*
if(!dj_undef(modulename, this.modules_)){
return this.modules_[modulename];
}
*/
var lmn = (new String(modulename)).toLowerCase();
if(this.loaded_modules_[lmn]){
return this.loaded_modules_[lmn];
}
// see if symbol is defined anyway
var module = dojo.evalObjPath(modulename);
if((modulename)&&(typeof module != 'undefined')&&(module)){
this.loaded_modules_[lmn] = module;
return module;
}
if(must_exist){
dojo.raise("no loaded module named '" + modulename + "'");
}
return null;
}
//Start of old bootstrap2:
/*
* This method taks a "map" of arrays which one can use to optionally load dojo
* modules. The map is indexed by the possible dojo.hostenv.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.kwCompoundRequire({
* browser: [
* ["foo.bar.baz", true, true], // an example that passes multiple args to loadModule()
* "foo.sample.*",
* "foo.test,
* ],
* default: [ "foo.sample.*" ],
* common: [ "really.important.module.*" ]
* });
*/
dojo.kwCompoundRequire = function(modMap){
var common = modMap["common"]||[];
var result = (modMap[dojo.hostenv.name_]) ? common.concat(modMap[dojo.hostenv.name_]||[]) : common.concat(modMap["default"]||[]);
for(var x=0; x<result.length; x++){
var curr = result[x];
if(curr.constructor == Array){
dojo.hostenv.loadModule.apply(dojo.hostenv, curr);
}else{
dojo.hostenv.loadModule(curr);
}
}
}
dojo.require = function(){
dojo.hostenv.loadModule.apply(dojo.hostenv, arguments);
}
dojo.requireIf = function(){
if((arguments[0] === true)||(arguments[0]=="common")||(arguments[0] && dojo.render[arguments[0]].capable)){
var args = [];
for (var i = 1; i < arguments.length; i++) { args.push(arguments[i]); }
dojo.require.apply(dojo, args);
}
}
dojo.requireAfterIf = dojo.requireIf;
dojo.provide = function(){
return dojo.hostenv.startPackage.apply(dojo.hostenv, arguments);
}
dojo.setModulePrefix = function(module, prefix){
return dojo.hostenv.setModulePrefix(module, prefix);
}
// determine if an object supports a given method
// useful for longer api chains where you have to test each object in the chain
dojo.exists = function(obj, name){
var p = name.split(".");
for(var i = 0; i < p.length; i++){
if(!(obj[p[i]])){ return false; }
obj = obj[p[i]];
}
return true;
}
};
if(typeof window == 'undefined'){
dojo.raise("no window object");
}
// attempt to figure out the path to dojo if it isn't set in the config
(function() {
// before we get any further with the config options, try to pick them out
// of the URL. Most of this code is from NW
if(djConfig.allowQueryConfig){
var baseUrl = document.location.toString(); // FIXME: use location.query instead?
var params = baseUrl.split("?", 2);
if(params.length > 1){
var paramStr = params[1];
var pairs = paramStr.split("&");
for(var x in pairs){
var sp = pairs[x].split("=");
// FIXME: is this eval dangerous?
if((sp[0].length > 9)&&(sp[0].substr(0, 9) == "djConfig.")){
var opt = sp[0].substr(9);
try{
djConfig[opt]=eval(sp[1]);
}catch(e){
djConfig[opt]=sp[1];
}
}
}
}
}
if(((djConfig["baseScriptUri"] == "")||(djConfig["baseRelativePath"] == "")) &&(document && document.getElementsByTagName)){
var scripts = document.getElementsByTagName("script");
var rePkg = /(__package__|dojo|bootstrap1)\.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) {
var root = src.substring(0, m.index);
if(src.indexOf("bootstrap1") > -1) { root += "../"; }
if(!this["djConfig"]) { djConfig = {}; }
if(djConfig["baseScriptUri"] == "") { djConfig["baseScriptUri"] = root; }
if(djConfig["baseRelativePath"] == "") { djConfig["baseRelativePath"] = root; }
break;
}
}
}
// fill in the rendering support information in dojo.render.*
var dr = dojo.render;
var drh = dojo.render.html;
var drs = dojo.render.svg;
var dua = (drh.UA = navigator.userAgent);
var dav = (drh.AV = navigator.appVersion);
var t = true;
var f = false;
drh.capable = t;
drh.support.builtin = t;
dr.ver = parseFloat(drh.AV);
dr.os.mac = dav.indexOf("Macintosh") >= 0;
dr.os.win = dav.indexOf("Windows") >= 0;
// could also be Solaris or something, but it's the same browser
dr.os.linux = dav.indexOf("X11") >= 0;
drh.opera = dua.indexOf("Opera") >= 0;
drh.khtml = (dav.indexOf("Konqueror") >= 0)||(dav.indexOf("Safari") >= 0);
drh.safari = dav.indexOf("Safari") >= 0;
var geckoPos = dua.indexOf("Gecko");
drh.mozilla = drh.moz = (geckoPos >= 0)&&(!drh.khtml);
if (drh.mozilla) {
// gecko version is YYYYMMDD
drh.geckoVersion = dua.substring(geckoPos + 6, geckoPos + 14);
}
drh.ie = (document.all)&&(!drh.opera);
drh.ie50 = drh.ie && dav.indexOf("MSIE 5.0")>=0;
drh.ie55 = drh.ie && dav.indexOf("MSIE 5.5")>=0;
drh.ie60 = drh.ie && dav.indexOf("MSIE 6.0")>=0;
drh.ie70 = drh.ie && dav.indexOf("MSIE 7.0")>=0;
// TODO: is the HTML LANG attribute relevant?
dojo.locale = dojo.locale || (drh.ie ? navigator.userLanguage : navigator.language).toLowerCase();
dr.vml.capable=drh.ie;
drs.capable = f;
drs.support.plugin = f;
drs.support.builtin = f;
var tdoc = window["document"];
var tdi = tdoc["implementation"];
if((tdi)&&(tdi["hasFeature"])&&(tdi.hasFeature("org.w3c.dom.svg", "1.0"))){
drs.capable = t;
drs.support.builtin = t;
drs.support.plugin = f;
}
// webkits after 420 support SVG natively. The test string is "AppleWebKit/420+"
if(drh.safari){
var tmp = dua.split("AppleWebKit/")[1];
var ver = parseFloat(tmp.split(" ")[0]);
if(ver >= 420){
drs.capable = t;
drs.support.builtin = t;
drs.support.plugin = f;
}
}
})();
dojo.hostenv.startPackage("dojo.hostenv");
dojo.render.name = dojo.hostenv.name_ = 'browser';
dojo.hostenv.searchIds = [];
// These are in order of decreasing likelihood; this will change in time.
dojo.hostenv._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
dojo.hostenv.getXmlhttpObject = function(){
var http = null;
var last_e = null;
try{ http = new XMLHttpRequest(); }catch(e){}
if(!http){
for(var i=0; i<3; ++i){
var progid = dojo.hostenv._XMLHTTP_PROGIDS[i];
try{
http = new ActiveXObject(progid);
}catch(e){
last_e = e;
}
if(http){
dojo.hostenv._XMLHTTP_PROGIDS = [progid]; // so faster next time
break;
}
}
/*if(http && !http.toString) {
http.toString = function() { "[object XMLHttpRequest]"; }
}*/
}
if(!http){
return dojo.raise("XMLHTTP not available", last_e);
}
return http;
}
/**
* Read the contents of the specified uri and return those contents.
*
* @param uri A relative or absolute uri. If absolute, it still must be in the
* same "domain" as we are.
*
* @param async_cb If not specified, load synchronously. If specified, load
* asynchronously, and use async_cb as the progress handler which takes the
* xmlhttp object as its argument. If async_cb, this function returns null.
*
* @param fail_ok Default false. If fail_ok and !async_cb and loading fails,
* return null instead of throwing.
*/
dojo.hostenv._blockAsync = false;
dojo.hostenv.getText = function(uri, async_cb, fail_ok){
// 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
// hostenv._blockAsync must also be checked in BrowserIO's watchInFlight()
// NOTE: must be declared before scope switches ie. this.getXmlhttpObject()
if(!async_cb){ this._blockAsync = true; }
var http = this.getXmlhttpObject();
function isDocumentOk(http){
var stat = http["status"];
// allow a 304 use cache, needed in konq (is this compliant with the http spec?)
return Boolean((!stat)||((200 <= stat)&&(300 > stat))||(stat==304));
}
if(async_cb){
var _this = this, timer = null, gbl = dojo.global();
var xhr = dojo.evalObjPath("dojo.io.XMLHTTPTransport");
http.onreadystatechange = function(){
if(timer){ gbl.clearTimeout(timer); timer = null; }
if(_this._blockAsync || (xhr && xhr._blockAsync)){
timer = gbl.setTimeout(function () { http.onreadystatechange.apply(this); }, 10);
}else{
if(4==http.readyState){
if(isDocumentOk(http)){
// dojo.debug("LOADED URI: "+uri);
async_cb(http.responseText);
}
}
}
}
}
http.open('GET', uri, async_cb ? true : false);
try{
http.send(null);
if(async_cb){
return null;
}
if(!isDocumentOk(http)){
var err = Error("Unable to load "+uri+" status:"+ http.status);
err.status = http.status;
err.responseText = http.responseText;
throw err;
}
}catch(e){
this._blockAsync = false;
if((fail_ok)&&(!async_cb)){
return null;
}else{
throw e;
}
}
this._blockAsync = false;
return http.responseText;
}
/*
* It turns out that if we check *right now*, as this script file is being loaded,
* then the last script element in the window DOM is ourselves.
* That is because any subsequent script elements haven't shown up in the document
* object yet.
*/
/*
function dj_last_script_src() {
var scripts = window.document.getElementsByTagName('script');
if(scripts.length < 1){
dojo.raise("No script elements in window.document, so can't figure out my script src");
}
var script = scripts[scripts.length - 1];
var src = script.src;
if(!src){
dojo.raise("Last script element (out of " + scripts.length + ") has no src");
}
return src;
}
if(!dojo.hostenv["library_script_uri_"]){
dojo.hostenv.library_script_uri_ = dj_last_script_src();
}
*/
dojo.hostenv.defaultDebugContainerId = 'dojoDebug';
dojo.hostenv._println_buffer = [];
dojo.hostenv._println_safe = false;
dojo.hostenv.println = function (line){
if(!dojo.hostenv._println_safe){
dojo.hostenv._println_buffer.push(line);
}else{
try {
var console = document.getElementById(djConfig.debugContainerId ?
djConfig.debugContainerId : dojo.hostenv.defaultDebugContainerId);
if(!console) { console = dojo.body(); }
var div = document.createElement("div");
div.appendChild(document.createTextNode(line));
console.appendChild(div);
} catch (e) {
try{
// safari needs the output wrapped in an element for some reason
document.write("<div>" + line + "</div>");
}catch(e2){
window.status = line;
}
}
}
}
dojo.addOnLoad(function(){
dojo.hostenv._println_safe = true;
while(dojo.hostenv._println_buffer.length > 0){
dojo.hostenv.println(dojo.hostenv._println_buffer.shift());
}
});
function dj_addNodeEvtHdlr(node, evtName, fp, capture){
var oldHandler = node["on"+evtName] || function(){};
node["on"+evtName] = function(){
fp.apply(node, arguments);
oldHandler.apply(node, arguments);
}
return true;
}
/* Uncomment this to allow init after DOMLoad, not after window.onload
// Mozilla exposes the event we could use
if (dojo.render.html.mozilla) {
document.addEventListener("DOMContentLoaded", dj_load_init, null);
}
// for Internet Explorer. readyState will not be achieved on init call, but dojo doesn't need it
//Tighten up the comments below to allow init after DOMLoad, not after window.onload
/ * @cc_on @ * /
/ * @if (@_win32)
document.write("<script defer>dj_load_init()<"+"/script>");
/ * @end @ * /
*/
// default for other browsers
// potential TODO: apply setTimeout approach for other browsers
// that will cause flickering though ( document is loaded and THEN is processed)
// maybe show/hide required in this case..
// TODO: other browsers may support DOMContentLoaded/defer attribute. Add them to above.
dj_addNodeEvtHdlr(window, "load", function(){
// allow multiple calls, only first one will take effect
if(arguments.callee.initialized){ return; }
arguments.callee.initialized = true;
var initFunc = function(){
//perform initialization
if(dojo.render.html.ie){
dojo.hostenv.makeWidgets();
}
};
if(dojo.hostenv.inFlightCount == 0){
initFunc();
dojo.hostenv.modulesLoaded();
}else{
dojo.addOnLoad(initFunc);
}
});
dj_addNodeEvtHdlr(window, "unload", function(){
dojo.hostenv.unloaded();
});
dojo.hostenv.makeWidgets = function(){
// you can put searchIds in djConfig and dojo.hostenv at the moment
// we should probably eventually move to one or the other
var sids = [];
if(djConfig.searchIds && djConfig.searchIds.length > 0) {
sids = sids.concat(djConfig.searchIds);
}
if(dojo.hostenv.searchIds && dojo.hostenv.searchIds.length > 0) {
sids = sids.concat(dojo.hostenv.searchIds);
}
if((djConfig.parseWidgets)||(sids.length > 0)){
if(dojo.evalObjPath("dojo.widget.Parse")){
// we must do this on a delay to avoid:
// http://www.shaftek.org/blog/archives/000212.html
// IE is such a tremendous peice of shit.
var parser = new dojo.xml.Parse();
if(sids.length > 0){
for(var x=0; x<sids.length; x++){
var tmpNode = document.getElementById(sids[x]);
if(!tmpNode){ continue; }
var frag = parser.parseElement(tmpNode, null, true);
dojo.widget.getParser().createComponents(frag);
}
}else if(djConfig.parseWidgets){
var frag = parser.parseElement(dojo.body(), null, true);
dojo.widget.getParser().createComponents(frag);
}
}
}
}
dojo.addOnLoad(function(){
if(!dojo.render.html.ie) {
dojo.hostenv.makeWidgets();
}
});
try {
if (dojo.render.html.ie) {
document.namespaces.add("v","urn:schemas-microsoft-com:vml");
document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
}
} catch (e) { }
// stub, over-ridden by debugging code. This will at least keep us from
// breaking when it's not included
dojo.hostenv.writeIncludes = function(){}
dojo.byId = function(id, doc){
if(id && (typeof id == "string" || id instanceof String)){
if(!doc){ doc = dojo.doc(); }
return doc.getElementById(id);
}
return id; // assume it's a node
}
//Semicolon is for when this file is integrated with a custom build on one line
//with some other file's contents. Sometimes that makes things not get defined
//properly, particularly with the using the closure below to do all the work.
;(function(){
//Don't do this work if dojo.js has already done it.
if(typeof dj_usingBootstrap != "undefined"){
return;
}
var isRhino = false;
var isSpidermonkey = false;
var isDashboard = false;
if((typeof this["load"] == "function")&&((typeof this["Packages"] == "function")||(typeof this["Packages"] == "object"))){
isRhino = true;
}else if(typeof this["load"] == "function"){
isSpidermonkey = true;
}else if(window.widget){
isDashboard = true;
}
var tmps = [];
if((this["djConfig"])&&((djConfig["isDebug"])||(djConfig["debugAtAllCosts"]))){
tmps.push("debug.js");
}
if((this["djConfig"])&&(djConfig["debugAtAllCosts"])&&(!isRhino)&&(!isDashboard)){
tmps.push("browser_debug.js");
}
//Support compatibility packages. Right now this only allows setting one
//compatibility package. Might need to revisit later down the line to support
//more than one.
if((this["djConfig"])&&(djConfig["compat"])){
tmps.push("compat/" + djConfig["compat"] + ".js");
}
var loaderRoot = djConfig["baseScriptUri"];
if((this["djConfig"])&&(djConfig["baseLoaderUri"])){
loaderRoot = djConfig["baseLoaderUri"];
}
for(var x=0; x < tmps.length; x++){
var spath = loaderRoot+"src/"+tmps[x];
if(isRhino||isSpidermonkey){
load(spath);
} else {
try {
document.write("<scr"+"ipt type='text/javascript' src='"+spath+"'></scr"+"ipt>");
} catch (e) {
var script = document.createElement("script");
script.src = spath;
document.getElementsByTagName("head")[0].appendChild(script);
}
}
}
})();
// Localization routines
/**
* Returns canonical form of locale, as used by Dojo. All variants are case-insensitive and are separated by '-'
* as specified in RFC 3066
*/
dojo.normalizeLocale = function(locale) {
return locale ? locale.toLowerCase() : dojo.locale;
};
dojo.searchLocalePath = function(locale, down, searchFunc){
locale = dojo.normalizeLocale(locale);
var elements = locale.split('-');
var searchlist = [];
for(var i = elements.length; i > 0; i--){
searchlist.push(elements.slice(0, i).join('-'));
}
searchlist.push(false);
if(down){searchlist.reverse();}
for(var j = searchlist.length - 1; j >= 0; j--){
var loc = searchlist[j] || "ROOT";
var stop = searchFunc(loc);
if(stop){ break; }
}
}
/**
* requireLocalization() is for loading translated bundles provided within a package in the namespace.
* Contents are typically strings, but may be any name/value pair, represented in JSON format.
* A bundle is structured in a program as follows, where modulename is mycode.mywidget and
* bundlename is mybundle:
*
* mycode/
* mywidget/
* nls/
* mybundle.js (the fallback translation, English in this example)
* de/
* mybundle.js
* de-at/
* mybundle.js
* en/
* (empty; use the fallback translation)
* en-us/
* mybundle.js
* en-gb/
* mybundle.js
* es/
* mybundle.js
* ...etc
*
* Each directory is named for a locale as specified by RFC 3066, (http://www.ietf.org/rfc/rfc3066.txt),
* normalized in lowercase.
*
* For a given locale, bundles will be loaded for that locale and all less-specific locales above it, as well
* as a fallback at the root. For example, a search for the "de-at" locale will first load nls/de-at/mybundle.js,
* then nls/de/mybundle.js and finally nls/mybundle.js. Lookups will traverse the locales in this same order
* and flatten all the values into a JS object (see dojo.i18n.getLocalization). A build step can preload the
* bundles to avoid data redundancy and extra network hits.
*
* @param modulename package in which the bundle is found
* @param bundlename bundle name, typically the filename without the '.js' suffix
* @param locale the locale to load (optional) By default, the browser's user locale as defined
* in dojo.locale
*/
dojo.requireLocalization = function(modulename, bundlename, locale /*optional*/){
var bundlepackage = [modulename, "_nls", bundlename].join(".");
var bundle = dojo.hostenv.startPackage(bundlepackage);
dojo.hostenv.loaded_modules_[bundlepackage] = bundle; // this seems to be necessary. why?
if(!dj_undef("dj_localesBuilt", dj_global) && dojo.hostenv.loaded_modules_[bundlepackage]){
locale = dojo.normalizeLocale(locale);
for(var i=0; i<dj_localesBuilt.length; i++){
if(dj_localesBuilt[i] == locale){return;}
}
}
var syms = dojo.hostenv.getModuleSymbols(modulename);
var modpath = syms.concat("nls").join("/");
var inherit = false;
dojo.searchLocalePath(locale, false, function(loc){
var pkg = bundlepackage + "." + loc;
var loaded = false;
if(!dojo.hostenv.findModule(pkg)){
// Mark loaded whether it's found or not, so that further load attempts will not be made
dojo.hostenv.loaded_modules_[pkg] = null;
var module = [modpath];
if(loc != "ROOT"){module.push(loc);}
module.push(bundlename);
var filespec = module.join("/") + '.js';
loaded = dojo.hostenv.loadPath(filespec, null, function(hash){
// Use singleton with prototype to point to other bundle, then mix-in result from loadPath
var clazz = function(){};
clazz.prototype = inherit;
bundle[loc] = new clazz();
for(var j in hash){ bundle[loc][j] = hash[j]; }
});
}else{
loaded = true;
}
if(loaded && bundle[loc]){
inherit = bundle[loc];
}
});
};
(function(){
function preload(locale){
if(!dj_undef("dj_localesGenerated", dj_global)){
dojo.setModulePrefix("nls","nls");
locale = dojo.normalizeLocale(locale);
dojo.searchLocalePath(locale, true, function(loc){
for(var i=0; i<dj_localesGenerated.length;i++){
if(dj_localesGenerated[i] == loc){
dojo.require("nls.dojo_"+loc);
return true;
}
}
return false;
});
}
}
preload(dojo.locale);
var extra = djConfig.extraLocale;
if(extra){
if(!extra instanceof Array){
extra = [extra];
}
for(var i=0; i<extra.length; i++){
preload(extra[i]);
}
var req = dojo.requireLocalization;
dojo.requireLocalization = function(m, b, locale){
req(m,b,locale);
if(locale){return;}
for(var i=0; i<extra.length; i++){
req(m,b,extra[i]);
}
};
}
})();
dojo.provide("dojo.string.common");
/**
* Trim whitespace from 'str'. If 'wh' > 0,
* only trim from start, if 'wh' < 0, only trim
* from end, otherwise trim both ends
*/
dojo.string.trim = function(str, wh){
if(!str.replace){ return str; }
if(!str.length){ return str; }
var re = (wh > 0) ? (/^\s+/) : (wh < 0) ? (/\s+$/) : (/^\s+|\s+$/g);
return str.replace(re, "");
}
/**
* Trim whitespace at the beginning of 'str'
*/
dojo.string.trimStart = function(str) {
return dojo.string.trim(str, 1);
}
/**
* Trim whitespace at the end of 'str'
*/
dojo.string.trimEnd = function(str) {
return dojo.string.trim(str, -1);
}
/**
* Return 'str' repeated 'count' times, optionally
* placing 'separator' between each rep
*/
dojo.string.repeat = function(str, count, separator) {
var out = "";
for(var i = 0; i < count; i++) {
out += str;
if(separator && i < count - 1) {
out += separator;
}
}
return out;
}
/**
* Pad 'str' to guarantee that it is at least 'len' length
* with the character 'c' at either the start (dir=1) or
* end (dir=-1) of the string
*/
dojo.string.pad = function(str, len/*=2*/, c/*='0'*/, dir/*=1*/) {
var out = String(str);
if(!c) {
c = '0';
}
if(!dir) {
dir = 1;
}
while(out.length < len) {
if(dir > 0) {
out = c + out;
} else {
out += c;
}
}
return out;
}
/** same as dojo.string.pad(str, len, c, 1) */
dojo.string.padLeft = function(str, len, c) {
return dojo.string.pad(str, len, c, 1);
}
/** same as dojo.string.pad(str, len, c, -1) */
dojo.string.padRight = function(str, len, c) {
return dojo.string.pad(str, len, c, -1);
}
dojo.provide("dojo.string");
dojo.provide("dojo.lang.common");
// Backwards compatibility
dojo.lang._mixin = dojo._mixin;
dojo.lang.mixin = dojo.mixin;
dojo.lang.extend = dojo.extend;
dojo.lang.find = function( /*Array*/ array,
/*Object*/ value,
/*Boolean?*/ identity,
/*Boolean?*/ findLast){
// summary: Return the index of value in array, returning -1 if not found.
// param: identity: If true, matches with identity comparison (===).
// If false, uses normal comparison (==).
// param: findLast: If true, returns index of last instance of value.
// usage:
// find(array, value[, identity [findLast]]) // recommended
// usage:
// find(value, array[, identity [findLast]]) // deprecated
// support both (array, value) and (value, array)
if(!dojo.lang.isArrayLike(array) && dojo.lang.isArrayLike(value)) {
dojo.deprecated('dojo.lang.find(value, array)', 'use dojo.lang.find(array, value) instead', "0.5");
var temp = array;
array = value;
value = temp;
}
var isString = dojo.lang.isString(array);
if(isString) { array = array.split(""); }
if(findLast) {
var step = -1;
var i = array.length - 1;
var end = -1;
} else {
var step = 1;
var i = 0;
var end = array.length;
}
if(identity){
while(i != end) {
if(array[i] === value){ return i; }
i += step;
}
}else{
while(i != end) {
if(array[i] == value){ return i; }
i += step;
}
}
return -1; // number
}
dojo.lang.indexOf = dojo.lang.find;
dojo.lang.findLast = function(/*Array*/ array, /*Object*/ value, /*boolean?*/ identity){
// summary: Return index of last occurance of value in array, returning -1 if not found.
// param: identity: If true, matches with identity comparison (===).
// If false, uses normal comparison (==).
return dojo.lang.find(array, value, identity, true);
}
dojo.lang.lastIndexOf = dojo.lang.findLast;
dojo.lang.inArray = function(array /*Array*/, value /*Object*/){
// summary: Return true if value is present in array.
return dojo.lang.find(array, value) > -1; // return: boolean
}
/**
* Partial implmentation of is* functions from
* http://www.crockford.com/javascript/recommend.html
* NOTE: some of these may not be the best thing to use in all situations
* as they aren't part of core JS and therefore can't work in every case.
* See WARNING messages inline for tips.
*
* The following is* functions are fairly "safe"
*/
dojo.lang.isObject = function(it){
// summary: Return true if it is an Object, Array or Function.
if(typeof it == "undefined"){ return false; }
return (typeof it == "object" || it === null || dojo.lang.isArray(it) || dojo.lang.isFunction(it));
}
dojo.lang.isArray = function(it){
// summary: Return true if it is an Array.
return (it instanceof Array || typeof it == "array");
}
dojo.lang.isArrayLike = function(it){
// summary: Return true if it can be used as an array (i.e. is an object with an integer length property).
if((!it)||(dojo.lang.isUndefined(it))){ return false; }
if(dojo.lang.isString(it)){ return false; }
if(dojo.lang.isFunction(it)){ return false; } // keeps out built-in constructors (Number, String, ...) which have length properties
if(dojo.lang.isArray(it)){ return true; }
// form node itself is ArrayLike, but not always iterable. Use form.elements instead.
if((it.tagName)&&(it.tagName.toLowerCase()=='form')){ return false; }
if(dojo.lang.isNumber(it.length) && isFinite(it.length)){ return true; }
return false;
}
dojo.lang.isFunction = function(it){
// summary: Return true if it is a Function.
if(!it){ return false; }
return (it instanceof Function || typeof it == "function");
}
dojo.lang.isString = function(it){
// summary: Return true if it is a String.
return (it instanceof String || typeof it == "string");
}
dojo.lang.isAlien = function(it){
// summary: Return true if it is not a built-in function.
if(!it){ return false; }
return !dojo.lang.isFunction() && /\{\s*\[native code\]\s*\}/.test(String(it));
}
dojo.lang.isBoolean = function(it){
// summary: Return true if it is a Boolean.
return (it instanceof Boolean || typeof it == "boolean");
}
/**
* The following is***() functions are somewhat "unsafe". Fortunately,
* there are workarounds the the language provides and are mentioned
* in the WARNING messages.
*
*/
dojo.lang.isNumber = function(it){
// summary: Return true if it is a number.
// warning:
// In most cases, isNaN(it) is sufficient to determine whether or not
// something is a number or can be used as such. For example, a number or string
// can be used interchangably when accessing array items (array["1"] is the same as
// array[1]) and isNaN will return false for both values ("1" and 1). However,
// isNumber("1") will return false, which is generally not too useful.
// Also, isNumber(NaN) returns true, again, this isn't generally useful, but there
// are corner cases (like when you want to make sure that two things are really
// the same type of thing). That is really where isNumber "shines".
//
// recommendation: Use isNaN(it) when possible
return (it instanceof Number || typeof it == "number");
}
/*
* FIXME: Should isUndefined go away since it is error prone?
*/
dojo.lang.isUndefined = function(it){
// summary: Return true if it is not defined.
// warning: In some cases, isUndefined will not behave as you
// might expect. If you do isUndefined(foo) and there is no earlier
// reference to foo, an error will be thrown before isUndefined is
// called. It behaves correctly if you scope yor object first, i.e.
// isUndefined(foo.bar) where foo is an object and bar isn't a
// property of the object.
//
// recommendation: Use typeof foo == "undefined" when possible
return ((it == undefined)&&(typeof it == "undefined"));
}
// end Crockford functions
dojo.provide("dojo.lang.extras");
/**
* Sets a timeout in milliseconds to execute a function in a given context
* with optional arguments.
*
* setTimeout (Object context, function func, number delay[, arg1[, ...]]);
* setTimeout (function func, number delay[, arg1[, ...]]);
*/
dojo.lang.setTimeout = function(func, delay){
var context = window, argsStart = 2;
if(!dojo.lang.isFunction(func)){
context = func;
func = delay;
delay = arguments[2];
argsStart++;
}
if(dojo.lang.isString(func)){
func = context[func];
}
var args = [];
for (var i = argsStart; i < arguments.length; i++) {
args.push(arguments[i]);
}
return dojo.global().setTimeout(function () { func.apply(context, args); }, delay);
}
dojo.lang.clearTimeout = function(timer){
dojo.global().clearTimeout(timer);
}
dojo.lang.getNameInObj = function(ns, item){
if(!ns){ ns = dj_global; }
for(var x in ns){
if(ns[x] === item){
return new String(x);
}
}
return null;
}
dojo.lang.shallowCopy = function(obj, deep) {
var i, ret;
if (obj === null) return null;
if (dojo.lang.isObject(obj)) {
ret = new obj.constructor();
for (i in obj) {
if(dojo.lang.isUndefined(ret[i])) {
ret[i] = deep ? dojo.lang.shallowCopy(obj[i], deep) : obj[i];
}
}
} else if (dojo.lang.isArray(obj)) {
ret = [];
for(i=0; i<obj.length; i++) {
ret[i] = deep ? dojo.lang.shallowCopy(obj[i], deep) : obj[i];
}
} else {
ret = obj;
}
return ret;
}
/**
* Return the first argument that isn't undefined
*/
dojo.lang.firstValued = function(/* ... */) {
for(var i = 0; i < arguments.length; i++) {
if(typeof arguments[i] != "undefined") {
return arguments[i];
}
}
return undefined;
}
/**
* Get a value from a reference specified as a string descriptor,
* (e.g. "A.B") in the given context.
*
* getObjPathValue(String objpath [, Object context, Boolean create])
*
* If context is not specified, dj_global is used
* If create is true, undefined objects in the path are created.
*/
dojo.lang.getObjPathValue = function(objpath, context, create){
with(dojo.parseObjPath(objpath, context, create)){
return dojo.evalProp(prop, obj, create);
}
}
/**
* Set a value on a reference specified as a string descriptor.
* (e.g. "A.B") in the given context.
*
* setObjPathValue(String objpath, value [, Object context, Boolean create])
*
* If context is not specified, dj_global is used
* If create is true, undefined objects in the path are created.
*/
dojo.lang.setObjPathValue = function(objpath, value, context, create){
if(arguments.length < 4){
create = true;
}
with(dojo.parseObjPath(objpath, context, create)){
if(obj && (create || (prop in obj))){
obj[prop] = value;
}
}
}
dojo.provide("dojo.io.IO");
/******************************************************************************
* Notes about dojo.io design:
*
* The dojo.io.* package has the unenviable task of making a lot of different
* types of I/O feel natural, despite a universal lack of good (or even
* reasonable!) I/O capability in the host environment. So lets pin this down
* a little bit further.
*
* Rhino:
* perhaps the best situation anywhere. Access to Java classes allows you
* to do anything one might want in terms of I/O, both synchronously and
* async. Can open TCP sockets and perform low-latency client/server
* interactions. HTTP transport is available through Java HTTP client and
* server classes. Wish it were always this easy.
*
* xpcshell:
* XPCOM for I/O. A cluster-fuck to be sure.
*
* spidermonkey:
* S.O.L.
*
* Browsers:
* Browsers generally do not provide any useable filesystem access. We are
* therefore limited to HTTP for moving information to and from Dojo
* instances living in a browser.
*
* XMLHTTP:
* Sync or async, allows reading of arbitrary text files (including
* JS, which can then be eval()'d), writing requires server
* cooperation and is limited to HTTP mechanisms (POST and GET).
*
* <iframe> hacks:
* iframe document hacks allow browsers to communicate asynchronously
* with a server via HTTP POST and GET operations. With significant
* effort and server cooperation, low-latency data transit between
* client and server can be acheived via iframe mechanisms (repubsub).
*
* SVG:
* Adobe's SVG viewer implements helpful primitives for XML-based
* requests, but receipt of arbitrary text data seems unlikely w/o
* <![CDATA[]]> sections.
*
*
* A discussion between Dylan, Mark, Tom, and Alex helped to lay down a lot
* the IO API interface. A transcript of it can be found at:
* http://dojotoolkit.org/viewcvs/viewcvs.py/documents/irc/irc_io_api_log.txt?rev=307&view=auto
*
* Also referenced in the design of the API was the DOM 3 L&S spec:
* http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html
******************************************************************************/
// a map of the available transport options. Transports should add themselves
// by calling add(name)
dojo.io.transports = [];
dojo.io.hdlrFuncNames = [ "load", "error", "timeout" ]; // we're omitting a progress() event for now
dojo.io.Request = function(url, mimetype, transport, changeUrl){
if((arguments.length == 1)&&(arguments[0].constructor == Object)){
this.fromKwArgs(arguments[0]);
}else{
this.url = url;
if(mimetype){ this.mimetype = mimetype; }
if(transport){ this.transport = transport; }
if(arguments.length >= 4){ this.changeUrl = changeUrl; }
}
}
dojo.lang.extend(dojo.io.Request, {
/** The URL to hit */
url: "",
/** The mime type used to interrpret the response body */
mimetype: "text/plain",
/** The HTTP method to use */
method: "GET",
/** An Object containing key-value pairs to be included with the request */
content: undefined, // Object
/** The transport medium to use */
transport: undefined, // String
/** If defined the URL of the page is physically changed */
changeUrl: undefined, // String
/** A form node to use in the request */
formNode: undefined, // HTMLFormElement
/** Whether the request should be made synchronously */
sync: false,
bindSuccess: false,
/** Cache/look for the request in the cache before attempting to request?
* NOTE: this isn't a browser cache, this is internal and would only cache in-page
*/
useCache: false,
/** Prevent the browser from caching this by adding a query string argument to the URL */
preventCache: false,
// events stuff
load: function(type, data, evt){ },
error: function(type, error){ },
timeout: function(type){ },
handle: function(){ },
//FIXME: change BrowserIO.js to use timeouts? IframeIO?
// The number of seconds to wait until firing a timeout callback.
// If it is zero, that means, don't do a timeout check.
timeoutSeconds: 0,
// the abort method needs to be filled in by the transport that accepts the
// bind() request
abort: function(){ },
// backButton: function(){ },
// forwardButton: function(){ },
fromKwArgs: function(kwArgs){
// normalize args
if(kwArgs["url"]){ kwArgs.url = kwArgs.url.toString(); }
if(kwArgs["formNode"]) { kwArgs.formNode = dojo.byId(kwArgs.formNode); }
if(!kwArgs["method"] && kwArgs["formNode"] && kwArgs["formNode"].method) {
kwArgs.method = kwArgs["formNode"].method;
}
// backwards compatibility
if(!kwArgs["handle"] && kwArgs["handler"]){ kwArgs.handle = kwArgs.handler; }
if(!kwArgs["load"] && kwArgs["loaded"]){ kwArgs.load = kwArgs.loaded; }
if(!kwArgs["changeUrl"] && kwArgs["changeURL"]) { kwArgs.changeUrl = kwArgs.changeURL; }
// encoding fun!
kwArgs.encoding = dojo.lang.firstValued(kwArgs["encoding"], djConfig["bindEncoding"], "");
kwArgs.sendTransport = dojo.lang.firstValued(kwArgs["sendTransport"], djConfig["ioSendTransport"], false);
var isFunction = dojo.lang.isFunction;
for(var x=0; x<dojo.io.hdlrFuncNames.length; x++){
var fn = dojo.io.hdlrFuncNames[x];
if(kwArgs[fn] && isFunction(kwArgs[fn])){ continue; }
if(kwArgs["handle"] && isFunction(kwArgs["handle"])){
kwArgs[fn] = kwArgs.handle;
}
// handler is aliased above, shouldn't need this check
/* else if(dojo.lang.isObject(kwArgs.handler)){
if(isFunction(kwArgs.handler[fn])){
kwArgs[fn] = kwArgs.handler[fn]||kwArgs.handler["handle"]||function(){};
}
}*/
}
dojo.lang.mixin(this, kwArgs);
}
});
dojo.io.Error = function(msg, type, num){
this.message = msg;
this.type = type || "unknown"; // must be one of "io", "parse", "unknown"
this.number = num || 0; // per-substrate error number, not normalized
}
dojo.io.transports.addTransport = function(name){
this.push(name);
// FIXME: do we need to handle things that aren't direct children of the
// dojo.io namespace? (say, dojo.io.foo.fooTransport?)
this[name] = dojo.io[name];
}
// binding interface, the various implementations register their capabilities
// and the bind() method dispatches
dojo.io.bind = function(request){
// if the request asks for a particular implementation, use it
if(!(request instanceof dojo.io.Request)){
try{
request = new dojo.io.Request(request);
}catch(e){ dojo.debug(e); }
}
var tsName = "";
if(request["transport"]){
tsName = request["transport"];
// FIXME: it would be good to call the error handler, although we'd
// need to use setTimeout or similar to accomplish this and we can't
// garuntee that this facility is available.
if(!this[tsName]){ return request; }
}else{
// otherwise we do our best to auto-detect what available transports
// will handle
for(var x=0; x<dojo.io.transports.length; x++){
var tmp = dojo.io.transports[x];
if((this[tmp])&&(this[tmp].canHandle(request))){
tsName = tmp;
}
}
if(tsName == ""){ return request; }
}
this[tsName].bind(request);
request.bindSuccess = true;
return request;
}
dojo.io.queueBind = function(request){
if(!(request instanceof dojo.io.Request)){
try{
request = new dojo.io.Request(request);
}catch(e){ dojo.debug(e); }
}
// make sure we get called if/when we get a response
var oldLoad = request.load;
request.load = function(){
dojo.io._queueBindInFlight = false;
var ret = oldLoad.apply(this, arguments);
dojo.io._dispatchNextQueueBind();
return ret;
}
var oldErr = request.error;
request.error = function(){
dojo.io._queueBindInFlight = false;
var ret = oldErr.apply(this, arguments);
dojo.io._dispatchNextQueueBind();
return ret;
}
dojo.io._bindQueue.push(request);
dojo.io._dispatchNextQueueBind();
return request;
}
dojo.io._dispatchNextQueueBind = function(){
if(!dojo.io._queueBindInFlight){
dojo.io._queueBindInFlight = true;
if(dojo.io._bindQueue.length > 0){
dojo.io.bind(dojo.io._bindQueue.shift());
}else{
dojo.io._queueBindInFlight = false;
}
}
}
dojo.io._bindQueue = [];
dojo.io._queueBindInFlight = false;
dojo.io.argsFromMap = function(map, encoding, last){
var enc = /utf/i.test(encoding||"") ? encodeURIComponent : dojo.string.encodeAscii;
var mapped = [];
var control = new Object();
for(var name in map){
var domap = function(elt){
var val = enc(name)+"="+enc(elt);
mapped[(last == name) ? "push" : "unshift"](val);
}
if(!control[name]){
var value = map[name];
// FIXME: should be isArrayLike?
if (dojo.lang.isArray(value)){
dojo.lang.forEach(value, domap);
}else{
domap(value);
}
}
}
return mapped.join("&");
}
dojo.io.setIFrameSrc = function(iframe, src, replace){
try{
var r = dojo.render.html;
// dojo.debug(iframe);
if(!replace){
if(r.safari){
iframe.location = src;
}else{
frames[iframe.name].location = src;
}
}else{
// Fun with DOM 0 incompatibilities!
var idoc;
if(r.ie){
idoc = iframe.contentWindow.document;
}else if(r.safari){
idoc = iframe.document;
}else{ // if(r.moz){
idoc = iframe.contentWindow;
}
//For Safari (at least 2.0.3) and Opera, if the iframe
//has just been created but it doesn't have content
//yet, then iframe.document may be null. In that case,
//use iframe.location and return.
if(!idoc){
iframe.location = src;
return;
}else{
idoc.location.replace(src);
}
}
}catch(e){
dojo.debug(e);
dojo.debug("setIFrameSrc: "+e);
}
}
/*
dojo.io.sampleTranport = new function(){
this.canHandle = function(kwArgs){
// canHandle just tells dojo.io.bind() if this is a good transport to
// use for the particular type of request.
if(
(
(kwArgs["mimetype"] == "text/plain") ||
(kwArgs["mimetype"] == "text/html") ||
(kwArgs["mimetype"] == "text/javascript")
)&&(
(kwArgs["method"] == "get") ||
( (kwArgs["method"] == "post") && (!kwArgs["formNode"]) )
)
){
return true;
}
return false;
}
this.bind = function(kwArgs){
var hdlrObj = {};
// set up a handler object
for(var x=0; x<dojo.io.hdlrFuncNames.length; x++){
var fn = dojo.io.hdlrFuncNames[x];
if(typeof kwArgs.handler == "object"){
if(typeof kwArgs.handler[fn] == "function"){
hdlrObj[fn] = kwArgs.handler[fn]||kwArgs.handler["handle"];
}
}else if(typeof kwArgs[fn] == "function"){
hdlrObj[fn] = kwArgs[fn];
}else{
hdlrObj[fn] = kwArgs["handle"]||function(){};
}
}
// build a handler function that calls back to the handler obj
var hdlrFunc = function(evt){
if(evt.type == "onload"){
hdlrObj.load("load", evt.data, evt);
}else if(evt.type == "onerr"){
var errObj = new dojo.io.Error("sampleTransport Error: "+evt.msg);
hdlrObj.error("error", errObj);
}
}
// the sample transport would attach the hdlrFunc() when sending the
// request down the pipe at this point
var tgtURL = kwArgs.url+"?"+dojo.io.argsFromMap(kwArgs.content);
// sampleTransport.sendRequest(tgtURL, hdlrFunc);
}
dojo.io.transports.addTransport("sampleTranport");
}
*/
dojo.provide("dojo.lang.array");
// FIXME: Is this worthless since you can do: if(name in obj)
// is this the right place for this?
dojo.lang.has = function(obj, name){
try{
return (typeof obj[name] != "undefined");
}catch(e){ return false; }
}
dojo.lang.isEmpty = function(obj) {
if(dojo.lang.isObject(obj)) {
var tmp = {};
var count = 0;
for(var x in obj){
if(obj[x] && (!tmp[x])){
count++;
break;
}
}
return (count == 0);
} else if(dojo.lang.isArrayLike(obj) || dojo.lang.isString(obj)) {
return obj.length == 0;
}
}
dojo.lang.map = function(arr, obj, unary_func){
var isString = dojo.lang.isString(arr);
if(isString){
arr = arr.split("");
}
if(dojo.lang.isFunction(obj)&&(!unary_func)){
unary_func = obj;
obj = dj_global;
}else if(dojo.lang.isFunction(obj) && unary_func){
// ff 1.5 compat
var tmpObj = obj;
obj = unary_func;
unary_func = tmpObj;
}
if(Array.map){
var outArr = Array.map(arr, unary_func, obj);
}else{
var outArr = [];
for(var i=0;i<arr.length;++i){
outArr.push(unary_func.call(obj, arr[i]));
}
}
if(isString) {
return outArr.join("");
} else {
return outArr;
}
}
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
dojo.lang.forEach = function(anArray /* Array */, callback /* Function */, thisObject /* Object */){
if(dojo.lang.isString(anArray)){
anArray = anArray.split("");
}
if(Array.forEach){
Array.forEach(anArray, callback, thisObject);
}else{
// FIXME: there are several ways of handilng thisObject. Is dj_global always the default context?
if(!thisObject){
thisObject=dj_global;
}
for(var i=0,l=anArray.length; i<l; i++){
callback.call(thisObject, anArray[i], i, anArray);
}
}
}
dojo.lang._everyOrSome = function(every, arr, callback, thisObject){
if(dojo.lang.isString(arr)){
arr = arr.split("");
}
if(Array.every){
return Array[ (every) ? "every" : "some" ](arr, callback, thisObject);
}else{
if(!thisObject){
thisObject = dj_global;
}
for(var i=0,l=arr.length; i<l; i++){
var result = callback.call(thisObject, arr[i], i, arr);
if((every)&&(!result)){
return false;
}else if((!every)&&(result)){
return true;
}
}
return (every) ? true : false;
}
}
dojo.lang.every = function(arr, callback, thisObject){
return this._everyOrSome(true, arr, callback, thisObject);
}
dojo.lang.some = function(arr, callback, thisObject){
return this._everyOrSome(false, arr, callback, thisObject);
}
dojo.lang.filter = function(arr, callback, thisObject) {
var isString = dojo.lang.isString(arr);
if(isString) { arr = arr.split(""); }
if(Array.filter) {
var outArr = Array.filter(arr, callback, thisObject);
} else {
if(!thisObject) {
if(arguments.length >= 3) { dojo.raise("thisObject doesn't exist!"); }
thisObject = dj_global;
}
var outArr = [];
for(var i = 0; i < arr.length; i++) {
if(callback.call(thisObject, arr[i], i, arr)) {
outArr.push(arr[i]);
}
}
}
if(isString) {
return outArr.join("");
} else {
return outArr;
}
}
/**
* Creates a 1-D array out of all the arguments passed,
* unravelling any array-like objects in the process
*
* Ex:
* unnest(1, 2, 3) ==> [1, 2, 3]
* unnest(1, [2, [3], [[[4]]]]) ==> [1, 2, 3, 4]
*/
dojo.lang.unnest = function(/* ... */) {
var out = [];
for(var i = 0; i < arguments.length; i++) {
if(dojo.lang.isArrayLike(arguments[i])) {
var add = dojo.lang.unnest.apply(this, arguments[i]);
out = out.concat(add);
} else {
out.push(arguments[i]);
}
}
return out;
}
/**
* Converts an array-like object (i.e. arguments, DOMCollection)
* to an array
**/
dojo.lang.toArray = function(arrayLike, startOffset) {
var array = [];
for(var i = startOffset||0; i < arrayLike.length; i++) {
array.push(arrayLike[i]);
}
return array;
}
dojo.provide("dojo.lang.func");
/**
* Runs a function in a given scope (thisObject), can
* also be used to preserve scope.
*
* hitch(foo, "bar"); // runs foo.bar() in the scope of foo
* hitch(foo, myFunction); // runs myFunction in the scope of foo
*/
dojo.lang.hitch = function(thisObject, method){
var fcn = (dojo.lang.isString(method) ? thisObject[method] : method) || function(){};
return function() {
return fcn.apply(thisObject, arguments);
};
}
dojo.lang.anonCtr = 0;
dojo.lang.anon = {};
dojo.lang.nameAnonFunc = function(anonFuncPtr, namespaceObj, searchForNames){
var nso = (namespaceObj || dojo.lang.anon);
if( (searchForNames) ||
((dj_global["djConfig"])&&(djConfig["slowAnonFuncLookups"] == true)) ){
for(var x in nso){
try{
if(nso[x] === anonFuncPtr){
return x;
}
}catch(e){} // window.external fails in IE embedded in Eclipse (Eclipse bug #151165)
}
}
var ret = "__"+dojo.lang.anonCtr++;
while(typeof nso[ret] != "undefined"){
ret = "__"+dojo.lang.anonCtr++;
}
nso[ret] = anonFuncPtr;
return ret;
}
dojo.lang.forward = function(funcName){
// Returns a function that forwards a method call to this.func(...)
return function(){
return this[funcName].apply(this, arguments);
};
}
dojo.lang.curry = function(ns, func /* args ... */){
var outerArgs = [];
ns = ns||dj_global;
if(dojo.lang.isString(func)){
func = ns[func];
}
for(var x=2; x<arguments.length; x++){
outerArgs.push(arguments[x]);
}
// since the event system replaces the original function with a new
// join-point runner with an arity of 0, we check to see if it's left us
// any clues about the original arity in lieu of the function's actual
// length property
var ecount = (func["__preJoinArity"]||func.length) - outerArgs.length;
// borrowed from svend tofte
function gather(nextArgs, innerArgs, expected){
var texpected = expected;
var totalArgs = innerArgs.slice(0); // copy
for(var x=0; x<nextArgs.length; x++){
totalArgs.push(nextArgs[x]);
}
// check the list of provided nextArgs to see if it, plus the
// number of innerArgs already supplied, meets the total
// expected.
expected = expected-nextArgs.length;
if(expected<=0){
var res = func.apply(ns, totalArgs);
expected = texpected;
return res;
}else{
return function(){
return gather(arguments,// check to see if we've been run
// with enough args
totalArgs, // a copy
expected); // how many more do we need to run?;
};
}
}
return gather([], outerArgs, ecount);
}
dojo.lang.curryArguments = function(ns, func, args, offset){
var targs = [];
var x = offset||0;
for(x=offset; x<args.length; x++){
targs.push(args[x]); // ensure that it's an arr
}
return dojo.lang.curry.apply(dojo.lang, [ns, func].concat(targs));
}
dojo.lang.tryThese = function(){
for(var x=0; x<arguments.length; x++){
try{
if(typeof arguments[x] == "function"){
var ret = (arguments[x]());
if(ret){
return ret;
}
}
}catch(e){
dojo.debug(e);
}
}
}
dojo.lang.delayThese = function(farr, cb, delay, onend){
/**
* alternate: (array funcArray, function callback, function onend)
* alternate: (array funcArray, function callback)
* alternate: (array funcArray)
*/
if(!farr.length){
if(typeof onend == "function"){
onend();
}
return;
}
if((typeof delay == "undefined")&&(typeof cb == "number")){
delay = cb;
cb = function(){};
}else if(!cb){
cb = function(){};
if(!delay){ delay = 0; }
}
setTimeout(function(){
(farr.shift())();
cb();
dojo.lang.delayThese(farr, cb, delay, onend);
}, delay);
}
dojo.provide("dojo.string.extras");
/**
* Performs parameterized substitutions on a string. For example,
* dojo.string.substituteParams("File '%{0}' is not found in directory '%{1}'.","foo.html","/temp");
* returns
* "File 'foo.html' is not found in directory '/temp'."
*
* @param template the original string template with %{values} to be replaced
* @param hash name/value pairs (type object) to provide substitutions. Alternatively, substitutions may be
* included as arguments 1..n to this function, corresponding to template parameters 0..n-1
* @return the completed string. Throws an exception if any parameter is unmatched
*/
//TODO: use ${} substitution syntax instead, like widgets do?
dojo.string.substituteParams = function(template /*string */, hash /* object - optional or ... */) {
var map = (typeof hash == 'object') ? hash : dojo.lang.toArray(arguments, 1);
return template.replace(/\%\{(\w+)\}/g, function(match, key){
return map[key] || dojo.raise("Substitution not found: " + key);
});
};
/** Uppercases the first letter of each word */
dojo.string.capitalize = function (str) {
if (!dojo.lang.isString(str)) { return ""; }
if (arguments.length == 0) { str = this; }
var words = str.split(' ');
for(var i=0; i<words.length; i++){
words[i] = words[i].charAt(0).toUpperCase() + words[i].substring(1);
}
return words.join(" ");
}
/**
* Return true if the entire string is whitespace characters
*/
dojo.string.isBlank = function (str) {
if(!dojo.lang.isString(str)) { return true; }
return (dojo.string.trim(str).length == 0);
}
dojo.string.encodeAscii = function(str) {
if(!dojo.lang.isString(str)) { return str; }
var ret = "";
var value = escape(str);
var match, re = /%u([0-9A-F]{4})/i;
while((match = value.match(re))) {
var num = Number("0x"+match[1]);
var newVal = escape("&#" + num + ";");
ret += value.substring(0, match.index) + newVal;
value = value.substring(match.index+match[0].length);
}
ret += value.replace(/\+/g, "%2B");
return ret;
}
dojo.string.escape = function(type, str) {
var args = dojo.lang.toArray(arguments, 1);
switch(type.toLowerCase()) {
case "xml":
case "html":
case "xhtml":
return dojo.string.escapeXml.apply(this, args);
case "sql":
return dojo.string.escapeSql.apply(this, args);
case "regexp":
case "regex":
return dojo.string.escapeRegExp.apply(this, args);
case "javascript":
case "jscript":
case "js":
return dojo.string.escapeJavaScript.apply(this, args);
case "ascii":
// so it's encode, but it seems useful
return dojo.string.encodeAscii.apply(this, args);
default:
return str;
}
}
dojo.string.escapeXml = function(str, noSingleQuotes) {
str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;")
.replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
if(!noSingleQuotes) { str = str.replace(/'/gm, "&#39;"); }
return str;
}
dojo.string.escapeSql = function(str) {
return str.replace(/'/gm, "''");
}
dojo.string.escapeRegExp = function(str) {
return str.replace(/\\/gm, "\\\\").replace(/([\f\b\n\t\r[\^$|?*+(){}])/gm, "\\$1");
}
dojo.string.escapeJavaScript = function(str) {
return str.replace(/(["'\f\b\n\t\r])/gm, "\\$1");
}
dojo.string.escapeString = function(str){
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");
}
// TODO: make an HTML version
dojo.string.summary = function(str, len) {
if(!len || str.length <= len) {
return str;
} else {
return str.substring(0, len).replace(/\.+$/, "") + "...";
}
}
/**
* Returns true if 'str' ends with 'end'
*/
dojo.string.endsWith = function(str, end, ignoreCase) {
if(ignoreCase) {
str = str.toLowerCase();
end = end.toLowerCase();
}
if((str.length - end.length) < 0){
return false;
}
return str.lastIndexOf(end) == str.length - end.length;
}
/**
* Returns true if 'str' ends with any of the arguments[2 -> n]
*/
dojo.string.endsWithAny = function(str /* , ... */) {
for(var i = 1; i < arguments.length; i++) {
if(dojo.string.endsWith(str, arguments[i])) {
return true;
}
}
return false;
}
/**
* Returns true if 'str' starts with 'start'
*/
dojo.string.startsWith = function(str, start, ignoreCase) {
if(ignoreCase) {
str = str.toLowerCase();
start = start.toLowerCase();
}
return str.indexOf(start) == 0;
}
/**
* Returns true if 'str' starts with any of the arguments[2 -> n]
*/
dojo.string.startsWithAny = function(str /* , ... */) {
for(var i = 1; i < arguments.length; i++) {
if(dojo.string.startsWith(str, arguments[i])) {
return true;
}
}
return false;
}
/**
* Returns true if 'str' contains any of the arguments 2 -> n
*/
dojo.string.has = function(str /* , ... */) {
for(var i = 1; i < arguments.length; i++) {
if(str.indexOf(arguments[i]) > -1){
return true;
}
}
return false;
}
dojo.string.normalizeNewlines = function (text,newlineChar) {
if (newlineChar == "\n") {
text = text.replace(/\r\n/g, "\n");
text = text.replace(/\r/g, "\n");
} else if (newlineChar == "\r") {
text = text.replace(/\r\n/g, "\r");
text = text.replace(/\n/g, "\r");
} else {
text = text.replace(/([^\r])\n/g, "$1\r\n");
text = text.replace(/\r([^\n])/g, "\r\n$1");
}
return text;
}
dojo.string.splitEscaped = function (str,charac) {
var components = [];
for (var i = 0, prevcomma = 0; i < str.length; i++) {
if (str.charAt(i) == '\\') { i++; continue; }
if (str.charAt(i) == charac) {
components.push(str.substring(prevcomma, i));
prevcomma = i + 1;
}
}
components.push(str.substr(prevcomma));
return components;
}
dojo.provide("dojo.dom");
dojo.dom.ELEMENT_NODE = 1;
dojo.dom.ATTRIBUTE_NODE = 2;
dojo.dom.TEXT_NODE = 3;
dojo.dom.CDATA_SECTION_NODE = 4;
dojo.dom.ENTITY_REFERENCE_NODE = 5;
dojo.dom.ENTITY_NODE = 6;
dojo.dom.PROCESSING_INSTRUCTION_NODE = 7;
dojo.dom.COMMENT_NODE = 8;
dojo.dom.DOCUMENT_NODE = 9;
dojo.dom.DOCUMENT_TYPE_NODE = 10;
dojo.dom.DOCUMENT_FRAGMENT_NODE = 11;
dojo.dom.NOTATION_NODE = 12;
dojo.dom.dojoml = "http://www.dojotoolkit.org/2004/dojoml";
/**
* comprehensive list of XML namespaces
**/
dojo.dom.xmlns = {
svg : "http://www.w3.org/2000/svg",
smil : "http://www.w3.org/2001/SMIL20/",
mml : "http://www.w3.org/1998/Math/MathML",
cml : "http://www.xml-cml.org",
xlink : "http://www.w3.org/1999/xlink",
xhtml : "http://www.w3.org/1999/xhtml",
xul : "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
xbl : "http://www.mozilla.org/xbl",
fo : "http://www.w3.org/1999/XSL/Format",
xsl : "http://www.w3.org/1999/XSL/Transform",
xslt : "http://www.w3.org/1999/XSL/Transform",
xi : "http://www.w3.org/2001/XInclude",
xforms : "http://www.w3.org/2002/01/xforms",
saxon : "http://icl.com/saxon",
xalan : "http://xml.apache.org/xslt",
xsd : "http://www.w3.org/2001/XMLSchema",
dt: "http://www.w3.org/2001/XMLSchema-datatypes",
xsi : "http://www.w3.org/2001/XMLSchema-instance",
rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
rdfs : "http://www.w3.org/2000/01/rdf-schema#",
dc : "http://purl.org/dc/elements/1.1/",
dcq: "http://purl.org/dc/qualifiers/1.0",
"soap-env" : "http://schemas.xmlsoap.org/soap/envelope/",
wsdl : "http://schemas.xmlsoap.org/wsdl/",
AdobeExtensions : "http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
};
dojo.dom.isNode = function(wh){
if(typeof Element == "function") {
try {
return wh instanceof Element;
} catch(E) {}
} else {
// best-guess
return wh && !isNaN(wh.nodeType);
}
}
dojo.dom.getUniqueId = function(){
var _document = dojo.doc();
do {
var id = "dj_unique_" + (++arguments.callee._idIncrement);
}while(_document.getElementById(id));
return id;
}
dojo.dom.getUniqueId._idIncrement = 0;
dojo.dom.firstElement = dojo.dom.getFirstChildElement = function(parentNode, tagName){
var node = parentNode.firstChild;
while(node && node.nodeType != dojo.dom.ELEMENT_NODE){
node = node.nextSibling;
}
if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
node = dojo.dom.nextElement(node, tagName);
}
return node;
}
dojo.dom.lastElement = dojo.dom.getLastChildElement = function(parentNode, tagName){
var node = parentNode.lastChild;
while(node && node.nodeType != dojo.dom.ELEMENT_NODE) {
node = node.previousSibling;
}
if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
node = dojo.dom.prevElement(node, tagName);
}
return node;
}
dojo.dom.nextElement = dojo.dom.getNextSiblingElement = function(node, tagName){
if(!node) { return null; }
do {
node = node.nextSibling;
} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);
if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
return dojo.dom.nextElement(node, tagName);
}
return node;
}
dojo.dom.prevElement = dojo.dom.getPreviousSiblingElement = function(node, tagName){
if(!node) { return null; }
if(tagName) { tagName = tagName.toLowerCase(); }
do {
node = node.previousSibling;
} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);
if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
return dojo.dom.prevElement(node, tagName);
}
return node;
}
// TODO: hmph
/*this.forEachChildTag = function(node, unaryFunc) {
var child = this.getFirstChildTag(node);
while(child) {
if(unaryFunc(child) == "break") { break; }
child = this.getNextSiblingTag(child);
}
}*/
dojo.dom.moveChildren = function(srcNode, destNode, trim){
var count = 0;
if(trim) {
while(srcNode.hasChildNodes() &&
srcNode.firstChild.nodeType == dojo.dom.TEXT_NODE) {
srcNode.removeChild(srcNode.firstChild);
}
while(srcNode.hasChildNodes() &&
srcNode.lastChild.nodeType == dojo.dom.TEXT_NODE) {
srcNode.removeChild(srcNode.lastChild);
}
}
while(srcNode.hasChildNodes()){
destNode.appendChild(srcNode.firstChild);
count++;
}
return count;
}
dojo.dom.copyChildren = function(srcNode, destNode, trim){
var clonedNode = srcNode.cloneNode(true);
return this.moveChildren(clonedNode, destNode, trim);
}
dojo.dom.removeChildren = function(node){
var count = node.childNodes.length;
while(node.hasChildNodes()){ node.removeChild(node.firstChild); }
return count;
}
dojo.dom.replaceChildren = function(node, newChild){
// FIXME: what if newChild is an array-like object?
dojo.dom.removeChildren(node);
node.appendChild(newChild);
}
dojo.dom.removeNode = function(node){
if(node && node.parentNode){
// return a ref to the removed child
return node.parentNode.removeChild(node);
}
}
dojo.dom.getAncestors = function(node, filterFunction, returnFirstHit) {
var ancestors = [];
var isFunction = (filterFunction && (filterFunction instanceof Function || typeof filterFunction == "function"));
while(node) {
if (!isFunction || filterFunction(node)) {
ancestors.push(node);
}
if (returnFirstHit && ancestors.length > 0) { return ancestors[0]; }
node = node.parentNode;
}
if (returnFirstHit) { return null; }
return ancestors;
}
dojo.dom.getAncestorsByTag = function(node, tag, returnFirstHit) {
tag = tag.toLowerCase();
return dojo.dom.getAncestors(node, function(el){
return ((el.tagName)&&(el.tagName.toLowerCase() == tag));
}, returnFirstHit);
}
dojo.dom.getFirstAncestorByTag = function(node, tag) {
return dojo.dom.getAncestorsByTag(node, tag, true);
}
dojo.dom.isDescendantOf = function(node, ancestor, guaranteeDescendant){
// guaranteeDescendant allows us to be a "true" isDescendantOf function
if(guaranteeDescendant && node) { node = node.parentNode; }
while(node) {
if(node == ancestor){ return true; }
node = node.parentNode;
}
return false;
}
dojo.dom.innerXML = function(node){
if(node.innerXML){
return node.innerXML;
}else if (node.xml){
return node.xml;
}else if(typeof XMLSerializer != "undefined"){
return (new XMLSerializer()).serializeToString(node);
}
}
dojo.dom.createDocument = function(){
var doc = null;
var _document = dojo.doc();
if(!dj_undef("ActiveXObject")){
var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ];
for(var i = 0; i<prefixes.length; i++){
try{
doc = new ActiveXObject(prefixes[i]+".XMLDOM");
}catch(e){ /* squelch */ };
if(doc){ break; }
}
}else if((_document.implementation)&&
(_document.implementation.createDocument)){
doc = _document.implementation.createDocument("", "", null);
}
return doc;
}
dojo.dom.createDocumentFromText = function(str, mimetype){
if(!mimetype){ mimetype = "text/xml"; }
if(!dj_undef("DOMParser")){
var parser = new DOMParser();
return parser.parseFromString(str, mimetype);
}else if(!dj_undef("ActiveXObject")){
var domDoc = dojo.dom.createDocument();
if(domDoc){
domDoc.async = false;
domDoc.loadXML(str);
return domDoc;
}else{
dojo.debug("toXml didn't work?");
}
/*
}else if((dojo.render.html.capable)&&(dojo.render.html.safari)){
// FIXME: this doesn't appear to work!
// from: http://web-graphics.com/mtarchive/001606.php
// var xml = '<?xml version="1.0"?>'+str;
var mtype = "text/xml";
var xml = '<?xml version="1.0"?>'+str;
var url = "data:"+mtype+";charset=utf-8,"+encodeURIComponent(xml);
var req = new XMLHttpRequest();
req.open("GET", url, false);
req.overrideMimeType(mtype);
req.send(null);
return req.responseXML;
*/
}else{
var _document = dojo.doc();
if(_document.createElement){
// FIXME: this may change all tags to uppercase!
var tmp = _document.createElement("xml");
tmp.innerHTML = str;
if(_document.implementation && _document.implementation.createDocument) {
var xmlDoc = _document.implementation.createDocument("foo", "", null);
for(var i = 0; i < tmp.childNodes.length; i++) {
xmlDoc.importNode(tmp.childNodes.item(i), true);
}
return xmlDoc;
}
// FIXME: probably not a good idea to have to return an HTML fragment
// FIXME: the tmp.doc.firstChild is as tested from IE, so it may not
// work that way across the board
return ((tmp.document)&&
(tmp.document.firstChild ? tmp.document.firstChild : tmp));
}
}
return null;
}
dojo.dom.prependChild = function(node, parent) {
if(parent.firstChild) {
parent.insertBefore(node, parent.firstChild);
} else {
parent.appendChild(node);
}
return true;
}
dojo.dom.insertBefore = function(node, ref, force){
if (force != true &&
(node === ref || node.nextSibling === ref)){ return false; }
var parent = ref.parentNode;
parent.insertBefore(node, ref);
return true;
}
dojo.dom.insertAfter = function(node, ref, force){
var pn = ref.parentNode;
if(ref == pn.lastChild){
if((force != true)&&(node === ref)){
return false;
}
pn.appendChild(node);
}else{
return this.insertBefore(node, ref.nextSibling, force);
}
return true;
}
dojo.dom.insertAtPosition = function(node, ref, position){
if((!node)||(!ref)||(!position)){ return false; }
switch(position.toLowerCase()){
case "before":
return dojo.dom.insertBefore(node, ref);
case "after":
return dojo.dom.insertAfter(node, ref);
case "first":
if(ref.firstChild){
return dojo.dom.insertBefore(node, ref.firstChild);
}else{
ref.appendChild(node);
return true;
}
break;
default: // aka: last
ref.appendChild(node);
return true;
}
}
dojo.dom.insertAtIndex = function(node, containingNode, insertionIndex){
var siblingNodes = containingNode.childNodes;
// if there aren't any kids yet, just add it to the beginning
if (!siblingNodes.length){
containingNode.appendChild(node);
return true;
}
// otherwise we need to walk the childNodes
// and find our spot
var after = null;
for(var i=0; i<siblingNodes.length; i++){
var sibling_index = siblingNodes.item(i)["getAttribute"] ? parseInt(siblingNodes.item(i).getAttribute("dojoinsertionindex")) : -1;
if (sibling_index < insertionIndex){
after = siblingNodes.item(i);
}
}
if (after){
// add it after the node in {after}
return dojo.dom.insertAfter(node, after);
}else{
// add it to the start
return dojo.dom.insertBefore(node, siblingNodes.item(0));
}
}
/**
* implementation of the DOM Level 3 attribute.
*
* @param node The node to scan for text
* @param text Optional, set the text to this value.
*/
dojo.dom.textContent = function(node, text){
if (arguments.length>1) {
var _document = dojo.doc();
dojo.dom.replaceChildren(node, _document.createTextNode(text));
return text;
} else {
if(node.textContent != undefined){ //FF 1.5
return node.textContent;
}
var _result = "";
if (node == null) { return _result; }
for (var i = 0; i < node.childNodes.length; i++) {
switch (node.childNodes[i].nodeType) {
case 1: // ELEMENT_NODE
case 5: // ENTITY_REFERENCE_NODE
_result += dojo.dom.textContent(node.childNodes[i]);
break;
case 3: // TEXT_NODE
case 2: // ATTRIBUTE_NODE
case 4: // CDATA_SECTION_NODE
_result += node.childNodes[i].nodeValue;
break;
default:
break;
}
}
return _result;
}
}
dojo.dom.hasParent = function (node) {
return node && node.parentNode && dojo.dom.isNode(node.parentNode);
}
/**
* Determines if node has any of the provided tag names and
* returns the tag name that matches, empty string otherwise.
*
* Examples:
*
* myFooNode = <foo />
* isTag(myFooNode, "foo"); // returns "foo"
* isTag(myFooNode, "bar"); // returns ""
* isTag(myFooNode, "FOO"); // returns ""
* isTag(myFooNode, "hey", "foo", "bar"); // returns "foo"
**/
dojo.dom.isTag = function(node /* ... */) {
if(node && node.tagName) {
for(var i=1; i<arguments.length; i++){
if(node.tagName==String(arguments[i])){
return String(arguments[i]);
}
}
}
return "";
}
/**
* Implements DOM Level 2 setAttributeNS so it works cross browser.
*
* Example:
* dojo.dom.setAttributeNS(domElem, "http://foobar.com/2006/someSpec",
* "hs:level", 3);
*/
dojo.dom.setAttributeNS = function(elem, namespaceURI, attrName, attrValue){
if(elem == null || ((elem == undefined)&&(typeof elem == "undefined"))){
dojo.raise("No element given to dojo.dom.setAttributeNS");
}
if(!((elem.setAttributeNS == undefined)&&(typeof elem.setAttributeNS == "undefined"))){ // w3c
elem.setAttributeNS(namespaceURI, attrName, attrValue);
}else{ // IE
// get a root XML document
var ownerDoc = elem.ownerDocument;
var attribute = ownerDoc.createNode(
2, // node type
attrName,
namespaceURI
);
// set value
attribute.nodeValue = attrValue;
// attach to element
elem.setAttributeNode(attribute);
}
}
dojo.provide("dojo.undo.browser");
try{
if((!djConfig["preventBackButtonFix"])&&(!dojo.hostenv.post_load_)){
document.write("<iframe style='border: 0px; width: 1px; height: 1px; position: absolute; bottom: 0px; right: 0px; visibility: visible;' name='djhistory' id='djhistory' src='"+(dojo.hostenv.getBaseScriptUri()+'iframe_history.html')+"'></iframe>");
}
}catch(e){/* squelch */}
if(dojo.render.html.opera){
dojo.debug("Opera is not supported with dojo.undo.browser, so back/forward detection will not work.");
}
/* NOTES:
* Safari 1.2:
* back button "works" fine, however it's not possible to actually
* DETECT that you've moved backwards by inspecting window.location.
* Unless there is some other means of locating.
* FIXME: perhaps we can poll on history.length?
* Safari 2.0.3+ (and probably 1.3.2+):
* works fine, except when changeUrl is used. When changeUrl is used,
* Safari jumps all the way back to whatever page was shown before
* the page that uses dojo.undo.browser support.
* IE 5.5 SP2:
* back button behavior is macro. It does not move back to the
* previous hash value, but to the last full page load. This suggests
* that the iframe is the correct way to capture the back button in
* these cases.
* Don't test this page using local disk for MSIE. MSIE will not create
* a history list for iframe_history.html if served from a file: URL.
* The XML served back from the XHR tests will also not be properly
* created if served from local disk. Serve the test pages from a web
* server to test in that browser.
* IE 6.0:
* same behavior as IE 5.5 SP2
* Firefox 1.0:
* the back button will return us to the previous hash on the same
* page, thereby not requiring an iframe hack, although we do then
* need to run a timer to detect inter-page movement.
*/
dojo.undo.browser = {
initialHref: window.location.href,
initialHash: window.location.hash,
moveForward: false,
historyStack: [],
forwardStack: [],
historyIframe: null,
bookmarkAnchor: null,
locationTimer: null,
/**
* setInitialState sets the state object and back callback for the very first page that is loaded.
* It is recommended that you call this method as part of an event listener that is registered via
* dojo.addOnLoad().
*/
setInitialState: function(args){
this.initialState = {"url": this.initialHref, "kwArgs": args, "urlHash": this.initialHash};
},
//FIXME: Would like to support arbitrary back/forward jumps. Have to rework iframeLoaded among other things.
//FIXME: is there a slight race condition in moz using change URL with the timer check and when
// the hash gets set? I think I have seen a back/forward call in quick succession, but not consistent.
/**
* addToHistory takes one argument, and it is an object that defines the following functions:
* - To support getting back button notifications, the object argument should implement a
* function called either "back", "backButton", or "handle". The string "back" will be
* passed as the first and only argument to this callback.
* - To support getting forward button notifications, the object argument should implement a
* function called either "forward", "forwardButton", or "handle". The string "forward" will be
* passed as the first and only argument to this callback.
* - If you want the browser location string to change, define "changeUrl" on the object. If the
* value of "changeUrl" is true, then a unique number will be appended to the URL as a fragment
* identifier (http://some.domain.com/path#uniquenumber). If it is any other value that does
* not evaluate to false, that value will be used as the fragment identifier. For example,
* if changeUrl: 'page1', then the URL will look like: http://some.domain.com/path#page1
*
* Full example:
*
* dojo.undo.browser.addToHistory({
* back: function() { alert('back pressed'); },
* forward: function() { alert('forward pressed'); },
* changeUrl: true
* });
*/
addToHistory: function(args){
var hash = null;
if(!this.historyIframe){
this.historyIframe = window.frames["djhistory"];
}
if(!this.bookmarkAnchor){
this.bookmarkAnchor = document.createElement("a");
dojo.body().appendChild(this.bookmarkAnchor);
this.bookmarkAnchor.style.display = "none";
}
if((!args["changeUrl"])||(dojo.render.html.ie)){
var url = dojo.hostenv.getBaseScriptUri()+"iframe_history.html?"+(new Date()).getTime();
this.moveForward = true;
dojo.io.setIFrameSrc(this.historyIframe, url, false);
}
if(args["changeUrl"]){
this.changingUrl = true;
hash = "#"+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime());
setTimeout("window.location.href = '"+hash+"'; dojo.undo.browser.changingUrl = false;", 1);
this.bookmarkAnchor.href = hash;
if(dojo.render.html.ie){
var oldCB = args["back"]||args["backButton"]||args["handle"];
//The function takes handleName as a parameter, in case the
//callback we are overriding was "handle". In that case,
//we will need to pass the handle name to handle.
var tcb = function(handleName){
if(window.location.hash != ""){
setTimeout("window.location.href = '"+hash+"';", 1);
}
//Use apply to set "this" to args, and to try to avoid memory leaks.
oldCB.apply(this, [handleName]);
}
//Set interceptor function in the right place.
if(args["back"]){
args.back = tcb;
}else if(args["backButton"]){
args.backButton = tcb;
}else if(args["handle"]){
args.handle = tcb;
}
//If addToHistory is called, then that means we prune the
//forward stack -- the user went back, then wanted to
//start a new forward path.
this.forwardStack = [];
var oldFW = args["forward"]||args["forwardButton"]||args["handle"];
//The function takes handleName as a parameter, in case the
//callback we are overriding was "handle". In that case,
//we will need to pass the handle name to handle.
var tfw = function(handleName){
if(window.location.hash != ""){
window.location.href = hash;
}
if(oldFW){ // we might not actually have one
//Use apply to set "this" to args, and to try to avoid memory leaks.
oldFW.apply(this, [handleName]);
}
}
//Set interceptor function in the right place.
if(args["forward"]){
args.forward = tfw;
}else if(args["forwardButton"]){
args.forwardButton = tfw;
}else if(args["handle"]){
args.handle = tfw;
}
}else if(dojo.render.html.moz){
// start the timer
if(!this.locationTimer){
this.locationTimer = setInterval("dojo.undo.browser.checkLocation();", 200);
}
}
}
this.historyStack.push({"url": url, "kwArgs": args, "urlHash": hash});
},
checkLocation: function(){
if (!this.changingUrl){
var hsl = this.historyStack.length;
if((window.location.hash == this.initialHash||window.location.href == this.initialHref)&&(hsl == 1)){
// FIXME: could this ever be a forward button?
// we can't clear it because we still need to check for forwards. Ugg.
// clearInterval(this.locationTimer);
this.handleBackButton();
return;
}
// first check to see if we could have gone forward. We always halt on
// a no-hash item.
if(this.forwardStack.length > 0){
if(this.forwardStack[this.forwardStack.length-1].urlHash == window.location.hash){
this.handleForwardButton();
return;
}
}
// ok, that didn't work, try someplace back in the history stack
if((hsl >= 2)&&(this.historyStack[hsl-2])){
if(this.historyStack[hsl-2].urlHash==window.location.hash){
this.handleBackButton();
return;
}
}
}
},
iframeLoaded: function(evt, ifrLoc){
if(!dojo.render.html.opera){
var query = this._getUrlQuery(ifrLoc.href);
if(query == null){
// alert("iframeLoaded");
// we hit the end of the history, so we should go back
if(this.historyStack.length == 1){
this.handleBackButton();
}
return;
}
if(this.moveForward){
// we were expecting it, so it's not either a forward or backward movement
this.moveForward = false;
return;
}
//Check the back stack first, since it is more likely.
//Note that only one step back or forward is supported.
if(this.historyStack.length >= 2 && query == this._getUrlQuery(this.historyStack[this.historyStack.length-2].url)){
this.handleBackButton();
}
else if(this.forwardStack.length > 0 && query == this._getUrlQuery(this.forwardStack[this.forwardStack.length-1].url)){
this.handleForwardButton();
}
}
},
handleBackButton: function(){
//The "current" page is always at the top of the history stack.
var current = this.historyStack.pop();
if(!current){ return; }
var last = this.historyStack[this.historyStack.length-1];
if(!last && this.historyStack.length == 0){
last = this.initialState;
}
if (last){
if(last.kwArgs["back"]){
last.kwArgs["back"]();
}else if(last.kwArgs["backButton"]){
last.kwArgs["backButton"]();
}else if(last.kwArgs["handle"]){
last.kwArgs.handle("back");
}
}
this.forwardStack.push(current);
},
handleForwardButton: function(){
var last = this.forwardStack.pop();
if(!last){ return; }
if(last.kwArgs["forward"]){
last.kwArgs.forward();
}else if(last.kwArgs["forwardButton"]){
last.kwArgs.forwardButton();
}else if(last.kwArgs["handle"]){
last.kwArgs.handle("forward");
}
this.historyStack.push(last);
},
_getUrlQuery: function(url){
var segments = url.split("?");
if (segments.length < 2){
return null;
}
else{
return segments[1];
}
}
}
dojo.provide("dojo.io.BrowserIO");
dojo.io.checkChildrenForFile = function(node){
var hasFile = false;
var inputs = node.getElementsByTagName("input");
dojo.lang.forEach(inputs, function(input){
if(hasFile){ return; }
if(input.getAttribute("type")=="file"){
hasFile = true;
}
});
return hasFile;
}
dojo.io.formHasFile = function(formNode){
return dojo.io.checkChildrenForFile(formNode);
}
dojo.io.updateNode = function(node, urlOrArgs){
node = dojo.byId(node);
var args = urlOrArgs;
if(dojo.lang.isString(urlOrArgs)){
args = { url: urlOrArgs };
}
args.mimetype = "text/html";
args.load = function(t, d, e){
while(node.firstChild){
if(dojo["event"]){
try{
dojo.event.browser.clean(node.firstChild);
}catch(e){}
}
node.removeChild(node.firstChild);
}
node.innerHTML = d;
};
dojo.io.bind(args);
}
dojo.io.formFilter = function(node) {
var type = (node.type||"").toLowerCase();
return !node.disabled && node.name
&& !dojo.lang.inArray(["file", "submit", "image", "reset", "button"], type);
}
// TODO: Move to htmlUtils
dojo.io.encodeForm = function(formNode, encoding, formFilter){
if((!formNode)||(!formNode.tagName)||(!formNode.tagName.toLowerCase() == "form")){
dojo.raise("Attempted to encode a non-form element.");
}
if(!formFilter) { formFilter = dojo.io.formFilter; }
var enc = /utf/i.test(encoding||"") ? encodeURIComponent : dojo.string.encodeAscii;
var values = [];
for(var i = 0; i < formNode.elements.length; i++){
var elm = formNode.elements[i];
if(!elm || elm.tagName.toLowerCase() == "fieldset" || !formFilter(elm)) { continue; }
var name = enc(elm.name);
var type = elm.type.toLowerCase();
if(type == "select-multiple"){
for(var j = 0; j < elm.options.length; j++){
if(elm.options[j].selected) {
values.push(name + "=" + enc(elm.options[j].value));
}
}
}else if(dojo.lang.inArray(["radio", "checkbox"], type)){
if(elm.checked){
values.push(name + "=" + enc(elm.value));
}
}else{
values.push(name + "=" + enc(elm.value));
}
}
// now collect input type="image", which doesn't show up in the elements array
var inputs = formNode.getElementsByTagName("input");
for(var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if(input.type.toLowerCase() == "image" && input.form == formNode
&& formFilter(input)) {
var name = enc(input.name);
values.push(name + "=" + enc(input.value));
values.push(name + ".x=0");
values.push(name + ".y=0");
}
}
return values.join("&") + "&";
}
dojo.io.FormBind = function(args) {
this.bindArgs = {};
if(args && args.formNode) {
this.init(args);
} else if(args) {
this.init({formNode: args});
}
}
dojo.lang.extend(dojo.io.FormBind, {
form: null,
bindArgs: null,
clickedButton: null,
init: function(args) {
var form = dojo.byId(args.formNode);
if(!form || !form.tagName || form.tagName.toLowerCase() != "form") {
throw new Error("FormBind: Couldn't apply, invalid form");
} else if(this.form == form) {
return;
} else if(this.form) {
throw new Error("FormBind: Already applied to a form");
}
dojo.lang.mixin(this.bindArgs, args);
this.form = form;
this.connect(form, "onsubmit", "submit");
for(var i = 0; i < form.elements.length; i++) {
var node = form.elements[i];
if(node && node.type && dojo.lang.inArray(["submit", "button"], node.type.toLowerCase())) {
this.connect(node, "onclick", "click");
}
}
var inputs = form.getElementsByTagName("input");
for(var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if(input.type.toLowerCase() == "image" && input.form == form) {
this.connect(input, "onclick", "click");
}
}
},
onSubmit: function(form) {
return true;
},
submit: function(e) {
e.preventDefault();
if(this.onSubmit(this.form)) {
dojo.io.bind(dojo.lang.mixin(this.bindArgs, {
formFilter: dojo.lang.hitch(this, "formFilter")
}));
}
},
click: function(e) {
var node = e.currentTarget;
if(node.disabled) { return; }
this.clickedButton = node;
},
formFilter: function(node) {
var type = (node.type||"").toLowerCase();
var accept = false;
if(node.disabled || !node.name) {
accept = false;
} else if(dojo.lang.inArray(["submit", "button", "image"], type)) {
if(!this.clickedButton) { this.clickedButton = node; }
accept = node == this.clickedButton;
} else {
accept = !dojo.lang.inArray(["file", "submit", "reset", "button"], type);
}
return accept;
},
// in case you don't have dojo.event.* pulled in
connect: function(srcObj, srcFcn, targetFcn) {
if(dojo.evalObjPath("dojo.event.connect")) {
dojo.event.connect(srcObj, srcFcn, this, targetFcn);
} else {
var fcn = dojo.lang.hitch(this, targetFcn);
srcObj[srcFcn] = function(e) {
if(!e) { e = window.event; }
if(!e.currentTarget) { e.currentTarget = e.srcElement; }
if(!e.preventDefault) { e.preventDefault = function() { window.event.returnValue = false; } }
fcn(e);
}
}
}
});
dojo.io.XMLHTTPTransport = new function(){
var _this = this;
var _cache = {}; // FIXME: make this public? do we even need to?
this.useCache = false; // if this is true, we'll cache unless kwArgs.useCache = false
this.preventCache = false; // if this is true, we'll always force GET requests to cache
// FIXME: Should this even be a function? or do we just hard code it in the next 2 functions?
function getCacheKey(url, query, method) {
return url + "|" + query + "|" + method.toLowerCase();
}
function addToCache(url, query, method, http) {
_cache[getCacheKey(url, query, method)] = http;
}
function getFromCache(url, query, method) {
return _cache[getCacheKey(url, query, method)];
}
this.clearCache = function() {
_cache = {};
}
// moved successful load stuff here
function doLoad(kwArgs, http, url, query, useCache) {
if( ((http.status>=200)&&(http.status<300))|| // allow any 2XX response code
(http.status==304)|| // get it out of the cache
(location.protocol=="file:" && (http.status==0 || http.status==undefined))||
(location.protocol=="chrome:" && (http.status==0 || http.status==undefined))
){
var ret;
if(kwArgs.method.toLowerCase() == "head"){
var headers = http.getAllResponseHeaders();
ret = {};
ret.toString = function(){ return headers; }
var values = headers.split(/[\r\n]+/g);
for(var i = 0; i < values.length; i++) {
var pair = values[i].match(/^([^:]+)\s*:\s*(.+)$/i);
if(pair) {
ret[pair[1]] = pair[2];
}
}
}else if(kwArgs.mimetype == "text/javascript"){
try{
ret = dj_eval(http.responseText);
}catch(e){
dojo.debug(e);
dojo.debug(http.responseText);
ret = null;
}
}else if(kwArgs.mimetype == "text/json"){
try{
ret = dj_eval("("+http.responseText+")");
}catch(e){
dojo.debug(e);
dojo.debug(http.responseText);
ret = false;
}
}else if((kwArgs.mimetype == "application/xml")||
(kwArgs.mimetype == "text/xml")){
ret = http.responseXML;
if(!ret || typeof ret == "string" || !http.getResponseHeader("Content-Type")) {
ret = dojo.dom.createDocumentFromText(http.responseText);
}
}else{
ret = http.responseText;
}
if(useCache){ // only cache successful responses
addToCache(url, query, kwArgs.method, http);
}
kwArgs[(typeof kwArgs.load == "function") ? "load" : "handle"]("load", ret, http, kwArgs);
}else{
var errObj = new dojo.io.Error("XMLHttpTransport Error: "+http.status+" "+http.statusText);
kwArgs[(typeof kwArgs.error == "function") ? "error" : "handle"]("error", errObj, http, kwArgs);
}
}
// set headers (note: Content-Type will get overriden if kwArgs.contentType is set)
function setHeaders(http, kwArgs){
if(kwArgs["headers"]) {
for(var header in kwArgs["headers"]) {
if(header.toLowerCase() == "content-type" && !kwArgs["contentType"]) {
kwArgs["contentType"] = kwArgs["headers"][header];
} else {
http.setRequestHeader(header, kwArgs["headers"][header]);
}
}
}
}
this.inFlight = [];
this.inFlightTimer = null;
this.startWatchingInFlight = function(){
if(!this.inFlightTimer){
// setInterval broken in mozilla x86_64 in some circumstances, see
// https://bugzilla.mozilla.org/show_bug.cgi?id=344439
// using setTimeout instead
this.inFlightTimer = setTimeout("dojo.io.XMLHTTPTransport.watchInFlight();", 10);
}
}
this.watchInFlight = function(){
var now = null;
// 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(!dojo.hostenv._blockAsync && !_this._blockAsync){
for(var x=this.inFlight.length-1; x>=0; x--){
var tif = this.inFlight[x];
if(!tif || tif.http._aborted || !tif.http.readyState){
this.inFlight.splice(x, 1); continue;
}
if(4==tif.http.readyState){
// remove it so we can clean refs
this.inFlight.splice(x, 1);
doLoad(tif.req, tif.http, tif.url, tif.query, tif.useCache);
}else if (tif.startTime){
//See if this is a timeout case.
if(!now){
now = (new Date()).getTime();
}
if(tif.startTime + (tif.req.timeoutSeconds * 1000) < now){
//Stop the request.
if(typeof tif.http.abort == "function"){
tif.http.abort();
}
// remove it so we can clean refs
this.inFlight.splice(x, 1);
tif.req[(typeof tif.req.timeout == "function") ? "timeout" : "handle"]("timeout", null, tif.http, tif.req);
}
}
}
}
clearTimeout(this.inFlightTimer);
if(this.inFlight.length == 0){
this.inFlightTimer = null;
return;
}
this.inFlightTimer = setTimeout("dojo.io.XMLHTTPTransport.watchInFlight();", 10);
}
var hasXmlHttp = dojo.hostenv.getXmlhttpObject() ? true : false;
this.canHandle = function(kwArgs){
// canHandle just tells dojo.io.bind() if this is a good transport to
// use for the particular type of request.
// FIXME: we need to determine when form values need to be
// multi-part mime encoded and avoid using this transport for those
// requests.
return hasXmlHttp
&& dojo.lang.inArray(["text/plain", "text/html", "application/xml", "text/xml", "text/javascript", "text/json"], (kwArgs["mimetype"].toLowerCase()||""))
&& !( kwArgs["formNode"] && dojo.io.formHasFile(kwArgs["formNode"]) );
}
this.multipartBoundary = "45309FFF-BD65-4d50-99C9-36986896A96F"; // unique guid as a boundary value for multipart posts
this.bind = function(kwArgs){
if(!kwArgs["url"]){
// are we performing a history action?
if( !kwArgs["formNode"]
&& (kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"] || kwArgs["watchForURL"])
&& (!djConfig.preventBackButtonFix)) {
dojo.deprecated("Using dojo.io.XMLHTTPTransport.bind() to add to browser history without doing an IO request",
"Use dojo.undo.browser.addToHistory() instead.", "0.4");
dojo.undo.browser.addToHistory(kwArgs);
return true;
}
}
// build this first for cache purposes
var url = kwArgs.url;
var query = "";
if(kwArgs["formNode"]){
var ta = kwArgs.formNode.getAttribute("action");
if((ta)&&(!kwArgs["url"])){ url = ta; }
var tp = kwArgs.formNode.getAttribute("method");
if((tp)&&(!kwArgs["method"])){ kwArgs.method = tp; }
query += dojo.io.encodeForm(kwArgs.formNode, kwArgs.encoding, kwArgs["formFilter"]);
}
if(url.indexOf("#") > -1) {
dojo.debug("Warning: dojo.io.bind: stripping hash values from url:", url);
url = url.split("#")[0];
}
if(kwArgs["file"]){
// force post for file transfer
kwArgs.method = "post";
}
if(!kwArgs["method"]){
kwArgs.method = "get";
}
// guess the multipart value
if(kwArgs.method.toLowerCase() == "get"){
// GET cannot use multipart
kwArgs.multipart = false;
}else{
if(kwArgs["file"]){
// enforce multipart when sending files
kwArgs.multipart = true;
}else if(!kwArgs["multipart"]){
// default
kwArgs.multipart = false;
}
}
if(kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"]){
dojo.undo.browser.addToHistory(kwArgs);
}
var content = kwArgs["content"] || {};
if(kwArgs.sendTransport) {
content["dojo.transport"] = "xmlhttp";
}
do { // break-block
if(kwArgs.postContent){
query = kwArgs.postContent;
break;
}
if(content) {
query += dojo.io.argsFromMap(content, kwArgs.encoding);
}
if(kwArgs.method.toLowerCase() == "get" || !kwArgs.multipart){
break;
}
var t = [];
if(query.length){
var q = query.split("&");
for(var i = 0; i < q.length; ++i){
if(q[i].length){
var p = q[i].split("=");
t.push( "--" + this.multipartBoundary,
"Content-Disposition: form-data; name=\"" + p[0] + "\"",
"",
p[1]);
}
}
}
if(kwArgs.file){
if(dojo.lang.isArray(kwArgs.file)){
for(var i = 0; i < kwArgs.file.length; ++i){
var o = kwArgs.file[i];
t.push( "--" + this.multipartBoundary,
"Content-Disposition: form-data; name=\"" + o.name + "\"; filename=\"" + ("fileName" in o ? o.fileName : o.name) + "\"",
"Content-Type: " + ("contentType" in o ? o.contentType : "application/octet-stream"),
"",
o.content);
}
}else{
var o = kwArgs.file;
t.push( "--" + this.multipartBoundary,
"Content-Disposition: form-data; name=\"" + o.name + "\"; filename=\"" + ("fileName" in o ? o.fileName : o.name) + "\"",
"Content-Type: " + ("contentType" in o ? o.contentType : "application/octet-stream"),
"",
o.content);
}
}
if(t.length){
t.push("--"+this.multipartBoundary+"--", "");
query = t.join("\r\n");
}
}while(false);
// kwArgs.Connection = "close";
var async = kwArgs["sync"] ? false : true;
var preventCache = kwArgs["preventCache"] ||
(this.preventCache == true && kwArgs["preventCache"] != false);
var useCache = kwArgs["useCache"] == true ||
(this.useCache == true && kwArgs["useCache"] != false );
// preventCache is browser-level (add query string junk), useCache
// is for the local cache. If we say preventCache, then don't attempt
// to look in the cache, but if useCache is true, we still want to cache
// the response
if(!preventCache && useCache){
var cachedHttp = getFromCache(url, query, kwArgs.method);
if(cachedHttp){
doLoad(kwArgs, cachedHttp, url, query, false);
return;
}
}
// much of this is from getText, but reproduced here because we need
// more flexibility
var http = dojo.hostenv.getXmlhttpObject(kwArgs);
var received = false;
// build a handler function that calls back to the handler obj
if(async){
var startTime =
// FIXME: setting up this callback handler leaks on IE!!!
this.inFlight.push({
"req": kwArgs,
"http": http,
"url": url,
"query": query,
"useCache": useCache,
"startTime": kwArgs.timeoutSeconds ? (new Date()).getTime() : 0
});
this.startWatchingInFlight();
}else{
// block async callbacks until sync is in, needed in khtml, others?
_this._blockAsync = true;
}
if(kwArgs.method.toLowerCase() == "post"){
// FIXME: need to hack in more flexible Content-Type setting here!
http.open("POST", url, async);
setHeaders(http, kwArgs);
http.setRequestHeader("Content-Type", kwArgs.multipart ? ("multipart/form-data; boundary=" + this.multipartBoundary) :
(kwArgs.contentType || "application/x-www-form-urlencoded"));
try{
http.send(query);
}catch(e){
if(typeof http.abort == "function"){
http.abort();
}
doLoad(kwArgs, {status: 404}, url, query, useCache);
}
}else{
var tmpUrl = url;
if(query != "") {
tmpUrl += (tmpUrl.indexOf("?") > -1 ? "&" : "?") + query;
}
if(preventCache) {
tmpUrl += (dojo.string.endsWithAny(tmpUrl, "?", "&")
? "" : (tmpUrl.indexOf("?") > -1 ? "&" : "?")) + "dojo.preventCache=" + new Date().valueOf();
}
http.open(kwArgs.method.toUpperCase(), tmpUrl, async);
setHeaders(http, kwArgs);
try {
http.send(null);
}catch(e) {
if(typeof http.abort == "function"){
http.abort();
}
doLoad(kwArgs, {status: 404}, url, query, useCache);
}
}
if( !async ) {
doLoad(kwArgs, http, url, query, useCache);
_this._blockAsync = false;
}
kwArgs.abort = function(){
try{// khtml doesent reset readyState on abort, need this workaround
http._aborted = true;
}catch(e){/*squelsh*/}
return http.abort();
}
return;
}
dojo.io.transports.addTransport("XMLHTTPTransport");
}
dojo.provide("dojo.io.cookie");
dojo.io.cookie.setCookie = function(name, value, days, path, domain, secure) {
var expires = -1;
if(typeof days == "number" && days >= 0) {
var d = new Date();
d.setTime(d.getTime()+(days*24*60*60*1000));
expires = d.toGMTString();
}
value = escape(value);
document.cookie = name + "=" + value + ";"
+ (expires != -1 ? " expires=" + expires + ";" : "")
+ (path ? "path=" + path : "")
+ (domain ? "; domain=" + domain : "")
+ (secure ? "; secure" : "");
}
dojo.io.cookie.set = dojo.io.cookie.setCookie;
dojo.io.cookie.getCookie = function(name) {
// FIXME: Which cookie should we return?
// If there are cookies set for different sub domains in the current
// scope there could be more than one cookie with the same name.
// I think taking the last one in the list takes the one from the
// deepest subdomain, which is what we're doing here.
var idx = document.cookie.lastIndexOf(name+'=');
if(idx == -1) { return null; }
var value = document.cookie.substring(idx+name.length+1);
var end = value.indexOf(';');
if(end == -1) { end = value.length; }
value = value.substring(0, end);
value = unescape(value);
return value;
}
dojo.io.cookie.get = dojo.io.cookie.getCookie;
dojo.io.cookie.deleteCookie = function(name) {
dojo.io.cookie.setCookie(name, "-", 0);
}
dojo.io.cookie.setObjectCookie = function(name, obj, days, path, domain, secure, clearCurrent) {
if(arguments.length == 5) { // for backwards compat
clearCurrent = domain;
domain = null;
secure = null;
}
var pairs = [], cookie, value = "";
if(!clearCurrent) { cookie = dojo.io.cookie.getObjectCookie(name); }
if(days >= 0) {
if(!cookie) { cookie = {}; }
for(var prop in obj) {
if(prop == null) {
delete cookie[prop];
} else if(typeof obj[prop] == "string" || typeof obj[prop] == "number") {
cookie[prop] = obj[prop];
}
}
prop = null;
for(var prop in cookie) {
pairs.push(escape(prop) + "=" + escape(cookie[prop]));
}
value = pairs.join("&");
}
dojo.io.cookie.setCookie(name, value, days, path, domain, secure);
}
dojo.io.cookie.getObjectCookie = function(name) {
var values = null, cookie = dojo.io.cookie.getCookie(name);
if(cookie) {
values = {};
var pairs = cookie.split("&");
for(var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split("=");
var value = pair[1];
if( isNaN(value) ) { value = unescape(pair[1]); }
values[ unescape(pair[0]) ] = value;
}
}
return values;
}
dojo.io.cookie.isSupported = function() {
if(typeof navigator.cookieEnabled != "boolean") {
dojo.io.cookie.setCookie("__TestingYourBrowserForCookieSupport__",
"CookiesAllowed", 90, null);
var cookieVal = dojo.io.cookie.getCookie("__TestingYourBrowserForCookieSupport__");
navigator.cookieEnabled = (cookieVal == "CookiesAllowed");
if(navigator.cookieEnabled) {
// FIXME: should we leave this around?
this.deleteCookie("__TestingYourBrowserForCookieSupport__");
}
}
return navigator.cookieEnabled;
}
// need to leave this in for backwards-compat from 0.1 for when it gets pulled in by dojo.io.*
if(!dojo.io.cookies) { dojo.io.cookies = dojo.io.cookie; }
dojo.provide("dojo.io.*");
dojo.provide("dojo.event");
// TODO: connection filter functions
// these are functions that accept a method invocation (like around
// advice) and return a boolean based on it. That value determines
// whether or not the connection proceeds. It could "feel" like around
// advice for those who know what it is (calling proceed() or not),
// but I think presenting it as a "filter" and/or calling it with the
// function args and not the MethodInvocation might make it more
// palletable to "normal" users than around-advice currently is
// TODO: execution scope mangling
// YUI's event facility by default executes listeners in the context
// of the source object. This is very odd, but should probably be
// supported as an option (both for the source and for the dest). It
// can be thought of as a connection-specific hitch().
// TODO: more resiliency for 4+ arguments to connect()
dojo.event = new function(){
this.canTimeout = dojo.lang.isFunction(dj_global["setTimeout"])||dojo.lang.isAlien(dj_global["setTimeout"]);
// FIXME: where should we put this method (not here!)?
function interpolateArgs(args, searchForNames){
var dl = dojo.lang;
var ao = {
srcObj: dj_global,
srcFunc: null,
adviceObj: dj_global,
adviceFunc: null,
aroundObj: null,
aroundFunc: null,
adviceType: (args.length>2) ? args[0] : "after",
precedence: "last",
once: false,
delay: null,
rate: 0,
adviceMsg: false
};
switch(args.length){
case 0: return;
case 1: return;
case 2:
ao.srcFunc = args[0];
ao.adviceFunc = args[1];
break;
case 3:
if((dl.isObject(args[0]))&&(dl.isString(args[1]))&&(dl.isString(args[2]))){
ao.adviceType = "after";
ao.srcObj = args[0];
ao.srcFunc = args[1];
ao.adviceFunc = args[2];
}else if((dl.isString(args[1]))&&(dl.isString(args[2]))){
ao.srcFunc = args[1];
ao.adviceFunc = args[2];
}else if((dl.isObject(args[0]))&&(dl.isString(args[1]))&&(dl.isFunction(args[2]))){
ao.adviceType = "after";
ao.srcObj = args[0];
ao.srcFunc = args[1];
var tmpName = dl.nameAnonFunc(args[2], ao.adviceObj, searchForNames);
ao.adviceFunc = tmpName;
}else if((dl.isFunction(args[0]))&&(dl.isObject(args[1]))&&(dl.isString(args[2]))){
ao.adviceType = "after";
ao.srcObj = dj_global;
var tmpName = dl.nameAnonFunc(args[0], ao.srcObj, searchForNames);
ao.srcFunc = tmpName;
ao.adviceObj = args[1];
ao.adviceFunc = args[2];
}
break;
case 4:
if((dl.isObject(args[0]))&&(dl.isObject(args[2]))){
// we can assume that we've got an old-style "connect" from
// the sigslot school of event attachment. We therefore
// assume after-advice.
ao.adviceType = "after";
ao.srcObj = args[0];
ao.srcFunc = args[1];
ao.adviceObj = args[2];
ao.adviceFunc = args[3];
}else if((dl.isString(args[0]))&&(dl.isString(args[1]))&&(dl.isObject(args[2]))){
ao.adviceType = args[0];
ao.srcObj = dj_global;
ao.srcFunc = args[1];
ao.adviceObj = args[2];
ao.adviceFunc = args[3];
}else if((dl.isString(args[0]))&&(dl.isFunction(args[1]))&&(dl.isObject(args[2]))){
ao.adviceType = args[0];
ao.srcObj = dj_global;
var tmpName = dl.nameAnonFunc(args[1], dj_global, searchForNames);
ao.srcFunc = tmpName;
ao.adviceObj = args[2];
ao.adviceFunc = args[3];
}else if((dl.isString(args[0]))&&(dl.isObject(args[1]))&&(dl.isString(args[2]))&&(dl.isFunction(args[3]))){
ao.srcObj = args[1];
ao.srcFunc = args[2];
var tmpName = dl.nameAnonFunc(args[3], dj_global, searchForNames);
ao.adviceObj = dj_global;
ao.adviceFunc = tmpName;
}else if(dl.isObject(args[1])){
ao.srcObj = args[1];
ao.srcFunc = args[2];
ao.adviceObj = dj_global;
ao.adviceFunc = args[3];
}else if(dl.isObject(args[2])){
ao.srcObj = dj_global;
ao.srcFunc = args[1];
ao.adviceObj = args[2];
ao.adviceFunc = args[3];
}else{
ao.srcObj = ao.adviceObj = ao.aroundObj = dj_global;
ao.srcFunc = args[1];
ao.adviceFunc = args[2];
ao.aroundFunc = args[3];
}
break;
case 6:
ao.srcObj = args[1];
ao.srcFunc = args[2];
ao.adviceObj = args[3]
ao.adviceFunc = args[4];
ao.aroundFunc = args[5];
ao.aroundObj = dj_global;
break;
default:
ao.srcObj = args[1];
ao.srcFunc = args[2];
ao.adviceObj = args[3]
ao.adviceFunc = args[4];
ao.aroundObj = args[5];
ao.aroundFunc = args[6];
ao.once = args[7];
ao.delay = args[8];
ao.rate = args[9];
ao.adviceMsg = args[10];
break;
}
if(dl.isFunction(ao.aroundFunc)){
var tmpName = dl.nameAnonFunc(ao.aroundFunc, ao.aroundObj, searchForNames);
ao.aroundFunc = tmpName;
}
if(dl.isFunction(ao.srcFunc)){
ao.srcFunc = dl.getNameInObj(ao.srcObj, ao.srcFunc);
}
if(dl.isFunction(ao.adviceFunc)){
ao.adviceFunc = dl.getNameInObj(ao.adviceObj, ao.adviceFunc);
}
if((ao.aroundObj)&&(dl.isFunction(ao.aroundFunc))){
ao.aroundFunc = dl.getNameInObj(ao.aroundObj, ao.aroundFunc);
}
if(!ao.srcObj){
dojo.raise("bad srcObj for srcFunc: "+ao.srcFunc);
}
if(!ao.adviceObj){
dojo.raise("bad adviceObj for adviceFunc: "+ao.adviceFunc);
}
if(!ao.adviceFunc){
dojo.debug("bad adviceFunc for srcFunc: "+ao.srcFunc);
dojo.debugShallow(ao);
}
return ao;
}
this.connect = function(){
if(arguments.length == 1){
var ao = arguments[0];
}else{
var ao = interpolateArgs(arguments, true);
}
if(dojo.lang.isArray(ao.srcObj) && ao.srcObj!=""){
var tmpAO = {};
for(var x in ao){
tmpAO[x] = ao[x];
}
var mjps = [];
dojo.lang.forEach(ao.srcObj, function(src){
if((dojo.render.html.capable)&&(dojo.lang.isString(src))){
src = dojo.byId(src);
// dojo.debug(src);
}
tmpAO.srcObj = src;
// dojo.debug(tmpAO.srcObj, tmpAO.srcFunc);
// dojo.debug(tmpAO.adviceObj, tmpAO.adviceFunc);
mjps.push(dojo.event.connect.call(dojo.event, tmpAO));
});
return mjps;
}
// FIXME: just doing a "getForMethod()" seems to be enough to put this into infinite recursion!!
var mjp = dojo.event.MethodJoinPoint.getForMethod(ao.srcObj, ao.srcFunc);
if(ao.adviceFunc){
var mjp2 = dojo.event.MethodJoinPoint.getForMethod(ao.adviceObj, ao.adviceFunc);
}
mjp.kwAddAdvice(ao);
return mjp; // advanced users might want to fsck w/ the join point
// manually
}
this.log = function(a1, a2){
var kwArgs;
if((arguments.length == 1)&&(typeof a1 == "object")){
kwArgs = a1;
}else{
kwArgs = {
srcObj: a1,
srcFunc: a2
};
}
kwArgs.adviceFunc = function(){
var argsStr = [];
for(var x=0; x<arguments.length; x++){
argsStr.push(arguments[x]);
}
dojo.debug("("+kwArgs.srcObj+")."+kwArgs.srcFunc, ":", argsStr.join(", "));
}
this.kwConnect(kwArgs);
}
this.connectBefore = function(){
var args = ["before"];
for(var i = 0; i < arguments.length; i++) { args.push(arguments[i]); }
return this.connect.apply(this, args);
}
this.connectAround = function(){
var args = ["around"];
for(var i = 0; i < arguments.length; i++) { args.push(arguments[i]); }
return this.connect.apply(this, args);
}
this.connectOnce = function(){
var ao = interpolateArgs(arguments, true);
ao.once = true;
return this.connect(ao);
}
this._kwConnectImpl = function(kwArgs, disconnect){
var fn = (disconnect) ? "disconnect" : "connect";
if(typeof kwArgs["srcFunc"] == "function"){
kwArgs.srcObj = kwArgs["srcObj"]||dj_global;
var tmpName = dojo.lang.nameAnonFunc(kwArgs.srcFunc, kwArgs.srcObj, true);
kwArgs.srcFunc = tmpName;
}
if(typeof kwArgs["adviceFunc"] == "function"){
kwArgs.adviceObj = kwArgs["adviceObj"]||dj_global;
var tmpName = dojo.lang.nameAnonFunc(kwArgs.adviceFunc, kwArgs.adviceObj, true);
kwArgs.adviceFunc = tmpName;
}
return dojo.event[fn]( (kwArgs["type"]||kwArgs["adviceType"]||"after"),
kwArgs["srcObj"]||dj_global,
kwArgs["srcFunc"],
kwArgs["adviceObj"]||kwArgs["targetObj"]||dj_global,
kwArgs["adviceFunc"]||kwArgs["targetFunc"],
kwArgs["aroundObj"],
kwArgs["aroundFunc"],
kwArgs["once"],
kwArgs["delay"],
kwArgs["rate"],
kwArgs["adviceMsg"]||false );
}
this.kwConnect = function(kwArgs){
return this._kwConnectImpl(kwArgs, false);
}
this.disconnect = function(){
var ao = interpolateArgs(arguments, true);
if(!ao.adviceFunc){ return; } // nothing to disconnect
var mjp = dojo.event.MethodJoinPoint.getForMethod(ao.srcObj, ao.srcFunc);
return mjp.removeAdvice(ao.adviceObj, ao.adviceFunc, ao.adviceType, ao.once);
}
this.kwDisconnect = function(kwArgs){
return this._kwConnectImpl(kwArgs, true);
}
}
// exactly one of these is created whenever a method with a joint point is run,
// if there is at least one 'around' advice.
dojo.event.MethodInvocation = function(join_point, obj, args) {
this.jp_ = join_point;
this.object = obj;
this.args = [];
for(var x=0; x<args.length; x++){
this.args[x] = args[x];
}
// the index of the 'around' that is currently being executed.
this.around_index = -1;
}
dojo.event.MethodInvocation.prototype.proceed = function() {
this.around_index++;
if(this.around_index >= this.jp_.around.length){
return this.jp_.object[this.jp_.methodname].apply(this.jp_.object, this.args);
// return this.jp_.run_before_after(this.object, this.args);
}else{
var ti = this.jp_.around[this.around_index];
var mobj = ti[0]||dj_global;
var meth = ti[1];
return mobj[meth].call(mobj, this);
}
}
dojo.event.MethodJoinPoint = function(obj, methname){
this.object = obj||dj_global;
this.methodname = methname;
this.methodfunc = this.object[methname];
this.before = [];
this.after = [];
this.around = [];
}
dojo.event.MethodJoinPoint.getForMethod = function(obj, methname) {
// if(!(methname in obj)){
if(!obj){ obj = dj_global; }
if(!obj[methname]){
// supply a do-nothing method implementation
obj[methname] = function(){};
if(!obj[methname]){
// e.g. cannot add to inbuilt objects in IE6
dojo.raise("Cannot set do-nothing method on that object "+methname);
}
}else if((!dojo.lang.isFunction(obj[methname]))&&(!dojo.lang.isAlien(obj[methname]))){
return null; // FIXME: should we throw an exception here instead?
}
// we hide our joinpoint instance in obj[methname + '$joinpoint']
var jpname = methname + "$joinpoint";
var jpfuncname = methname + "$joinpoint$method";
var joinpoint = obj[jpname];
if(!joinpoint){
var isNode = false;
if(dojo.event["browser"]){
if( (obj["attachEvent"])||
(obj["nodeType"])||
(obj["addEventListener"]) ){
isNode = true;
dojo.event.browser.addClobberNodeAttrs(obj, [jpname, jpfuncname, methname]);
}
}
var origArity = obj[methname].length;
obj[jpfuncname] = obj[methname];
// joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, methname);
joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, jpfuncname);
obj[methname] = function(){
var args = [];
if((isNode)&&(!arguments.length)){
var evt = null;
try{
if(obj.ownerDocument){
evt = obj.ownerDocument.parentWindow.event;
}else if(obj.documentElement){
evt = obj.documentElement.ownerDocument.parentWindow.event;
}else if(obj.event){ //obj is a window
evt = obj.event;
}else{
evt = window.event;
}
}catch(e){
evt = window.event;
}
if(evt){
args.push(dojo.event.browser.fixEvent(evt, this));
}
}else{
for(var x=0; x<arguments.length; x++){
if((x==0)&&(isNode)&&(dojo.event.browser.isEvent(arguments[x]))){
args.push(dojo.event.browser.fixEvent(arguments[x], this));
}else{
args.push(arguments[x]);
}
}
}
// return joinpoint.run.apply(joinpoint, arguments);
return joinpoint.run.apply(joinpoint, args);
}
obj[methname].__preJoinArity = origArity;
}
return joinpoint;
}
dojo.lang.extend(dojo.event.MethodJoinPoint, {
unintercept: function(){
this.object[this.methodname] = this.methodfunc;
this.before = [];
this.after = [];
this.around = [];
},
disconnect: dojo.lang.forward("unintercept"),
run: function() {
var obj = this.object||dj_global;
var args = arguments;
// optimization. We only compute once the array version of the arguments
// pseudo-arr in order to prevent building it each time advice is unrolled.
var aargs = [];
for(var x=0; x<args.length; x++){
aargs[x] = args[x];
}
var unrollAdvice = function(marr){
if(!marr){
dojo.debug("Null argument to unrollAdvice()");
return;
}
var callObj = marr[0]||dj_global;
var callFunc = marr[1];
if(!callObj[callFunc]){
dojo.raise("function \"" + callFunc + "\" does not exist on \"" + callObj + "\"");
}
var aroundObj = marr[2]||dj_global;
var aroundFunc = marr[3];
var msg = marr[6];
var undef;
var to = {
args: [],
jp_: this,
object: obj,
proceed: function(){
return callObj[callFunc].apply(callObj, to.args);
}
};
to.args = aargs;
var delay = parseInt(marr[4]);
var hasDelay = ((!isNaN(delay))&&(marr[4]!==null)&&(typeof marr[4] != "undefined"));
if(marr[5]){
var rate = parseInt(marr[5]);
var cur = new Date();
var timerSet = false;
if((marr["last"])&&((cur-marr.last)<=rate)){
if(dojo.event.canTimeout){
if(marr["delayTimer"]){
clearTimeout(marr.delayTimer);
}
var tod = parseInt(rate*2); // is rate*2 naive?
var mcpy = dojo.lang.shallowCopy(marr);
marr.delayTimer = setTimeout(function(){
// FIXME: on IE at least, event objects from the
// browser can go out of scope. How (or should?) we
// deal with it?
mcpy[5] = 0;
unrollAdvice(mcpy);
}, tod);
}
return;
}else{
marr.last = cur;
}
}
// FIXME: need to enforce rates for a connection here!
if(aroundFunc){
// NOTE: around advice can't delay since we might otherwise depend
// on execution order!
aroundObj[aroundFunc].call(aroundObj, to);
}else{
// var tmjp = dojo.event.MethodJoinPoint.getForMethod(obj, methname);
if((hasDelay)&&((dojo.render.html)||(dojo.render.svg))){ // FIXME: the render checks are grotty!
dj_global["setTimeout"](function(){
if(msg){
callObj[callFunc].call(callObj, to);
}else{
callObj[callFunc].apply(callObj, args);
}
}, delay);
}else{ // many environments can't support delay!
if(msg){
callObj[callFunc].call(callObj, to);
}else{
callObj[callFunc].apply(callObj, args);
}
}
}
}
if(this.before.length>0){
// pass a cloned array, if this event disconnects this event forEach on this.before wont work
dojo.lang.forEach(this.before.concat(new Array()), unrollAdvice);
}
var result;
if(this.around.length>0){
var mi = new dojo.event.MethodInvocation(this, obj, args);
result = mi.proceed();
}else if(this.methodfunc){
result = this.object[this.methodname].apply(this.object, args);
}
if(this.after.length>0){
// see comment on this.before above
dojo.lang.forEach(this.after.concat(new Array()), unrollAdvice);
}
return (this.methodfunc) ? result : null;
},
getArr: function(kind){
var arr = this.after;
// FIXME: we should be able to do this through props or Array.in()
if((typeof kind == "string")&&(kind.indexOf("before")!=-1)){
arr = this.before;
}else if(kind=="around"){
arr = this.around;
}
return arr;
},
kwAddAdvice: function(args){
this.addAdvice( args["adviceObj"], args["adviceFunc"],
args["aroundObj"], args["aroundFunc"],
args["adviceType"], args["precedence"],
args["once"], args["delay"], args["rate"],
args["adviceMsg"]);
},
addAdvice: function( thisAdviceObj, thisAdvice,
thisAroundObj, thisAround,
advice_kind, precedence,
once, delay, rate, asMessage){
var arr = this.getArr(advice_kind);
if(!arr){
dojo.raise("bad this: " + this);
}
var ao = [thisAdviceObj, thisAdvice, thisAroundObj, thisAround, delay, rate, asMessage];
if(once){
if(this.hasAdvice(thisAdviceObj, thisAdvice, advice_kind, arr) >= 0){
return;
}
}
if(precedence == "first"){
arr.unshift(ao);
}else{
arr.push(ao);
}
},
hasAdvice: function(thisAdviceObj, thisAdvice, advice_kind, arr){
if(!arr){ arr = this.getArr(advice_kind); }
var ind = -1;
for(var x=0; x<arr.length; x++){
var aao = (typeof thisAdvice == "object") ? (new String(thisAdvice)).toString() : thisAdvice;
var a1o = (typeof arr[x][1] == "object") ? (new String(arr[x][1])).toString() : arr[x][1];
if((arr[x][0] == thisAdviceObj)&&(a1o == aao)){
ind = x;
}
}
return ind;
},
removeAdvice: function(thisAdviceObj, thisAdvice, advice_kind, once){
var arr = this.getArr(advice_kind);
var ind = this.hasAdvice(thisAdviceObj, thisAdvice, advice_kind, arr);
if(ind == -1){
return false;
}
while(ind != -1){
arr.splice(ind, 1);
if(once){ break; }
ind = this.hasAdvice(thisAdviceObj, thisAdvice, advice_kind, arr);
}
return true;
}
});
dojo.provide("dojo.event.topic");
dojo.event.topic = new function(){
this.topics = {};
this.getTopic = function(topicName){
if(!this.topics[topicName]){
this.topics[topicName] = new this.TopicImpl(topicName);
}
return this.topics[topicName];
}
this.registerPublisher = function(topic, obj, funcName){
var topic = this.getTopic(topic);
topic.registerPublisher(obj, funcName);
}
this.subscribe = function(topic, obj, funcName){
var topic = this.getTopic(topic);
topic.subscribe(obj, funcName);
}
this.unsubscribe = function(topic, obj, funcName){
var topic = this.getTopic(topic);
topic.unsubscribe(obj, funcName);
}
this.destroy = function(topic){
this.getTopic(topic).destroy();
delete this.topics[topic];
}
this.publishApply = function(topic, args){
var topic = this.getTopic(topic);
topic.sendMessage.apply(topic, args);
}
this.publish = function(topic, message){
var topic = this.getTopic(topic);
// if message is an array, we treat it as a set of arguments,
// otherwise, we just pass on the arguments passed in as-is
var args = [];
// could we use concat instead here?
for(var x=1; x<arguments.length; x++){
args.push(arguments[x]);
}
topic.sendMessage.apply(topic, args);
}
}
dojo.event.topic.TopicImpl = function(topicName){
this.topicName = topicName;
this.subscribe = function(listenerObject, listenerMethod){
var tf = listenerMethod||listenerObject;
var to = (!listenerMethod) ? dj_global : listenerObject;
dojo.event.kwConnect({
srcObj: this,
srcFunc: "sendMessage",
adviceObj: to,
adviceFunc: tf
});
}
this.unsubscribe = function(listenerObject, listenerMethod){
var tf = (!listenerMethod) ? listenerObject : listenerMethod;
var to = (!listenerMethod) ? null : listenerObject;
dojo.event.kwDisconnect({
srcObj: this,
srcFunc: "sendMessage",
adviceObj: to,
adviceFunc: tf
});
}
this.destroy = function(){
dojo.event.MethodJoinPoint.getForMethod(this, "sendMessage").disconnect();
}
this.registerPublisher = function(publisherObject, publisherMethod){
dojo.event.connect(publisherObject, publisherMethod, this, "sendMessage");
}
this.sendMessage = function(message){
// The message has been propagated
}
}
dojo.provide("dojo.event.browser");
// FIXME: any particular reason this is in the global scope?
dojo._ie_clobber = new function(){
this.clobberNodes = [];
function nukeProp(node, prop){
// try{ node.removeAttribute(prop); }catch(e){ /* squelch */ }
try{ node[prop] = null; }catch(e){ /* squelch */ }
try{ delete node[prop]; }catch(e){ /* squelch */ }
// FIXME: JotLive needs this, but I'm not sure if it's too slow or not
try{ node.removeAttribute(prop); }catch(e){ /* squelch */ }
}
this.clobber = function(nodeRef){
var na;
var tna;
if(nodeRef){
tna = nodeRef.all || nodeRef.getElementsByTagName("*");
na = [nodeRef];
for(var x=0; x<tna.length; x++){
// if we're gonna be clobbering the thing, at least make sure
// we aren't trying to do it twice
if(tna[x]["__doClobber__"]){
na.push(tna[x]);
}
}
}else{
try{ window.onload = null; }catch(e){}
na = (this.clobberNodes.length) ? this.clobberNodes : document.all;
}
tna = null;
var basis = {};
for(var i = na.length-1; i>=0; i=i-1){
var el = na[i];
if(el["__clobberAttrs__"]){
for(var j=0; j<el.__clobberAttrs__.length; j++){
nukeProp(el, el.__clobberAttrs__[j]);
}
nukeProp(el, "__clobberAttrs__");
nukeProp(el, "__doClobber__");
}
}
na = null;
}
}
if(dojo.render.html.ie){
dojo.addOnUnload(function(){
dojo._ie_clobber.clobber();
try{
if((dojo["widget"])&&(dojo.widget["manager"])){
dojo.widget.manager.destroyAll();
}
}catch(e){}
try{ window.onload = null; }catch(e){}
try{ window.onunload = null; }catch(e){}
dojo._ie_clobber.clobberNodes = [];
// CollectGarbage();
});
}
dojo.event.browser = new function(){
var clobberIdx = 0;
this.clean = function(node){
if(dojo.render.html.ie){
dojo._ie_clobber.clobber(node);
}
}
this.addClobberNode = function(node){
if(!dojo.render.html.ie){ return; }
if(!node["__doClobber__"]){
node.__doClobber__ = true;
dojo._ie_clobber.clobberNodes.push(node);
// this might not be the most efficient thing to do, but it's
// much less error prone than other approaches which were
// previously tried and failed
node.__clobberAttrs__ = [];
}
}
this.addClobberNodeAttrs = function(node, props){
if(!dojo.render.html.ie){ return; }
this.addClobberNode(node);
for(var x=0; x<props.length; x++){
node.__clobberAttrs__.push(props[x]);
}
}
this.removeListener = function(node, evtName, fp, capture){
if(!capture){ var capture = false; }
evtName = evtName.toLowerCase();
if(evtName.substr(0,2)=="on"){ evtName = evtName.substr(2); }
// FIXME: this is mostly a punt, we aren't actually doing anything on IE
if(node.removeEventListener){
node.removeEventListener(evtName, fp, capture);
}
}
this.addListener = function(node, evtName, fp, capture, dontFix){
if(!node){ return; } // FIXME: log and/or bail?
if(!capture){ var capture = false; }
evtName = evtName.toLowerCase();
if(evtName.substr(0,2)!="on"){ evtName = "on"+evtName; }
if(!dontFix){
// build yet another closure around fp in order to inject fixEvent
// around the resulting event
var newfp = function(evt){
if(!evt){ evt = window.event; }
var ret = fp(dojo.event.browser.fixEvent(evt, this));
if(capture){
dojo.event.browser.stopEvent(evt);
}
return ret;
}
}else{
newfp = fp;
}
if(node.addEventListener){
node.addEventListener(evtName.substr(2), newfp, capture);
return newfp;
}else{
if(typeof node[evtName] == "function" ){
var oldEvt = node[evtName];
node[evtName] = function(e){
oldEvt(e);
return newfp(e);
}
}else{
node[evtName]=newfp;
}
if(dojo.render.html.ie){
this.addClobberNodeAttrs(node, [evtName]);
}
return newfp;
}
}
this.isEvent = function(obj){
// FIXME: event detection hack ... could test for additional attributes
// if necessary
return (typeof obj != "undefined")&&(typeof Event != "undefined")&&(obj.eventPhase);
// Event does not support instanceof in Opera, otherwise:
//return (typeof Event != "undefined")&&(obj instanceof Event);
}
this.currentEvent = null;
this.callListener = function(listener, curTarget){
if(typeof listener != 'function'){
dojo.raise("listener not a function: " + listener);
}
dojo.event.browser.currentEvent.currentTarget = curTarget;
return listener.call(curTarget, dojo.event.browser.currentEvent);
}
this.stopPropagation = function(){
dojo.event.browser.currentEvent.cancelBubble = true;
}
this.preventDefault = function(){
dojo.event.browser.currentEvent.returnValue = false;
}
this.keys = {
KEY_BACKSPACE: 8,
KEY_TAB: 9,
KEY_ENTER: 13,
KEY_SHIFT: 16,
KEY_CTRL: 17,
KEY_ALT: 18,
KEY_PAUSE: 19,
KEY_CAPS_LOCK: 20,
KEY_ESCAPE: 27,
KEY_SPACE: 32,
KEY_PAGE_UP: 33,
KEY_PAGE_DOWN: 34,
KEY_END: 35,
KEY_HOME: 36,
KEY_LEFT_ARROW: 37,
KEY_UP_ARROW: 38,
KEY_RIGHT_ARROW: 39,
KEY_DOWN_ARROW: 40,
KEY_INSERT: 45,
KEY_DELETE: 46,
KEY_LEFT_WINDOW: 91,
KEY_RIGHT_WINDOW: 92,
KEY_SELECT: 93,
KEY_F1: 112,
KEY_F2: 113,
KEY_F3: 114,
KEY_F4: 115,
KEY_F5: 116,
KEY_F6: 117,
KEY_F7: 118,
KEY_F8: 119,
KEY_F9: 120,
KEY_F10: 121,
KEY_F11: 122,
KEY_F12: 123,
KEY_NUM_LOCK: 144,
KEY_SCROLL_LOCK: 145
};
// reverse lookup
this.revKeys = [];
for(var key in this.keys){
this.revKeys[this.keys[key]] = key;
}
this.fixEvent = function(evt, sender){
if(!evt){
if(window["event"]){
evt = window.event;
}
}
if((evt["type"])&&(evt["type"].indexOf("key") == 0)){ // key events
evt.keys = this.revKeys;
// FIXME: how can we eliminate this iteration?
for(var key in this.keys) {
evt[key] = this.keys[key];
}
if((dojo.render.html.ie)&&(evt["type"] == "keypress")){
evt.charCode = evt.keyCode;
}
}
if(dojo.render.html.ie){
if(!evt.target){ evt.target = evt.srcElement; }
if(!evt.currentTarget){ evt.currentTarget = (sender ? sender : evt.srcElement); }
if(!evt.layerX){ evt.layerX = evt.offsetX; }
if(!evt.layerY){ evt.layerY = evt.offsetY; }
// FIXME: scroll position query is duped from dojo.html to avoid dependency on that entire module
// DONOT replace the following to use dojo.body(), in IE, document.documentElement should be used
// here rather than document.body
var doc = (evt.srcElement && evt.srcElement.ownerDocument) ? evt.srcElement.ownerDocument : document;
var docBody = ((dojo.render.html.ie55)||(doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
if(!evt.pageX){ evt.pageX = evt.clientX + (docBody.scrollLeft || 0) }
if(!evt.pageY){ evt.pageY = evt.clientY + (docBody.scrollTop || 0) }
// mouseover
if(evt.type == "mouseover"){ evt.relatedTarget = evt.fromElement; }
// mouseout
if(evt.type == "mouseout"){ evt.relatedTarget = evt.toElement; }
this.currentEvent = evt;
evt.callListener = this.callListener;
evt.stopPropagation = this.stopPropagation;
evt.preventDefault = this.preventDefault;
}
return evt;
}
this.stopEvent = function(ev) {
if(window.event){
ev.returnValue = false;
ev.cancelBubble = true;
}else{
ev.preventDefault();
ev.stopPropagation();
}
}
}
dojo.provide("dojo.event.*");
dojo.provide("dojo.xml.Parse");
//TODO: determine dependencies
// currently has dependency on dojo.xml.DomUtil nodeTypes constants...
/* generic method for taking a node and parsing it into an object
TODO: WARNING: This comment is wrong!
For example, the following xml fragment
<foo bar="bar">
<baz xyzzy="xyzzy"/>
</foo>
can be described as:
dojo.???.foo = {}
dojo.???.foo.bar = {}
dojo.???.foo.bar.value = "bar";
dojo.???.foo.baz = {}
dojo.???.foo.baz.xyzzy = {}
dojo.???.foo.baz.xyzzy.value = "xyzzy"
*/
// using documentFragment nomenclature to generalize in case we don't want to require passing a collection of nodes with a single parent
dojo.xml.Parse = function(){
function getDojoTagName(node){
var tagName = node.tagName;
if(dojo.render.html.capable && dojo.render.html.ie && node.scopeName != 'HTML'){
tagName = node.scopeName + ':' + tagName;
}
if(tagName.substr(0,5).toLowerCase() == "dojo:"){
return tagName.toLowerCase();
}
if(tagName.substr(0,4).toLowerCase() == "dojo"){
// FIXME: this assumes tag names are always lower case
return "dojo:" + tagName.substring(4).toLowerCase();
}
// allow lower-casing
var djt = node.getAttribute("dojoType") || node.getAttribute("dojotype");
if(djt){
if(djt.indexOf(":")<0){
djt = "dojo:"+djt;
}
return djt.toLowerCase();
}
if(node.getAttributeNS && node.getAttributeNS(dojo.dom.dojoml,"type")){
return "dojo:" + node.getAttributeNS(dojo.dom.dojoml,"type").toLowerCase();
}
try{
// FIXME: IE really really doesn't like this, so we squelch errors for it
djt = node.getAttribute("dojo:type");
}catch(e){ /* FIXME: log? */ }
if(djt){ return "dojo:"+djt.toLowerCase(); }
if(!dj_global["djConfig"] || !djConfig["ignoreClassNames"]){
// FIXME: should we make this optionally enabled via djConfig?
var classes = node.className||node.getAttribute("class");
// FIXME: following line, without check for existence of classes.indexOf
// breaks firefox 1.5's svg widgets
if(classes && classes.indexOf && classes.indexOf("dojo-") != -1){
var aclasses = classes.split (" ");
for(var x=0; x<aclasses.length; x++){
if(aclasses[x].length > 5 && aclasses[x].indexOf("dojo-") >= 0){
return "dojo:"+aclasses[x].substr(5).toLowerCase();
}
}
}
}
return tagName.toLowerCase();
}
this.parseElement = function(node, hasParentNodeSet, optimizeForDojoML, thisIdx){
var parsedNodeSet = {};
//There's a weird bug in IE where it counts end tags, e.g. </dojo:button> as nodes that should be parsed. Ignore these
if(node.tagName && node.tagName.indexOf("/") == 0){
return null;
}
var tagName = getDojoTagName(node);
parsedNodeSet[tagName] = [];
if(tagName.substr(0,4).toLowerCase()=="dojo"){
parsedNodeSet.namespace = "dojo";
}else{
var pos = tagName.indexOf(":");
if(pos > 0){
parsedNodeSet.namespace = tagName.substring(0,pos);
}
}
var process = false;
if(!optimizeForDojoML){process=true;}
else if(parsedNodeSet.namespace&&dojo.getNamespace(parsedNodeSet.namespace)){process=true;}
else if(dojo.widget.tags[tagName]){
dojo.deprecated('dojo.xml.Parse.parseElement', 'Widgets should be placed in a defined namespace', "0.5");
process = true;
}
if(process){
var attributeSet = this.parseAttributes(node);
for(var attr in attributeSet){
if((!parsedNodeSet[tagName][attr])||(typeof parsedNodeSet[tagName][attr] != "array")){
parsedNodeSet[tagName][attr] = [];
}
parsedNodeSet[tagName][attr].push(attributeSet[attr]);
}
// FIXME: we might want to make this optional or provide cloning instead of
// referencing, but for now, we include a node reference to allow
// instantiated components to figure out their "roots"
parsedNodeSet[tagName].nodeRef = node;
parsedNodeSet.tagName = tagName;
parsedNodeSet.index = thisIdx||0;
// dojo.debug("parseElement: set the element tagName = "+parsedNodeSet.tagName+" and namespace to "+parsedNodeSet.namespace);
}
var count = 0;
for(var i = 0; i < node.childNodes.length; i++){
var tcn = node.childNodes.item(i);
switch(tcn.nodeType){
case dojo.dom.ELEMENT_NODE: // element nodes, call this function recursively
count++;
var ctn = getDojoTagName(tcn);
if(!parsedNodeSet[ctn]){
parsedNodeSet[ctn] = [];
}
parsedNodeSet[ctn].push(this.parseElement(tcn, true, optimizeForDojoML, count));
if( (tcn.childNodes.length == 1)&&
(tcn.childNodes.item(0).nodeType == dojo.dom.TEXT_NODE)){
parsedNodeSet[ctn][parsedNodeSet[ctn].length-1].value = tcn.childNodes.item(0).nodeValue;
}
break;
case dojo.dom.TEXT_NODE: // if a single text node is the child, treat it as an attribute
if(node.childNodes.length == 1){
parsedNodeSet[tagName].push({ value: node.childNodes.item(0).nodeValue });
}
break;
default: break;
/*
case dojo.dom.ATTRIBUTE_NODE: // attribute node... not meaningful here
break;
case dojo.dom.CDATA_SECTION_NODE: // cdata section... not sure if this would ever be meaningful... might be...
break;
case dojo.dom.ENTITY_REFERENCE_NODE: // entity reference node... not meaningful here
break;
case dojo.dom.ENTITY_NODE: // entity node... not sure if this would ever be meaningful
break;
case dojo.dom.PROCESSING_INSTRUCTION_NODE: // processing instruction node... not meaningful here
break;
case dojo.dom.COMMENT_NODE: // comment node... not not sure if this would ever be meaningful
break;
case dojo.dom.DOCUMENT_NODE: // document node... not sure if this would ever be meaningful
break;
case dojo.dom.DOCUMENT_TYPE_NODE: // document type node... not meaningful here
break;
case dojo.dom.DOCUMENT_FRAGMENT_NODE: // document fragment node... not meaningful here
break;
case dojo.dom.NOTATION_NODE:// notation node... not meaningful here
break;
*/
}
}
//return (hasParentNodeSet) ? parsedNodeSet[node.tagName] : parsedNodeSet;
//if(parsedNodeSet.tagName)dojo.debug("parseElement: RETURNING NODE WITH TAGNAME "+parsedNodeSet.tagName);
return parsedNodeSet;
};
/* parses a set of attributes on a node into an object tree */
this.parseAttributes = function(node){
var parsedAttributeSet = {};
var atts = node.attributes;
// TODO: should we allow for duplicate attributes at this point...
// would any of the relevant dom implementations even allow this?
var attnode, i=0;
while((attnode=atts[i++])){
if((dojo.render.html.capable)&&(dojo.render.html.ie)){
if(!attnode){ continue; }
if( (typeof attnode == "object")&&
(typeof attnode.nodeValue == 'undefined')||
(attnode.nodeValue == null)||
(attnode.nodeValue == '')){
continue;
}
}
var nn = attnode.nodeName.split(":");
nn = (nn.length == 2) ? nn[1] : attnode.nodeName;
parsedAttributeSet[nn] = {
value: attnode.nodeValue
};
}
return parsedAttributeSet;
};
};
dojo.provide("dojo.lang.declare");
/*
* Creates a constructor: inherit and extend
*
* - inherits from "superclass(es)"
*
* "superclass" argument may be a Function, or an array of
* Functions.
*
* If "superclass" is an array, the first element is used
* as the prototypical ancestor and any following Functions
* become mixin ancestors.
*
* All "superclass(es)" must be Functions (not mere Objects).
*
* Using mixin ancestors provides a type of multiple
* inheritance. Mixin ancestors prototypical
* properties are copied to the subclass, and any
* inializater/constructor is invoked.
*
* - "props" are copied to the constructor prototype
*
* - name of the class ("className" argument) is stored in
* "declaredClass" property
*
* - An initializer function can be specified in the "init"
* argument, or by including a function called "initializer"
* in "props".
*
* - Superclass methods (inherited methods) can be invoked using "inherited" method:
*
* this.inherited(<method name>[, <argument array>]);
*
* - inherited will continue up the prototype chain until it finds an implementation of method
* - nested calls to inherited are supported (i.e. inherited method "A" can succesfully call inherited("A"), and so on)
*
* Aliased as "dojo.declare"
*
* Usage:
*
* dojo.declare("my.classes.bar", my.classes.foo, {
* initializer: function() {
* this.myComplicatedObject = new ReallyComplicatedObject();
* },
* someValue: 2,
* aMethod: function() { doStuff(); }
* });
*
*/
dojo.lang.declare = function(className /*string*/, superclass /*function || array*/, init /*function*/, props /*object*/){
// FIXME: parameter juggling for backward compat ... deprecate and remove after 0.3.*
// new sig: (className (string)[, superclass (function || array)[, init (function)][, props (object)]])
// old sig: (className (string)[, superclass (function || array), props (object), init (function)])
if ((dojo.lang.isFunction(props))||((!props)&&(!dojo.lang.isFunction(init)))){
var temp = props;
props = init;
init = temp;
}
var mixins = [ ];
if (dojo.lang.isArray(superclass)) {
mixins = superclass;
superclass = mixins.shift();
}
if(!init){
init = dojo.evalObjPath(className, false);
if ((init)&&(!dojo.lang.isFunction(init))){ init = null };
}
var ctor = dojo.lang.declare._makeConstructor();
var scp = (superclass ? superclass.prototype : null);
if(scp){
scp.prototyping = true;
ctor.prototype = new superclass();
scp.prototyping = false;
}
ctor.superclass = scp;
ctor.mixins = mixins;
for(var i=0,l=mixins.length; i<l; i++){
dojo.lang.extend(ctor, mixins[i].prototype);
}
ctor.prototype.initializer = null;
ctor.prototype.declaredClass = className;
if(dojo.lang.isArray(props)){
dojo.lang.extend.apply(dojo.lang, [ctor].concat(props));
}else{
dojo.lang.extend(ctor, (props)||{});
}
dojo.lang.extend(ctor, dojo.lang.declare.base);
ctor.prototype.constructor = ctor;
ctor.prototype.initializer=(ctor.prototype.initializer)||(init)||(function(){});
dojo.lang.setObjPathValue(className, ctor, null, true);
return ctor;
}
dojo.lang.declare._makeConstructor = function() {
return function(){
// get the generational context (which object [or prototype] should be constructed)
var self = this._getPropContext();
var s = self.constructor.superclass;
if((s)&&(s.constructor)){
if(s.constructor==arguments.callee){
// if this constructor is invoked directly (my.ancestor.call(this))
this.inherited("constructor", arguments);
}else{
this._inherited(s, "constructor", arguments);
}
}
var m = (self.constructor.mixins)||([]);
for(var i=0,l=m.length; i<l; i++) {
(((m[i].prototype)&&(m[i].prototype.initializer))||(m[i])).apply(this, arguments);
}
if((!this.prototyping)&&(self.initializer)){
self.initializer.apply(this, arguments);
}
}
}
dojo.lang.declare.base = {
_getPropContext: function() { return (this.___proto||this); },
// caches ptype context and calls method on it
_inherited: function(ptype, method, args){
var stack = this.___proto;
this.___proto = ptype;
var result = ptype[method].apply(this,(args||[]));
this.___proto = stack;
return result;
},
// invokes ctor.prototype.method, with args, in our context
inheritedFrom: function(ctor, prop, args){
var p = ((ctor)&&(ctor.prototype)&&(ctor.prototype[prop]));
return (dojo.lang.isFunction(p) ? p.apply(this, (args||[])) : p);
},
// searches backward thru prototype chain to find nearest ancestral instance of prop
inherited: function(prop, args){
var p = this._getPropContext();
do{
if((!p.constructor)||(!p.constructor.superclass)){return;}
p = p.constructor.superclass;
}while(!(prop in p));
return (dojo.lang.isFunction(p[prop]) ? this._inherited(p, prop, args) : p[prop]);
}
}
dojo.declare = dojo.lang.declare;
dojo.provide("dojo.widget.Manager");
// Manager class
dojo.widget.manager = new function(){
this.widgets = [];
this.widgetIds = [];
// map of widgetId-->widget for widgets without parents (top level widgets)
this.topWidgets = {};
var widgetTypeCtr = {};
var renderPrefixCache = [];
this.getUniqueId = function (widgetType) {
return widgetType + "_" + (widgetTypeCtr[widgetType] != undefined ?
++widgetTypeCtr[widgetType] : widgetTypeCtr[widgetType] = 0);
}
this.add = function(widget){
//dojo.profile.start("dojo.widget.manager.add");
this.widgets.push(widget);
// Opera9 uses ID (caps)
if(!widget.extraArgs["id"]){
widget.extraArgs["id"] = widget.extraArgs["ID"];
}
// FIXME: the rest of this method is very slow!
if(widget.widgetId == ""){
if(widget["id"]){
widget.widgetId = widget["id"];
}else if(widget.extraArgs["id"]){
widget.widgetId = widget.extraArgs["id"];
}else{
widget.widgetId = this.getUniqueId(widget.widgetType);
}
}
if(this.widgetIds[widget.widgetId]){
dojo.debug("widget ID collision on ID: "+widget.widgetId);
}
this.widgetIds[widget.widgetId] = widget;
// Widget.destroy already calls removeById(), so we don't need to
// connect() it here
//dojo.profile.end("dojo.widget.manager.add");
}
this.destroyAll = function(){
for(var x=this.widgets.length-1; x>=0; x--){
try{
// this.widgets[x].destroyChildren();
this.widgets[x].destroy(true);
delete this.widgets[x];
}catch(e){ }
}
}
// FIXME: we should never allow removal of the root widget until all others
// are removed!
this.remove = function(widgetIndex){
if(dojo.lang.isNumber(widgetIndex)){
var tw = this.widgets[widgetIndex].widgetId;
delete this.widgetIds[tw];
this.widgets.splice(widgetIndex, 1);
}else{
this.removeById(widgetIndex);
}
}
// FIXME: suboptimal performance
this.removeById = function(id) {
if(!dojo.lang.isString(id)){
id = id["widgetId"];
if(!id){ dojo.debug("invalid widget or id passed to removeById"); return; }
}
for (var i=0; i<this.widgets.length; i++){
if(this.widgets[i].widgetId == id){
this.remove(i);
break;
}
}
}
this.getWidgetById = function(id){
if(dojo.lang.isString(id)){
return this.widgetIds[id];
}
return id;
}
this.getWidgetsByType = function(type){
var lt = type.toLowerCase();
var ret = [];
dojo.lang.forEach(this.widgets, function(x){
if(x.widgetType.toLowerCase() == lt){
ret.push(x);
}
});
return ret;
}
this.getWidgetsByFilter = function(unaryFunc, onlyOne){
var ret = [];
dojo.lang.every(this.widgets, function(x){
if(unaryFunc(x)){
ret.push(x);
if(onlyOne){return false;}
}
return true;
});
return (onlyOne ? ret[0] : ret);
}
this.getAllWidgets = function() {
return this.widgets.concat();
}
// added, trt 2006-01-20
this.getWidgetByNode = function(/* DOMNode */ node){
var w=this.getAllWidgets();
node = dojo.byId(node);
for(var i=0; i<w.length; i++){
if(w[i].domNode==node){
return w[i];
}
}
return null;
}
// shortcuts, baby
this.byId = this.getWidgetById;
this.byType = this.getWidgetsByType;
this.byFilter = this.getWidgetsByFilter;
this.byNode = this.getWidgetByNode;
// map of previousally discovered implementation names to constructors
var knownWidgetImplementations = {};
// support manually registered widget packages
var widgetPackages = ["dojo.widget"];
for (var i=0; i<widgetPackages.length; i++) {
// convenience for checking if a package exists (reverse lookup)
widgetPackages[widgetPackages[i]] = true;
}
this.registerWidgetPackage = function(pname) {
if(!widgetPackages[pname]){
widgetPackages[pname] = true;
widgetPackages.push(pname);
}
}
this.getWidgetPackageList = function() {
return dojo.lang.map(widgetPackages, function(elt) { return(elt!==true ? elt : undefined); });
}
this.getImplementation = function(widgetName, ctorObject, mixins, namespace){
// try and find a name for the widget
var impl = this.getImplementationName(widgetName, namespace);
if(impl){
// var tic = new Date();
var ret;
if(ctorObject){ret = new impl(ctor);}
else{ret = new impl();}
// dojo.debug(new Date() - tic);
return ret;
}
}
this.getImplementationName = function(widgetName, namespace){
/*
* This is the overly-simplistic implemention of getImplementation (har
* har). In the future, we are going to want something that allows more
* freedom of expression WRT to specifying different specializations of
* a widget.
*
* Additionally, this implementation treats widget names as case
* insensitive, which does not necessarialy mesh with the markup which
* can construct a widget.
*/
if(!namespace){namespace="dojo";}
var lowerCaseWidgetName = widgetName.toLowerCase();
if(!knownWidgetImplementations[namespace]){knownWidgetImplementations[namespace]={};}
var impl = knownWidgetImplementations[namespace][lowerCaseWidgetName];
if(impl){
return impl;
}
var ns = dojo.getNamespace(namespace);
if(ns){ns.load(widgetName);}
// first store a list of the render prefixes we are capable of rendering
if(!renderPrefixCache.length){
for(var renderer in dojo.render){
if(dojo.render[renderer]["capable"] === true){
var prefixes = dojo.render[renderer].prefixes;
for(var i = 0; i < prefixes.length; i++){
renderPrefixCache.push(prefixes[i].toLowerCase());
}
}
}
// make sure we don't HAVE to prefix widget implementation names
// with anything to get them to render
renderPrefixCache.push("");
}
var nsSearchArr = null;
var deprWarningLogged=false;
for(var counter = 0; counter < 2; counter++){
// look for a rendering-context specific version of our widget name
for(var i = 0; i < widgetPackages.length; i++){
var widgetPackage = dojo.evalObjPath(widgetPackages[i]);
if(!widgetPackage) { continue; }
var pos = widgetPackages[i].indexOf(".");
if(pos > -1){
var n = widgetPackages[i].substring(0,pos);
if(n != namespace){
if(counter==0){continue;}
if(!deprWarningLogged){
deprWarningLogged = true;
dojo.deprecated('dojo.widget.Manager.getImplementationName', 'Wrong namespace ('+namespace+
') specified. Developers should specify correct namespaces for all non-Dojo widgets', "0.5");
}
}
}
for (var j = 0; j < renderPrefixCache.length; j++) {
if (!widgetPackage[renderPrefixCache[j]]) { continue; }
for (var widgetClass in widgetPackage[renderPrefixCache[j]]) {
if (widgetClass.toLowerCase() != lowerCaseWidgetName) { continue; }
knownWidgetImplementations[namespace][lowerCaseWidgetName] =
widgetPackage[renderPrefixCache[j]][widgetClass];
return knownWidgetImplementations[namespace][lowerCaseWidgetName];
}
}
for (var j = 0; j < renderPrefixCache.length; j++) {
for (var widgetClass in widgetPackage) {
if (widgetClass.toLowerCase() != (renderPrefixCache[j] + lowerCaseWidgetName) &&
widgetClass.toLowerCase() != lowerCaseWidgetName) { continue; }
knownWidgetImplementations[namespace][lowerCaseWidgetName] =
widgetPackage[widgetClass];
return knownWidgetImplementations[namespace][lowerCaseWidgetName];
}
}
}
var newNs = dojo.findNamespaceForWidget(lowerCaseWidgetName);
if(newNs){
namespace = newNs.nsPrefix;
}
}
throw new Error('Could not locate "' + widgetName + '" class');
}
// FIXME: does it even belong in this name space?
// NOTE: this method is implemented by DomWidget.js since not all
// hostenv's would have an implementation.
/*this.getWidgetFromPrimitive = function(baseRenderType){
dojo.unimplemented("dojo.widget.manager.getWidgetFromPrimitive");
}
this.getWidgetFromEvent = function(nativeEvt){
dojo.unimplemented("dojo.widget.manager.getWidgetFromEvent");
}*/
// Catch window resize events and notify top level widgets
this.resizing=false;
this.onWindowResized = function(){
if(this.resizing){
return; // duplicate event
}
try{
this.resizing=true;
for(var id in this.topWidgets){
var child = this.topWidgets[id];
if(child.checkSize ){
child.checkSize();
}
}
}catch(e){
}finally{
this.resizing=false;
}
}
if(typeof window != "undefined") {
dojo.addOnLoad(this, 'onWindowResized'); // initial sizing
dojo.event.connect(window, 'onresize', this, 'onWindowResized'); // window resize
}
// FIXME: what else?
};
(function(){
var dw = dojo.widget;
var dwm = dw.manager;
var h = dojo.lang.curry(dojo.lang, "hitch", dwm);
var g = function(oldName, newName){
dw[(newName||oldName)] = h(oldName);
}
// copy the methods from the default manager (this) to the widget namespace
g("add", "addWidget");
g("destroyAll", "destroyAllWidgets");
g("remove", "removeWidget");
g("removeById", "removeWidgetById");
g("getWidgetById");
g("getWidgetById", "byId");
g("getWidgetsByType");
g("getWidgetsByFilter");
g("getWidgetsByType", "byType");
g("getWidgetsByFilter", "byFilter");
g("getWidgetByNode", "byNode");
dw.all = function(n){
var widgets = dwm.getAllWidgets.apply(dwm, arguments);
if(arguments.length > 0) {
return widgets[n];
}
return widgets;
}
g("registerWidgetPackage");
g("getImplementation", "getWidgetImplementation");
g("getImplementationName", "getWidgetImplementationName");
dw.widgets = dwm.widgets;
dw.widgetIds = dwm.widgetIds;
dw.root = dwm.root;
})();
dojo.provide("dojo.widget.Widget");
dojo.provide("dojo.widget.tags");
dojo.declare("dojo.widget.Widget", null,
function() {
//dojo.debug("NEW "+this.widgetType);
// these properties aren't primitives and need to be created on a per-item
// basis.
this.children = [];
// this.selection = new dojo.widget.Selection();
// FIXME: need to replace this with context menu stuff
this.extraArgs = {};
},
{
// FIXME: need to be able to disambiguate what our rendering context is
// here!
//
// needs to be a string with the end classname. Every subclass MUST
// over-ride.
//
// base widget properties
parent: null,
// obviously, top-level and modal widgets should set these appropriately
isTopLevel: false,
isModal: false,
isEnabled: true,
isHidden: false,
isContainer: false, // can we contain other widgets?
widgetId: "",
widgetType: "Widget", // used for building generic widgets
namespace: "dojo", //defaults to 'dojo'
toString: function() {
return '[Widget ' + this.widgetType + ', ' + (this.widgetId || 'NO ID') + ']'; // string
},
repr: function(){
return this.toString();
},
enable: function(){
// should be over-ridden
this.isEnabled = true;
},
disable: function(){
// should be over-ridden
this.isEnabled = false;
},
hide: function(){
// should be over-ridden
this.isHidden = true;
},
show: function(){
// should be over-ridden
this.isHidden = false;
},
onResized: function(){
// Clients should override this function to do special processing,
// then call this.notifyChildrenOfResize() to notify children of resize
this.notifyChildrenOfResize();
},
notifyChildrenOfResize: function(){
for(var i=0; i<this.children.length; i++){
var child = this.children[i];
//dojo.debug(this.widgetId + " resizing child " + child.widgetId);
if( child.onResized ){
child.onResized();
}
}
},
create: function(args, fragment, parentComp, namespace){
//dojo.profile.start(this.widgetType + " create");
if(namespace){
this.namespace = namespace;
}
// dojo.debug(this.widgetType, "create");
//dojo.profile.start(this.widgetType + " satisfyPropertySets");
this.satisfyPropertySets(args, fragment, parentComp);
//dojo.profile.end(this.widgetType + " satisfyPropertySets");
// dojo.debug(this.widgetType, "-> mixInProperties");
//dojo.profile.start(this.widgetType + " mixInProperties");
this.mixInProperties(args, fragment, parentComp);
//dojo.profile.end(this.widgetType + " mixInProperties");
// dojo.debug(this.widgetType, "-> postMixInProperties");
//dojo.profile.start(this.widgetType + " postMixInProperties");
this.postMixInProperties(args, fragment, parentComp);
//dojo.profile.end(this.widgetType + " postMixInProperties");
// dojo.debug(this.widgetType, "-> dojo.widget.manager.add");
dojo.widget.manager.add(this);
// dojo.debug(this.widgetType, "-> buildRendering");
//dojo.profile.start(this.widgetType + " buildRendering");
this.buildRendering(args, fragment, parentComp);
//dojo.profile.end(this.widgetType + " buildRendering");
// dojo.debug(this.widgetType, "-> initialize");
//dojo.profile.start(this.widgetType + " initialize");
this.initialize(args, fragment, parentComp);
//dojo.profile.end(this.widgetType + " initialize");
// dojo.debug(this.widgetType, "-> postInitialize");
// postinitialize includes subcomponent creation
// profile is put directly to function
this.postInitialize(args, fragment, parentComp);
// dojo.debug(this.widgetType, "-> postCreate");
//dojo.profile.start(this.widgetType + " postCreate");
this.postCreate(args, fragment, parentComp);
//dojo.profile.end(this.widgetType + " postCreate");
// dojo.debug(this.widgetType, "done!");
//dojo.profile.end(this.widgetType + " create");
return this;
},
// Destroy this widget and it's descendants
destroy: function(finalize){
// FIXME: this is woefully incomplete
this.destroyChildren();
this.uninitialize();
this.destroyRendering(finalize);
dojo.widget.manager.removeById(this.widgetId);
},
// Destroy the children of this widget, and their descendents
destroyChildren: function(){
while(this.children.length > 0){
var tc = this.children[0];
this.removeChild(tc);
tc.destroy();
}
},
getChildrenOfType: function(type, recurse){
var ret = [];
var isFunc = dojo.lang.isFunction(type);
if(!isFunc){
type = type.toLowerCase();
}
for(var x=0; x<this.children.length; x++){
if(isFunc){
if(this.children[x] instanceof type){
ret.push(this.children[x]);
}
}else{
if(this.children[x].widgetType.toLowerCase() == type){
ret.push(this.children[x]);
}
}
if(recurse){
ret = ret.concat(this.children[x].getChildrenOfType(type, recurse));
}
}
return ret;
},
getDescendants: function(){
var result = [];
var stack = [this];
var elem;
while ((elem = stack.pop())){
result.push(elem);
// a child may be data object without children field set (not widget)
if (elem.children) {
dojo.lang.forEach(elem.children, function(elem) { stack.push(elem); });
}
}
return result;
},
isFirstNode: function() {
return this === this.parent.children[0];
},
isLastNode: function() {
return this === this.parent.children[this.parent.children.length-1];
},
satisfyPropertySets: function(args){
// dojo.profile.start("satisfyPropertySets");
// get the default propsets for our component type
/*
var typePropSets = []; // FIXME: need to pull these from somewhere!
var localPropSets = []; // pull out propsets from the parser's return structure
// for(var x=0; x<args.length; x++){
// }
for(var x=0; x<typePropSets.length; x++){
}
for(var x=0; x<localPropSets.length; x++){
}
*/
// dojo.profile.end("satisfyPropertySets");
return args;
},
mixInProperties: function(args, frag){
if((args["fastMixIn"])||(frag["fastMixIn"])){
// dojo.profile.start("mixInProperties_fastMixIn");
// fast mix in assumes case sensitivity, no type casting, etc...
// dojo.lang.mixin(this, args);
for(var x in args){
this[x] = args[x];
}
// dojo.profile.end("mixInProperties_fastMixIn");
return;
}
// dojo.profile.start("mixInProperties");
/*
* the actual mix-in code attempts to do some type-assignment based on
* PRE-EXISTING properties of the "this" object. When a named property
* of a propset is located, it is first tested to make sure that the
* current object already "has one". Properties which are undefined in
* the base widget are NOT settable here. The next step is to try to
* determine type of the pre-existing property. If it's a string, the
* property value is simply assigned. If a function, the property is
* replaced with a "new Function()" declaration. If an Array, the
* system attempts to split the string value on ";" chars, and no
* further processing is attempted (conversion of array elements to a
* integers, for instance). If the property value is an Object
* (testObj.constructor === Object), the property is split first on ";"
* chars, secondly on ":" chars, and the resulting key/value pairs are
* assigned to an object in a map style. The onus is on the property
* user to ensure that all property values are converted to the
* expected type before usage.
*/
var undef;
// NOTE: we cannot assume that the passed properties are case-correct
// (esp due to some browser bugs). Therefore, we attempt to locate
// properties for assignment regardless of case. This may cause
// problematic assignments and bugs in the future and will need to be
// documented with big bright neon lights.
// FIXME: fails miserably if a mixin property has a default value of null in
// a widget
// NOTE: caching lower-cased args in the prototype is only
// acceptable if the properties are invariant.
// if we have a name-cache, get it
var lcArgs = dojo.widget.lcArgsCache[this.widgetType];
if ( lcArgs == null ){
// build a lower-case property name cache if we don't have one
lcArgs = {};
for(var y in this){
lcArgs[((new String(y)).toLowerCase())] = y;
}
dojo.widget.lcArgsCache[this.widgetType] = lcArgs;
}
var visited = {};
for(var x in args){
if(!this[x]){ // check the cache for properties
var y = lcArgs[(new String(x)).toLowerCase()];
if(y){
args[y] = args[x];
x = y;
}
}
if(visited[x]){ continue; }
visited[x] = true;
if((typeof this[x]) != (typeof undef)){
if(typeof args[x] != "string"){
this[x] = args[x];
}else{
if(dojo.lang.isString(this[x])){
this[x] = args[x];
}else if(dojo.lang.isNumber(this[x])){
this[x] = new Number(args[x]); // FIXME: what if NaN is the result?
}else if(dojo.lang.isBoolean(this[x])){
this[x] = (args[x].toLowerCase()=="false") ? false : true;
}else if(dojo.lang.isFunction(this[x])){
// FIXME: need to determine if always over-writing instead
// of attaching here is appropriate. I suspect that we
// might want to only allow attaching w/ action items.
// RAR, 1/19/05: I'm going to attach instead of
// over-write here. Perhaps function objects could have
// some sort of flag set on them? Or mixed-into objects
// could have some list of non-mutable properties
// (although I'm not sure how that would alleviate this
// particular problem)?
// this[x] = new Function(args[x]);
// after an IRC discussion last week, it was decided
// that these event handlers should execute in the
// context of the widget, so that the "this" pointer
// takes correctly.
// argument that contains no punctuation other than . is
// considered a function spec, not code
if(args[x].search(/[^\w\.]+/i) == -1){
this[x] = dojo.evalObjPath(args[x], false);
}else{
var tn = dojo.lang.nameAnonFunc(new Function(args[x]), this);
dojo.event.connect(this, x, this, tn);
}
}else if(dojo.lang.isArray(this[x])){ // typeof [] == "object"
this[x] = args[x].split(";");
} else if (this[x] instanceof Date) {
this[x] = new Date(Number(args[x])); // assume timestamp
}else if(typeof this[x] == "object"){
// FIXME: should we be allowing extension here to handle
// other object types intelligently?
// if we defined a URI, we probably want to allow plain strings
// to override it
if (this[x] instanceof dojo.uri.Uri){
this[x] = args[x];
}else{
// FIXME: unlike all other types, we do not replace the
// object with a new one here. Should we change that?
var pairs = args[x].split(";");
for(var y=0; y<pairs.length; y++){
var si = pairs[y].indexOf(":");
if((si != -1)&&(pairs[y].length>si)){
this[x][pairs[y].substr(0, si).replace(/^\s+|\s+$/g, "")] = pairs[y].substr(si+1);
}
}
}
}else{
// the default is straight-up string assignment. When would
// we ever hit this?
this[x] = args[x];
}
}
}else{
// collect any extra 'non mixed in' args
this.extraArgs[x.toLowerCase()] = args[x];
}
}
// dojo.profile.end("mixInProperties");
},
postMixInProperties: function(){
},
initialize: function(args, frag){
// dojo.unimplemented("dojo.widget.Widget.initialize");
return false;
},
postInitialize: function(args, frag){
return false;
},
postCreate: function(args, frag){
return false;
},
uninitialize: function(){
// dojo.unimplemented("dojo.widget.Widget.uninitialize");
return false;
},
buildRendering: function(){
// SUBCLASSES MUST IMPLEMENT
dojo.unimplemented("dojo.widget.Widget.buildRendering, on "+this.toString()+", ");
return false;
},
destroyRendering: function(){
// SUBCLASSES MUST IMPLEMENT
dojo.unimplemented("dojo.widget.Widget.destroyRendering");
return false;
},
cleanUp: function(){
// SUBCLASSES MUST IMPLEMENT
dojo.unimplemented("dojo.widget.Widget.cleanUp");
return false;
},
addedTo: function(parent){
// this is just a signal that can be caught
},
addChild: function(child){
// SUBCLASSES MUST IMPLEMENT
dojo.unimplemented("dojo.widget.Widget.addChild");
return false;
},
// Detach the given child widget from me, but don't destroy it
removeChild: function(widget){
for(var x=0; x<this.children.length; x++){
if(this.children[x] === widget){
this.children.splice(x, 1);
break;
}
}
return widget;
},
resize: function(width, height){
// both width and height may be set as percentages. The setWidth and
// setHeight functions attempt to determine if the passed param is
// specified in percentage or native units. Integers without a
// measurement are assumed to be in the native unit of measure.
this.setWidth(width);
this.setHeight(height);
},
setWidth: function(width){
if((typeof width == "string")&&(width.substr(-1) == "%")){
this.setPercentageWidth(width);
}else{
this.setNativeWidth(width);
}
},
setHeight: function(height){
if((typeof height == "string")&&(height.substr(-1) == "%")){
this.setPercentageHeight(height);
}else{
this.setNativeHeight(height);
}
},
setPercentageHeight: function(height){
// SUBCLASSES MUST IMPLEMENT
return false;
},
setNativeHeight: function(height){
// SUBCLASSES MUST IMPLEMENT
return false;
},
setPercentageWidth: function(width){
// SUBCLASSES MUST IMPLEMENT
return false;
},
setNativeWidth: function(width){
// SUBCLASSES MUST IMPLEMENT
return false;
},
getPreviousSibling: function() {
var idx = this.getParentIndex();
// first node is idx=0 not found is idx<0
if (idx<=0) return null;
return this.parent.children[idx-1];
},
getSiblings: function() {
return this.parent.children;
},
getParentIndex: function() {
return dojo.lang.indexOf( this.parent.children, this, true);
},
getNextSibling: function() {
var idx = this.getParentIndex();
if (idx == this.parent.children.length-1) return null; // last node
if (idx < 0) return null; // not found
return this.parent.children[idx+1];
}
});
// Lower case name cache: listing of the lower case elements in each widget.
// We can't store the lcArgs in the widget itself because if B subclasses A,
// then B.prototype.lcArgs might return A.prototype.lcArgs, which is not what we
// want
dojo.widget.lcArgsCache = {};
// TODO: should have a more general way to add tags or tag libraries?
// TODO: need a default tags class to inherit from for things like getting propertySets
// TODO: parse properties/propertySets into component attributes
// TODO: parse subcomponents
// TODO: copy/clone raw markup fragments/nodes as appropriate
dojo.widget.tags = {};
dojo.widget.tags.addParseTreeHandler = function(type){
var ltype = type.toLowerCase();
this[ltype] = function(fragment, widgetParser, parentComp, insertionIndex, localProps){
var _ltype = ltype;
dojo.profile.start(_ltype);
var n = dojo.widget.buildWidgetFromParseTree(ltype, fragment, widgetParser, parentComp, insertionIndex, localProps);
dojo.profile.end(_ltype);
return n;
}
}
dojo.widget.tags.addParseTreeHandler("dojo:widget");
dojo.widget.tags["dojo:propertyset"] = function(fragment, widgetParser, parentComp){
// FIXME: Is this needed?
// FIXME: Not sure that this parses into the structure that I want it to parse into...
// FIXME: add support for nested propertySets
var properties = widgetParser.parseProperties(fragment["dojo:propertyset"]);
}
// FIXME: need to add the <dojo:connect />
dojo.widget.tags["dojo:connect"] = function(fragment, widgetParser, parentComp){
var properties = widgetParser.parseProperties(fragment["dojo:connect"]);
}
// FIXME: if we know the insertion point (to a reasonable location), why then do we:
// - create a template node
// - clone the template node
// - render the clone and set properties
// - remove the clone from the render tree
// - place the clone
// this is quite dumb
dojo.widget.buildWidgetFromParseTree = function(type, frag,
parser, parentComp,
insertionIndex, localProps){
//dojo.profile.start("buildWidgetFromParseTree");
var stype = type.split(":");
stype = (stype.length == 2) ? stype[1] : type;
// FIXME: we don't seem to be doing anything with this!
// var propertySets = parser.getPropertySets(frag);
var localProperties = localProps || parser.parseProperties(frag[frag.namespace+":"+stype]);
// var tic = new Date();
var twidget = dojo.widget.manager.getImplementation(stype,null,null,frag.namespace);
if(!twidget){
throw new Error("cannot find \"" + stype + "\" widget");
}else if (!twidget.create){
throw new Error("\"" + stype + "\" widget object does not appear to implement *Widget");
}
localProperties["dojoinsertionindex"] = insertionIndex;
// FIXME: we lose no less than 5ms in construction!
var ret = twidget.create(localProperties, frag, parentComp, frag.namespace);
// dojo.debug(new Date() - tic);
//dojo.profile.end("buildWidgetFromParseTree");
return ret;
}
/*
* Create a widget constructor function (aka widgetClass)
*/
dojo.widget.defineWidget = function(widgetClass /*string*/, renderer /*string*/, superclasses /*function||array*/, init /*function*/, props /*object*/){
// This meta-function does parameter juggling for backward compat and overloading
// if 4th argument is a string, we are using the old syntax
// old sig: widgetClass, superclasses, props (object), renderer (string), init (function)
if(dojo.lang.isString(arguments[3])){
dojo.widget._defineWidget(arguments[0], arguments[3], arguments[1], arguments[4], arguments[2]);
}else{
// widgetClass
var args = [ arguments[0] ], p = 3;
if(dojo.lang.isString(arguments[1])){
// renderer, superclass
args.push(arguments[1], arguments[2]);
}else{
// superclass
args.push('', arguments[1]);
p = 2;
}
if(dojo.lang.isFunction(arguments[p])){
// init (function), props (object)
args.push(arguments[p], arguments[p+1]);
}else{
// props (object)
args.push(null, arguments[p]);
}
dojo.widget._defineWidget.apply(this, args);
}
}
dojo.widget.defineWidget.renderers = "html|svg|vml";
dojo.widget._defineWidget = function(widgetClass /*string*/, renderer /*string*/, superclasses /*function||array*/, init /*function*/, props /*object*/){
// FIXME: uncomment next line to test parameter juggling ... remove when confidence improves
//dojo.debug('(c:)' + widgetClass + '\n\n(r:)' + renderer + '\n\n(i:)' + init + '\n\n(p:)' + props);
// widgetClass takes the form foo.bar.baz<.renderer>.WidgetName (e.g. foo.bar.baz.WidgetName or foo.bar.baz.html.WidgetName)
var namespace = widgetClass.split(".");
var type = namespace.pop(); // type <= WidgetName, namespace <= foo.bar.baz<.renderer>
var regx = "\\.(" + (renderer ? renderer + '|' : '') + dojo.widget.defineWidget.renderers + ")\\.";
var r = widgetClass.search(new RegExp(regx));
namespace = (r < 0 ? namespace.join(".") : widgetClass.substr(0, r));
dojo.widget.manager.registerWidgetPackage(namespace);
var pos = namespace.indexOf(".");
var nsName = (pos > -1) ? namespace.substring(0,pos) : namespace;
dojo.widget.tags.addParseTreeHandler(nsName+":"+type.toLowerCase());
if(nsName != "dojo"){
// 2006/06/26 Providing a duplicate dojo handler is a deprecation
// and should eventually be removed from code
dojo.widget.tags.addParseTreeHandler("dojo:"+type.toLowerCase());
}
props=(props)||{};
props.widgetType = type;
if((!init)&&(props["classConstructor"])){
init = props.classConstructor;
delete props.classConstructor;
}
dojo.declare(widgetClass, superclasses, init, props);
}
dojo.provide("dojo.namespace");
//Every namespace that is defined using the dojo.defineNamespace method has one of these Namespace objects created.
//It stores the fully qualified namespace name, it's location relative to the dojo root, the short namespace name, and a
//resolver function that maps a widget's short name to it's fully qualified name
dojo.Namespace = function(objRoot, location, nsPrefix, resolver){
this.root = objRoot;
this.location = location;
this.nsPrefix = nsPrefix;
this.resolver = resolver;
dojo.setModulePrefix(nsPrefix, location);
};
dojo.Namespace.prototype._loaded = {};
dojo.Namespace.prototype.load = function(name, domain){
if(this.resolver){
var fullName = this.resolver(name,domain);
//only load a widget once. This is a quicker check than dojo.require does
if(fullName && !this._loaded[fullName]){
//workaround so we don't break the build system
var req = dojo.require;
req(fullName);
this._loaded[fullName] = true;
}
if(this._loaded[fullName]){
return true;
}
}
return false;
};
//This function is used to define a new namespace.
//objRoot is the fully qualified namespace name
//location is the file system location relative to the dojo root, e.g. "../myNewNamespace"
//nsPrefix is the short name of the namespace. e.g. for the namespace " my.new.namespace", the nsPrefix could be "mnn"
//resolver is a function that takes two parameters:
// 1. a short name of a widget and returns it's fully qualified name. For example if passed "checkbox", it could return " dojo.widget.CheckBox"
// 2. the widget domain, e.g. "html", "svg", "vml" etc. This is optional, and depends on what the particular widget set supports. Dojo defaults to "html"
// resolver is optional, as it only applies to widgets, and a namespace may have no widgets
//widgetPackage the name of a widget package. e.g. if you had a namespace with nsPrefix = "mnn", and your widgets were in a
// "widget" folder in that namespace, your widget package would be "mnn.widget". This is optional, like the resolver
dojo.defineNamespace = function(objRoot, location, nsPrefix, resolver /*optional*/, widgetPackage /*optional*/){
// dojo.debug("dojo.defineNamespace('"+objRoot+"','"+location+"','"+nsPrefix+"',resolver) called");
if(dojo._namespaces[objRoot]){
return;
}
var ns = new dojo.Namespace(objRoot, location, nsPrefix, resolver);
dojo._namespaces[objRoot] = ns;
if(nsPrefix){
dojo._namespaces[nsPrefix] = ns;
}
if(widgetPackage){
dojo.widget.manager.registerWidgetPackage(widgetPackage);
}
};
dojo.findNamespaceForWidget = function(widgetName){
dojo.deprecated('dojo.findNamespaceForWidget', 'Widget [' + widgetName + '] not defined for a namespace'+
', so searching all namespaces. Developers should specify namespaces for all non-Dojo widgets', "0.5");
widgetName = widgetName.toLowerCase();
for(x in dojo._namespaces){
if(dojo._namespaces[x].load(widgetName)){
return dojo._namespaces[x];
}
}
};
dojo.provide("dojo.widget.Parse");
dojo.widget.Parse = function(fragment){
this.propertySetsList = [];
this.fragment = fragment;
this.createComponents = function(frag, parentComp){
var comps = [];
var built = false;
// if we have items to parse/create at this level, do it!
try{
if((frag)&&(frag["tagName"])&&(frag!=frag["nodeRef"])){
var djTags = dojo.widget.tags;
// we split so that you can declare multiple
// non-destructive widgets from the same ctor node
var tna = String(frag["tagName"]).split(";");
for(var x=0; x<tna.length; x++){
var ltn = (tna[x].replace(/^\s+|\s+$/g, "")).toLowerCase();
var pos = ltn.indexOf(":");
var nsName = (pos > 0) ? ltn.substring(0,pos) : null;
//if we don't already have a tag registered for this widget, try to load it's
//namespace, if it has one
if(!djTags[ltn] && dojo.getNamespace && dojo.lang.isString(ltn) && pos>0){
var ns = dojo.getNamespace(nsName);
var tagName = ltn.substring(pos+1,ltn.length);
var domain = null;
var dojoDomain = frag[ltn]["dojoDomain"] || frag[ltn]["dojodomain"];
if(dojoDomain){
domain = dojoDomain[0].value;
}
if(ns){
ns.load(tagName, domain);
}
}
if(!djTags[ltn]){
dojo.deprecated('dojo.widget.Parse.createComponents', 'Widget not defined for namespace'+nsName+
', so searching all namespaces. Developers should specify namespaces for all non-Dojo widgets', "0.5");
var newNs = dojo.findNamespaceForWidget(tagName);
if(newNs){
ltn = newNs.nsPrefix + ":" + (ltn.indexOf(":")> 0 ? ltn.substring(ltn.indexOf(":")+1) : ltn);
}
}
if(djTags[ltn]){
built = true;
frag.tagName = ltn;
var ret = djTags[ltn](frag, this, parentComp, frag["index"]);
comps.push(ret);
}else{
if(dojo.lang.isString(ltn) && nsName && dojo._namespaces[nsName]){
dojo.debug("no tag handler registered for type: ", ltn);
}
}
}
}
}catch(e){
dojo.debug("dojo.widget.Parse: error:", e);
// throw e;
// IE is such a bitch sometimes
}
// if there's a sub-frag, build widgets from that too
if(!built){
comps = comps.concat(this.createSubComponents(frag, parentComp));
}
return comps;
}
/* createSubComponents recurses over a raw JavaScript object structure,
and calls the corresponding handler for its normalized tagName if it exists
*/
this.createSubComponents = function(fragment, parentComp){
var frag, comps = [];
for(var item in fragment){
frag = fragment[item];
if ((frag)&&(typeof frag == "object")&&(frag!=fragment.nodeRef)&&(frag!=fragment["tagName"])){
comps = comps.concat(this.createComponents(frag, parentComp));
}
}
return comps;
}
/* parsePropertySets checks the top level of a raw JavaScript object
structure for any propertySets. It stores an array of references to
propertySets that it finds.
*/
this.parsePropertySets = function(fragment){
return [];
var propertySets = [];
for(var item in fragment){
if((fragment[item]["tagName"] == "dojo:propertyset")){
propertySets.push(fragment[item]);
}
}
// FIXME: should we store these propertySets somewhere for later retrieval
this.propertySetsList.push(propertySets);
return propertySets;
}
/* parseProperties checks a raw JavaScript object structure for
properties, and returns an array of properties that it finds.
*/
this.parseProperties = function(fragment){
var properties = {};
for(var item in fragment){
// FIXME: need to check for undefined?
// case: its a tagName or nodeRef
if((fragment[item] == fragment["tagName"])||
(fragment[item] == fragment.nodeRef)){
// do nothing
}else{
if((fragment[item]["tagName"])&&
(dojo.widget.tags[fragment[item].tagName.toLowerCase()])){
// TODO: it isn't a property or property set, it's a fragment,
// so do something else
// FIXME: needs to be a better/stricter check
// TODO: handle xlink:href for external property sets
}else if((fragment[item][0])&&(fragment[item][0].value!="")&&(fragment[item][0].value!=null)){
try{
// FIXME: need to allow more than one provider
if(item.toLowerCase() == "dataprovider") {
var _this = this;
this.getDataProvider(_this, fragment[item][0].value);
properties.dataProvider = this.dataProvider;
}
properties[item] = fragment[item][0].value;
var nestedProperties = this.parseProperties(fragment[item]);
// FIXME: this kind of copying is expensive and inefficient!
for(var property in nestedProperties){
properties[property] = nestedProperties[property];
}
}catch(e){ dojo.debug(e); }
}
}
}
return properties;
}
/* getPropertySetById returns the propertySet that matches the provided id
*/
this.getDataProvider = function(objRef, dataUrl){
// FIXME: this is currently sync. To make this async, we made need to move
//this step into the widget ctor, so that it is loaded when it is needed
// to populate the widget
dojo.io.bind({
url: dataUrl,
load: function(type, evaldObj){
if(type=="load"){
objRef.dataProvider = evaldObj;
}
},
mimetype: "text/javascript",
sync: true
});
}
this.getPropertySetById = function(propertySetId){
for(var x = 0; x < this.propertySetsList.length; x++){
if(propertySetId == this.propertySetsList[x]["id"][0].value){
return this.propertySetsList[x];
}
}
return "";
}
/* getPropertySetsByType returns the propertySet(s) that match(es) the
* provided componentClass
*/
this.getPropertySetsByType = function(componentType){
var propertySets = [];
for(var x=0; x < this.propertySetsList.length; x++){
var cpl = this.propertySetsList[x];
var cpcc = cpl["componentClass"]||cpl["componentType"]||null;
var propertySetId = this.propertySetsList[x]["id"][0].value;
if((cpcc)&&(propertySetId == cpcc[0].value)){
propertySets.push(cpl);
}
}
return propertySets;
}
/* getPropertySets returns the propertySet for a given component fragment
*/
this.getPropertySets = function(fragment){
var ppl = "dojo:propertyproviderlist";
var propertySets = [];
var tagname = fragment["tagName"];
if(fragment[ppl]){
var propertyProviderIds = fragment[ppl].value.split(" ");
// FIXME: should the propertyProviderList attribute contain #
// syntax for reference to ids or not?
// FIXME: need a better test to see if this is local or external
// FIXME: doesn't handle nested propertySets, or propertySets that
// just contain information about css documents, etc.
for(var propertySetId in propertyProviderIds){
if((propertySetId.indexOf("..")==-1)&&(propertySetId.indexOf("://")==-1)){
// get a reference to a propertySet within the current parsed structure
var propertySet = this.getPropertySetById(propertySetId);
if(propertySet != ""){
propertySets.push(propertySet);
}
}else{
// FIXME: add code to parse and return a propertySet from
// another document
// alex: is this even necessaray? Do we care? If so, why?
}
}
}
// we put the typed ones first so that the parsed ones override when
// iteration happens.
return (this.getPropertySetsByType(tagname)).concat(propertySets);
}
/*
nodeRef is the node to be replaced... in the future, we might want to add
an alternative way to specify an insertion point
componentName is the expected dojo widget name, i.e. Button of ContextMenu
properties is an object of name value pairs
namespace is the namespace of the widget. Defaults to "dojo"
*/
this.createComponentFromScript = function(nodeRef, componentName, properties, namespace){
if(!namespace){ namespace = "dojo"; }
var ltn = namespace + ":" + componentName.toLowerCase();
var djTags = dojo.widget.tags;
//if we don't already have a tag registered for this widget, try to load it's
//namespace, if it has one
if(!djTags[ltn] && dojo.getNamespace && dojo.lang.isString(ltn)){
var ns = dojo.getNamespace(namespace);
if(ns){ns.load(componentName);}
}
if(!djTags[ltn]){
dojo.deprecated('dojo.widget.Parse.createComponentFromScript', 'Widget not defined for namespace'+
namespace +
', so searching all namespaces. Developers should specify namespaces for all non-Dojo widgets', "0.5");
var newNs = dojo.findNamespaceForWidget(componentName.toLowerCase());
if(newNs){
var newLtn = newNs.nsPrefix + ":"+(ltn.indexOf(":")> 0 ? ltn.substring(ltn.indexOf(":")+1) : ltn);
properties[newLtn]=properties[ltn];
properties.namespace = newNs.nsPrefix;
ltn = newLtn;
}
}
if(djTags[ltn]){
properties.fastMixIn = true;
//dojo.profile.start("dojo.widget.tags - "+ltn);
//var ret = [dojo.widget.tags[ltn](properties, this, null, null, properties)];
var ret = [dojo.widget.buildWidgetFromParseTree(ltn, properties, this, null, null, properties)];
//dojo.profile.end("dojo.widget.tags - "+ltn);
return ret;
}else{
dojo.debug("no tag handler registered for type: ", ltn);
}
}
}
dojo.widget._parser_collection = {"dojo": new dojo.widget.Parse() };
dojo.widget.getParser = function(name){
if(!name){ name = "dojo"; }
if(!this._parser_collection[name]){
this._parser_collection[name] = new dojo.widget.Parse();
}
return this._parser_collection[name];
}
/**
* Creates widget.
*
* @param name The name of the widget to create with optional namespace prefix,
* e.g."ns:widget", namespace defaults to "dojo".
* @param props Key-Value pairs of properties of the widget
* @param refNode If the position argument is specified, this node is used as
* a reference for inserting this node into a DOM tree; else
* the widget becomes the domNode
* @param position The position to insert this widget's node relative to the
* refNode argument
* @return The new Widget object
*/
dojo.widget.createWidget = function(name, props, refNode, position){
var isNode = false;
var isNameStr = (typeof name == "string");
if(isNameStr){
var pos = name.indexOf(":");
var namespace = (pos > -1) ? name.substring(0,pos) : "dojo";
if(pos > -1){ name = name.substring(pos+1); }
var lowerCaseName = name.toLowerCase();
var namespacedName = namespace+":" + lowerCaseName;
isNode = ( dojo.byId(name) && (!dojo.widget.tags[namespacedName]) );
}
if( (arguments.length == 1) && ((isNode)||(!isNameStr)) ){
// we got a DOM node
var xp = new dojo.xml.Parse();
// FIXME: we should try to find the parent!
var tn = (isNode) ? dojo.byId(name) : name;
return dojo.widget.getParser().createComponents(xp.parseElement(tn, null, true))[0];
}
function fromScript(placeKeeperNode, name, props, namespace){
props[namespacedName] = {
dojotype: [{value: lowerCaseName}],
nodeRef: placeKeeperNode,
fastMixIn: true
};
props.namespace = namespace;
return dojo.widget.getParser().createComponentFromScript(
placeKeeperNode, name, props, namespace);
}
props = props||{};
var notRef = false;
var tn = null;
var h = dojo.render.html.capable;
if(h){
tn = document.createElement("span");
}
if(!refNode){
notRef = true;
refNode = tn;
if(h){
dojo.body().appendChild(refNode);
}
}else if(position){
dojo.dom.insertAtPosition(tn, refNode, position);
}else{ // otherwise don't replace, but build in-place
tn = refNode;
}
var widgetArray = fromScript(tn, name.toLowerCase(), props, namespace);
if (!widgetArray || !widgetArray[0] || typeof widgetArray[0].widgetType == "undefined") {
throw new Error("createWidget: Creation of \"" + name + "\" widget failed.");
}
if (notRef) {
if (widgetArray[0].domNode.parentNode) {
widgetArray[0].domNode.parentNode.removeChild(widgetArray[0].domNode);
}
}
return widgetArray[0]; // just return the widget
}
dojo.provide("dojo.namespaces.dojo");
(function(){
//mapping of all widget short names to their full package names
// This is used for widget autoloading - no dojo.require() is necessary.
// If you use a widget in markup or create one dynamically, then this
// mapping is used to find and load any dependencies not already loaded.
// You should use your own namespace for any custom widgets.
// For extra widgets you use, dojo.declare() may be used to explicitly load them.
var map = {
html: {
"accordioncontainer": "dojo.widget.AccordionContainer",
"treerpccontroller": "dojo.widget.TreeRPCController",
"accordionpane": "dojo.widget.AccordionPane",
"button": "dojo.widget.Button",
"chart": "dojo.widget.Chart",
"checkbox": "dojo.widget.Checkbox",
"civicrmdatepicker": "dojo.widget.CiviCrmDatePicker",
"colorpalette": "dojo.widget.ColorPalette",
"combobox": "dojo.widget.ComboBox",
"contentpane": "dojo.widget.ContentPane",
"contextmenu": "dojo.widget.ContextMenu",
"datepicker": "dojo.widget.DatePicker",
"debugconsole": "dojo.widget.DebugConsole",
"dialog": "dojo.widget.Dialog",
"docpane": "dojo.widget.DocPane",
"dropdownbutton": "dojo.widget.DropdownButton",
"dropdowndatepicker": "dojo.widget.DropdownDatePicker",
"editor2": "dojo.widget.Editor2",
"editor2toolbar": "dojo.widget.Editor2Toolbar",
"editor": "dojo.widget.Editor",
"editortree": "dojo.widget.EditorTree",
"editortreecontextmenu": "dojo.widget.EditorTreeContextMenu",
"editortreenode": "dojo.widget.EditorTreeNode",
"fisheyelist": "dojo.widget.FisheyeList",
"editortreecontroller": "dojo.widget.EditorTreeController",
"googlemap": "dojo.widget.GoogleMap",
"editortreeselector": "dojo.widget.EditorTreeSelector",
"floatingpane": "dojo.widget.FloatingPane",
"hslcolorpicker": "dojo.widget.HslColorPicker",
"inlineeditbox": "dojo.widget.InlineEditBox",
"layoutcontainer": "dojo.widget.LayoutContainer",
"linkpane": "dojo.widget.LinkPane",
"manager": "dojo.widget.Manager",
"popupcontainer": "dojo.widget.Menu2",
"popupmenu2": "dojo.widget.Menu2",
"menuitem2": "dojo.widget.Menu2",
"menuseparator2": "dojo.widget.Menu2",
"menubar2": "dojo.widget.Menu2",
"menubaritem2": "dojo.widget.Menu2",
"monthlyCalendar": "dojo.widget.MonthlyCalendar",
"popupbutton": "dojo.widget.PopUpButton",
"richtext": "dojo.widget.RichText",
"remotetabcontroller": "dojo.widget.RemoteTabController",
"resizehandle": "dojo.widget.ResizeHandle",
"resizabletextarea": "dojo.widget.ResizableTextarea",
"select": "dojo.widget.Select",
"slideshow": "dojo.widget.SlideShow",
"sortabletable": "dojo.widget.SortableTable",
"simpledropdownbuttons": "dojo.widget.SimpleDropdownButtons",
"splitcontainer": "dojo.widget.SplitContainer",
"svgbutton": "dojo.widget.SvgButton",
"tabcontainer": "dojo.widget.TabContainer",
"taskbar": "dojo.widget.TaskBar",
"timepicker": "dojo.widget.TimePicker",
"titlepane": "dojo.widget.TitlePane",
"toaster": "dojo.widget.Toaster",
"toggler": "dojo.widget.Toggler",
"toolbar": "dojo.widget.Toolbar",
"tooltip": "dojo.widget.Tooltip",
"tree": "dojo.widget.Tree",
"treebasiccontroller": "dojo.widget.TreeBasicController",
"treecontextmenu": "dojo.widget.TreeContextMenu",
"treeselector": "dojo.widget.TreeSelector",
"treecontrollerextension": "dojo.widget.TreeControllerExtension",
"treenode": "dojo.widget.TreeNode",
"validate": "dojo.widget.validate",
"treeloadingcontroller": "dojo.widget.TreeLoadingController",
"widget": "dojo.widget.Widget",
"wizard": "dojo.widget.Wizard",
"yahoomap": "dojo.widget.YahooMap"
},
svg: {
"chart": "dojo.widget.svg.Chart",
"hslcolorpicker": "dojo.widget.svg.HslColorPicker"
},
vml: {
"chart": "dojo.widget.vml.Chart"
}
};
function dojoNamespaceResolver(name, domain){
if(!domain){ domain="html"; }
if(!map[domain]){ return null; }
return map[domain][name];
}
dojo.defineNamespace("dojo", "src", "dojo", dojoNamespaceResolver);
dojo.addDojoNamespaceMapping = function(shortName, fullName){
map[shortName]=fullName;
};
})();
dojo.provide("dojo.html.style");
/**
* Returns the string value of the list of CSS classes currently assigned
* directly to the node in question. Returns an empty string if no class attribute
* is found;
*/
dojo.html.getClass = function(node){
node = dojo.byId(node);
if(!node){ return ""; }
var cs = "";
if(node.className){
cs = node.className;
}else if(dojo.html.hasAttribute(node, "class")){
cs = dojo.html.getAttribute(node, "class");
}
return cs.replace(/^\s+|\s+$/g, "");
}
/**
* Returns an array of CSS classes currently assigned
* directly to the node in question. Returns an empty array if no classes
* are found;
*/
dojo.html.getClasses = function(node) {
var c = dojo.html.getClass(node);
return (c == "") ? [] : c.split(/\s+/g);
}
/**
* Returns whether or not the specified classname is a portion of the
* class list currently applied to the node. Does not cover cascaded
* styles, only classes directly applied to the node.
*/
dojo.html.hasClass = function(node, classname){
return (new RegExp('(^|\\s+)'+classname+'(\\s+|$)')).test(dojo.html.getClass(node))
}
/**
* Adds the specified class to the beginning of the class list on the
* passed node. This gives the specified class the highest precidence
* when style cascading is calculated for the node. Returns true or
* false; indicating success or failure of the operation, respectively.
*/
dojo.html.prependClass = function(node, classStr){
classStr += " " + dojo.html.getClass(node);
return dojo.html.setClass(node, classStr);
}
/**
* Adds the specified class to the end of the class list on the
* passed &node;. Returns &true; or &false; indicating success or failure.
*/
dojo.html.addClass = function(node, classStr){
if (dojo.html.hasClass(node, classStr)) {
return false;
}
classStr = (dojo.html.getClass(node) + " " + classStr).replace(/^\s+|\s+$/g,"");
return dojo.html.setClass(node, classStr);
}
/**
* Clobbers the existing list of classes for the node, replacing it with
* the list given in the 2nd argument. Returns true or false
* indicating success or failure.
*/
dojo.html.setClass = function(node, classStr){
node = dojo.byId(node);
var cs = new String(classStr);
try{
if(typeof node.className == "string"){
node.className = cs;
}else if(node.setAttribute){
node.setAttribute("class", classStr);
node.className = cs;
}else{
return false;
}
}catch(e){
dojo.debug("dojo.html.setClass() failed", e);
}
return true;
}
/**
* Removes the className from the node;. Returns
* true or false indicating success or failure.
*/
dojo.html.removeClass = function(node, classStr, allowPartialMatches){
//dojo.debug("was class "+dojo.html.getClass(node));
try{
if (!allowPartialMatches) {
var newcs = dojo.html.getClass(node).replace(new RegExp('(^|\\s+)'+classStr+'(\\s+|$)'), "$1$2");
} else {
var newcs = dojo.html.getClass(node).replace(classStr,'');
}
dojo.html.setClass(node, newcs);
//dojo.debug("now class "+newcs)
}catch(e){
dojo.debug("dojo.html.removeClass() failed", e);
}
return true;
}
/**
* Replaces 'oldClass' and adds 'newClass' to node
*/
dojo.html.replaceClass = function(node, newClass, oldClass) {
dojo.html.removeClass(node, oldClass);
dojo.html.addClass(node, newClass);
}
// Enum type for getElementsByClass classMatchType arg:
dojo.html.classMatchType = {
ContainsAll : 0, // all of the classes are part of the node's class (default)
ContainsAny : 1, // any of the classes are part of the node's class
IsOnly : 2 // only all of the classes are part of the node's class
}
/**
* Returns an array of nodes for the given classStr, children of a
* parent, and optionally of a certain nodeType
*/
dojo.html.getElementsByClass = function(classStr, parent, nodeType, classMatchType, useNonXpath){
var _document = dojo.doc();
parent = dojo.byId(parent) || _document;
var classes = classStr.split(/\s+/g);
var nodes = [];
if( classMatchType != 1 && classMatchType != 2 ) classMatchType = 0; // make it enum
var reClass = new RegExp("(\\s|^)((" + classes.join(")|(") + "))(\\s|$)");
var srtLength = classes.join(" ").length;
var candidateNodes = [];
if(!useNonXpath && _document.evaluate) { // supports dom 3 xpath
var xpath = ".//" + (nodeType || "*") + "[contains(";
if(classMatchType != dojo.html.classMatchType.ContainsAny){
xpath += "concat(' ',@class,' '), ' " +
classes.join(" ') and contains(concat(' ',@class,' '), ' ") +
" ')";
if (classMatchType == 2) {
xpath += " and string-length(@class)="+srtLength+"]";
}else{
xpath += "]";
}
}else{
xpath += "concat(' ',@class,' '), ' " +
classes.join(" ')) or contains(concat(' ',@class,' '), ' ") +
" ')]";
}
var xpathResult = _document.evaluate(xpath, parent, null, XPathResult.ANY_TYPE, null);
var result = xpathResult.iterateNext();
while(result){
try{
candidateNodes.push(result);
result = xpathResult.iterateNext();
}catch(e){ break; }
}
return candidateNodes;
}else{
if(!nodeType){
nodeType = "*";
}
candidateNodes = parent.getElementsByTagName(nodeType);
var node, i = 0;
outer:
while(node = candidateNodes[i++]){
var nodeClasses = dojo.html.getClasses(node);
if(nodeClasses.length == 0){ continue outer; }
var matches = 0;
for(var j = 0; j < nodeClasses.length; j++){
if(reClass.test(nodeClasses[j])){
if(classMatchType == dojo.html.classMatchType.ContainsAny){
nodes.push(node);
continue outer;
}else{
matches++;
}
}else{
if(classMatchType == dojo.html.classMatchType.IsOnly){
continue outer;
}
}
}
if(matches == classes.length){
if( (classMatchType == dojo.html.classMatchType.IsOnly)&&
(matches == nodeClasses.length)){
nodes.push(node);
}else if(classMatchType == dojo.html.classMatchType.ContainsAll){
nodes.push(node);
}
}
}
return nodes;
}
}
dojo.html.getElementsByClassName = dojo.html.getElementsByClass;
dojo.html.toCamelCase = function(selector){
var arr = selector.split('-'), cc = arr[0];
for(var i = 1; i < arr.length; i++) {
cc += arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
}
return cc;
}
dojo.html.toSelectorCase = function(selector){
return selector.replace(/([A-Z])/g, "-$1" ).toLowerCase();
}
dojo.html.getComputedStyle = function(node, cssSelector, inValue){
node = dojo.byId(node);
// cssSelector may actually be in camel case, so force selector version
var cssSelector = dojo.html.toSelectorCase(cssSelector);
var property = dojo.html.toCamelCase(cssSelector);
if(!node || !node.style){
return inValue;
}else if(document.defaultView &&
// mozilla segfaults when margin-* and node is removed from doc
// FIXME: need to figure out a if there is quicker workaround
dojo.dom.isDescendantOf(node, node.ownerDocument)){ // W3, gecko, KHTML
try{
var cs = document.defaultView.getComputedStyle(node, "");
if (cs){
return cs.getPropertyValue(cssSelector);
}
}catch(e){ // reports are that Safari can throw an exception above
if (node.style.getPropertyValue){ // W3
return node.style.getPropertyValue(cssSelector);
}else return inValue;
}
}else if(node.currentStyle){ // IE
return node.currentStyle[property];
}if(node.style.getPropertyValue){ // W3
return node.style.getPropertyValue(cssSelector);
}else{
return inValue;
}
}
dojo.html.getStyleProperty = function(node, cssSelector){
node = dojo.byId(node);
return (node && node.style ? node.style[dojo.html.toCamelCase(cssSelector)] : undefined);
}
dojo.html.getStyle = function(node, cssSelector){
var value = dojo.html.getStyleProperty(node, cssSelector);
return (value ? value : dojo.html.getComputedStyle(node, cssSelector));
}
dojo.html.setStyle = function(node, cssSelector, value){
node = dojo.byId(node);
if(node && node.style){
var camelCased = dojo.html.toCamelCase(cssSelector);
node.style[camelCased] = value;
}
}
dojo.html.copyStyle = function(target, source){
// work around for opera which doesn't have cssText, and for IE which fails on setAttribute
if(!source.style.cssText){
target.setAttribute("style", source.getAttribute("style"));
}else{
target.style.cssText = source.style.cssText;
}
dojo.html.addClass(target, dojo.html.getClass(source));
}
dojo.html.getUnitValue = function(node, cssSelector, autoIsZero){
var s = dojo.html.getComputedStyle(node, cssSelector);
if((!s)||((s == 'auto')&&(autoIsZero))){ return { value: 0, units: 'px' }; }
// FIXME: is regex inefficient vs. parseInt or some manual test?
var match = s.match(/(\-?[\d.]+)([a-z%]*)/i);
if (!match){return dojo.html.getUnitValue.bad;}
return { value: Number(match[1]), units: match[2].toLowerCase() };
}
dojo.html.getUnitValue.bad = { value: NaN, units: '' };
dojo.html.getPixelValue = function(node, cssSelector, autoIsZero){
var result = dojo.html.getUnitValue(node, cssSelector, autoIsZero);
// FIXME: there is serious debate as to whether or not this is the right solution
if(isNaN(result.value)){ return 0; }
// FIXME: code exists for converting other units to px (see Dean Edward's IE7)
// but there are cross-browser complexities
if((result.value)&&(result.units != 'px')){ return NaN; }
return result.value;
}
dojo.html.setPositivePixelValue = function(node, selector, value){
if(isNaN(value)){return false;}
node.style[selector] = Math.max(0, value) + 'px';
return true;
}
dojo.html.styleSheet = null;
// FIXME: this is a really basic stub for adding and removing cssRules, but
// it assumes that you know the index of the cssRule that you want to add
// or remove, making it less than useful. So we need something that can
// search for the selector that you you want to remove.
dojo.html.insertCssRule = function(selector, declaration, index) {
if (!dojo.html.styleSheet) {
if (document.createStyleSheet) { // IE
dojo.html.styleSheet = document.createStyleSheet();
} else if (document.styleSheets[0]) { // rest
// FIXME: should create a new style sheet here
// fall back on an exsiting style sheet
dojo.html.styleSheet = document.styleSheets[0];
} else { return null; } // fail
}
if (arguments.length < 3) { // index may == 0
if (dojo.html.styleSheet.cssRules) { // W3
index = dojo.html.styleSheet.cssRules.length;
} else if (dojo.html.styleSheet.rules) { // IE
index = dojo.html.styleSheet.rules.length;
} else { return null; } // fail
}
if (dojo.html.styleSheet.insertRule) { // W3
var rule = selector + " { " + declaration + " }";
return dojo.html.styleSheet.insertRule(rule, index);
} else if (dojo.html.styleSheet.addRule) { // IE
return dojo.html.styleSheet.addRule(selector, declaration, index);
} else { return null; } // fail
}
dojo.html.removeCssRule = function(index){
if(!dojo.html.styleSheet){
dojo.debug("no stylesheet defined for removing rules");
return false;
}
if(dojo.html.render.ie){
if(!index){
index = dojo.html.styleSheet.rules.length;
dojo.html.styleSheet.removeRule(index);
}
}else if(document.styleSheets[0]){
if(!index){
index = dojo.html.styleSheet.cssRules.length;
}
dojo.html.styleSheet.deleteRule(index);
}
return true;
}
// calls css by XmlHTTP and inserts it into DOM as <style [widgetType="widgetType"]> *downloaded cssText*</style>
dojo.html._insertedCssFiles = []; // cache container needed because IE reformats cssText when added to DOM
dojo.html.insertCssFile = function(URI, doc, checkDuplicates){
if(!URI){ return; }
if(!doc){ doc = document; }
var cssStr = dojo.hostenv.getText(URI);
cssStr = dojo.html.fixPathsInCssText(cssStr, URI);
if(checkDuplicates){
var idx = -1, node, ent = dojo.html._insertedCssFiles;
for(var i = 0; i < ent.length; i++){
if((ent[i].doc == doc) && (ent[i].cssText == cssStr)){
idx = i; node = ent[i].nodeRef;
break;
}
}
// make sure we havent deleted our node
if(node){
var styles = doc.getElementsByTagName("style");
for(var i = 0; i < styles.length; i++){
if(styles[i] == node){
return;
}
}
// delete this entry
dojo.html._insertedCssFiles.shift(idx, 1);
}
}
var style = dojo.html.insertCssText(cssStr);
dojo.html._insertedCssFiles.push({'doc': doc, 'cssText': cssStr, 'nodeRef': style});
// insert custom attribute ex dbgHref="../foo.css" usefull when debugging in DOM inspectors, no?
if(style && djConfig.isDebug){
style.setAttribute("dbgHref", URI);
}
return style
}
// DomNode Style = insertCssText(String ".dojoMenu {color: green;}"[, DomDoc document, dojo.uri.Uri Url ])
dojo.html.insertCssText = function(cssStr, doc, URI){
if(!cssStr){ return; }
if(!doc){ doc = document; }
if(URI){// fix paths in cssStr
cssStr = dojo.html.fixPathsInCssText(cssStr, URI);
}
var style = doc.createElement("style");
style.setAttribute("type", "text/css");
// IE is b0rken enough to require that we add the element to the doc
// before changing it's properties
var head = doc.getElementsByTagName("head")[0];
if(!head){ // must have a head tag
dojo.debug("No head tag in document, aborting styles");
return;
}else{
head.appendChild(style);
}
if(style.styleSheet){// IE
style.styleSheet.cssText = cssStr;
}else{ // w3c
var cssText = doc.createTextNode(cssStr);
style.appendChild(cssText);
}
return style;
}
// String cssText = fixPathsInCssText(String cssStr, dojo.uri.Uri URI)
// usage: cssText comes from dojoroot/src/widget/templates/HtmlFoobar.css
// it has .dojoFoo { background-image: url(images/bar.png);}
// then uri should point to dojoroot/src/widget/templates/
dojo.html.fixPathsInCssText = function(cssStr, URI){
if(!cssStr || !URI){ return; }
var match, str = "", url = "";
var regex = /url\(\s*([\t\s\w()\/.\\'"-:#=&?]+)\s*\)/;
var regexProtocol = /(file|https?|ftps?):\/\//;
var regexTrim = /^[\s]*(['"]?)([\w()\/.\\'"-:#=&?]*)\1[\s]*?$/;
while(match = regex.exec(cssStr)){
url = match[1].replace(regexTrim, "$2");
if(!regexProtocol.exec(url)){
url = (new dojo.uri.Uri(URI, url).toString());
}
str += cssStr.substring(0, match.index) + "url(" + url + ")";
cssStr = cssStr.substr(match.index + match[0].length);
}
return str + cssStr;
}
dojo.html.setActiveStyleSheet = function(title){
var i = 0, a, els = dojo.doc().getElementsByTagName("link");
while (a = els[i++]) {
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")){
a.disabled = true;
if (a.getAttribute("title") == title) { a.disabled = false; }
}
}
}
dojo.html.getActiveStyleSheet = function(){
var i = 0, a, els = dojo.doc().getElementsByTagName("link");
while (a = els[i++]) {
if (a.getAttribute("rel").indexOf("style") != -1 &&
a.getAttribute("title") && !a.disabled) { return a.getAttribute("title"); }
}
return null;
}
dojo.html.getPreferredStyleSheet = function(){
var i = 0, a, els = dojo.doc().getElementsByTagName("link");
while (a = els[i++]) {
if(a.getAttribute("rel").indexOf("style") != -1
&& a.getAttribute("rel").indexOf("alt") == -1
&& a.getAttribute("title")) { return a.getAttribute("title"); }
}
return null;
}
dojo.provide("dojo.uri.Uri");
dojo.uri = new function() {
this.dojoUri = function (uri) {
// returns a Uri object resolved relative to the dojo root
return new dojo.uri.Uri(dojo.hostenv.getBaseScriptUri(), uri);
}
//returns a URI of a widget in a namespace, for example dojo.uri.nsUri("dojo","Editor"), or dojo.uri.nsUri("customNS","someWidget")
this.nsUri = function(namespace,uri){
var ns = dojo.getNamespace(namespace);
if(!ns){
return null;
}
var loc = ns.location;
if(loc.lastIndexOf("/") != loc.length - 1){
loc += "/";
}
return new dojo.uri.Uri(dojo.hostenv.getBaseScriptUri()+loc,uri);
}
this.Uri = function (/*uri1, uri2, [...]*/) {
// An object representing a Uri.
// Each argument is evaluated in order relative to the next until
// a conanical uri is producued. To get an absolute Uri relative
// to the current document use
// new dojo.uri.Uri(document.baseURI, uri)
// TODO: support for IPv6, see RFC 2732
// resolve uri components relative to each other
var uri = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if(!arguments[i]) { continue; }
// Safari doesn't support this.constructor so we have to be explicit
var relobj = new dojo.uri.Uri(arguments[i].toString());
var uriobj = new dojo.uri.Uri(uri.toString());
if (relobj.path == "" && relobj.scheme == null &&
relobj.authority == null && relobj.query == null) {
if (relobj.fragment != null) { uriobj.fragment = relobj.fragment; }
relobj = uriobj;
} else if (relobj.scheme == null) {
relobj.scheme = uriobj.scheme;
if (relobj.authority == null) {
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 != null) { uri += relobj.scheme + ":"; }
if (relobj.authority != null) { uri += "//" + relobj.authority; }
uri += relobj.path;
if (relobj.query != null) { uri += "?" + relobj.query; }
if (relobj.fragment != null) { uri += "#" + relobj.fragment; }
}
this.uri = uri.toString();
// break the uri into its main components
var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
var r = this.uri.match(new RegExp(regexp));
this.scheme = r[2] || (r[1] ? "" : null);
this.authority = r[4] || (r[3] ? "" : null);
this.path = r[5]; // can never be undefined
this.query = r[7] || (r[6] ? "" : null);
this.fragment = r[9] || (r[8] ? "" : null);
if (this.authority != null) {
// server based naming authority
regexp = "^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$";
r = this.authority.match(new RegExp(regexp));
this.user = r[3] || null;
this.password = r[4] || null;
this.host = r[5];
this.port = r[7] || null;
}
this.toString = function(){ return this.uri; }
}
};
dojo.provide("dojo.uri.*");
dojo.provide("dojo.widget.DomWidget");
dojo.widget._cssFiles = {};
dojo.widget._cssStrings = {};
dojo.widget._templateCache = {};
dojo.widget.defaultStrings = {
dojoRoot: dojo.hostenv.getBaseScriptUri(),
baseScriptUri: dojo.hostenv.getBaseScriptUri()
};
dojo.widget.buildFromTemplate = function() {
dojo.lang.forward("fillFromTemplateCache");
}
// static method to build from a template w/ or w/o a real widget in place
dojo.widget.fillFromTemplateCache = function(obj, templatePath, templateString, avoidCache){
// dojo.debug("avoidCache:", avoidCache);
var tpath = templatePath || obj.templatePath;
// DEPRECATED: use Uri objects, not strings
if (tpath && !(tpath instanceof dojo.uri.Uri)) {
tpath = dojo.uri.dojoUri(tpath);
dojo.deprecated("templatePath should be of type dojo.uri.Uri", null, "0.4");
}
var tmplts = dojo.widget._templateCache;
if(!obj["widgetType"]) { // don't have a real template here
do {
var dummyName = "__dummyTemplate__" + dojo.widget._templateCache.dummyCount++;
} while(tmplts[dummyName]);
obj.widgetType = dummyName;
}
var wt = obj.widgetType;
var ts = tmplts[wt];
if(!ts){
tmplts[wt] = { "string": null, "node": null };
if(avoidCache){
ts = {};
}else{
ts = tmplts[wt];
}
}
if((!obj.templateString)&&(!avoidCache)){
obj.templateString = templateString || ts["string"];
}
if((!obj.templateNode)&&(!avoidCache)){
obj.templateNode = ts["node"];
}
if((!obj.templateNode)&&(!obj.templateString)&&(tpath)){
// fetch a text fragment and assign it to templateString
// NOTE: we rely on blocking IO here!
var tstring = dojo.hostenv.getText(tpath);
if(tstring){
// strip <?xml ...?> declarations so that external SVG and XML
// documents can be added to a document without worry
tstring = tstring.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
var matches = tstring.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
if(matches){
tstring = matches[1];
}
}else{
tstring = "";
}
obj.templateString = tstring;
if(!avoidCache){
tmplts[wt]["string"] = tstring;
}
}
if((!ts["string"])&&(!avoidCache)){
ts.string = obj.templateString;
}
}
dojo.widget._templateCache.dummyCount = 0;
dojo.widget.attachProperties = ["dojoAttachPoint", "id"];
dojo.widget.eventAttachProperty = "dojoAttachEvent";
dojo.widget.onBuildProperty = "dojoOnBuild";
dojo.widget.waiNames = ["waiRole", "waiState"];
dojo.widget.wai = {
waiRole: { name: "waiRole",
namespace: "http://www.w3.org/TR/xhtml2",
alias: "x2",
prefix: "wairole:"
},
waiState: { name: "waiState",
namespace: "http://www.w3.org/2005/07/aaa" ,
alias: "aaa",
prefix: ""
},
setAttr: function(node, ns, attr, value){
if(dojo.render.html.ie){
node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
}else{
node.setAttributeNS(this[ns].namespace, attr, this[ns].prefix+value);
}
},
getAttr: function(node, ns, attr){
if(dojo.render.html.ie){
return node.getAttribute(this[ns].alias+":"+attr);
}else{
return node.getAttributeNS(this[ns].namespace, attr);
}
}
};
dojo.widget.attachTemplateNodes = function(rootNode, targetObj, events){
// FIXME: this method is still taking WAAAY too long. We need ways of optimizing:
// a.) what we are looking for on each node
// b.) the nodes that are subject to interrogation (use xpath instead?)
// c.) how expensive event assignment is (less eval(), more connect())
// var start = new Date();
var elementNodeType = dojo.dom.ELEMENT_NODE;
function trim(str){
return str.replace(/^\s+|\s+$/g, "");
}
if(!rootNode){
rootNode = targetObj.domNode;
}
if(rootNode.nodeType != elementNodeType){
return;
}
// alert(events.length);
var nodes = rootNode.all || rootNode.getElementsByTagName("*");
var _this = targetObj;
for(var x=-1; x<nodes.length; x++){
var baseNode = (x == -1) ? rootNode : nodes[x];
// FIXME: is this going to have capitalization problems? Could use getAttribute(name, 0); to get attributes case-insensitve
var attachPoint = [];
for(var y=0; y<this.attachProperties.length; y++){
var tmpAttachPoint = baseNode.getAttribute(this.attachProperties[y]);
if(tmpAttachPoint){
attachPoint = tmpAttachPoint.split(";");
for(var z=0; z<attachPoint.length; z++){
if(dojo.lang.isArray(targetObj[attachPoint[z]])){
targetObj[attachPoint[z]].push(baseNode);
}else{
targetObj[attachPoint[z]]=baseNode;
}
}
break;
}
}
// continue;
// FIXME: we need to put this into some kind of lookup structure
// instead of direct assignment
var tmpltPoint = baseNode.getAttribute(this.templateProperty);
if(tmpltPoint){
targetObj[tmpltPoint]=baseNode;
}
dojo.lang.forEach(dojo.widget.waiNames, function(name){
var wai = dojo.widget.wai[name];
var val = baseNode.getAttribute(wai.name);
if(val){
if(val.indexOf('-') == -1){
dojo.widget.wai.setAttr(baseNode, wai.name, "role", val);
}else{
// this is a state-value pair
var statePair = val.split('-');
dojo.widget.wai.setAttr(baseNode, wai.name, statePair[0], statePair[1]);
}
}
}, this);
var attachEvent = baseNode.getAttribute(this.eventAttachProperty);
if(attachEvent){
// NOTE: we want to support attributes that have the form
// "domEvent: nativeEvent; ..."
var evts = attachEvent.split(";");
for(var y=0; y<evts.length; y++){
if((!evts[y])||(!evts[y].length)){ continue; }
var thisFunc = null;
var tevt = trim(evts[y]);
if(evts[y].indexOf(":") >= 0){
// oh, if only JS had tuple assignment
var funcNameArr = tevt.split(":");
tevt = trim(funcNameArr[0]);
thisFunc = trim(funcNameArr[1]);
}
if(!thisFunc){
thisFunc = tevt;
}
var tf = function(){
var ntf = new String(thisFunc);
return function(evt){
if(_this[ntf]){
_this[ntf](dojo.event.browser.fixEvent(evt, this));
}
};
}();
dojo.event.browser.addListener(baseNode, tevt, tf, false, true);
// dojo.event.browser.addListener(baseNode, tevt, dojo.lang.hitch(_this, thisFunc));
}
}
for(var y=0; y<events.length; y++){
//alert(events[x]);
var evtVal = baseNode.getAttribute(events[y]);
if((evtVal)&&(evtVal.length)){
var thisFunc = null;
var domEvt = events[y].substr(4); // clober the "dojo" prefix
thisFunc = trim(evtVal);
var funcs = [thisFunc];
if(thisFunc.indexOf(";")>=0){
funcs = dojo.lang.map(thisFunc.split(";"), trim);
}
for(var z=0; z<funcs.length; z++){
if(!funcs[z].length){ continue; }
var tf = function(){
var ntf = new String(funcs[z]);
return function(evt){
if(_this[ntf]){
_this[ntf](dojo.event.browser.fixEvent(evt, this));
}
}
}();
dojo.event.browser.addListener(baseNode, domEvt, tf, false, true);
// dojo.event.browser.addListener(baseNode, domEvt, dojo.lang.hitch(_this, funcs[z]));
}
}
}
var onBuild = baseNode.getAttribute(this.onBuildProperty);
if(onBuild){
eval("var node = baseNode; var widget = targetObj; "+onBuild);
}
}
}
dojo.widget.getDojoEventsFromStr = function(str){
// var lstr = str.toLowerCase();
var re = /(dojoOn([a-z]+)(\s?))=/gi;
var evts = str ? str.match(re)||[] : [];
var ret = [];
var lem = {};
for(var x=0; x<evts.length; x++){
if(evts[x].legth < 1){ continue; }
var cm = evts[x].replace(/\s/, "");
cm = (cm.slice(0, cm.length-1));
if(!lem[cm]){
lem[cm] = true;
ret.push(cm);
}
}
return ret;
}
/*
dojo.widget.buildAndAttachTemplate = function(obj, templatePath, templateCssPath, templateString, targetObj) {
this.buildFromTemplate(obj, templatePath, templateCssPath, templateString);
var node = dojo.dom.createNodesFromText(obj.templateString, true)[0];
this.attachTemplateNodes(node, targetObj||obj, dojo.widget.getDojoEventsFromStr(templateString));
return node;
}
*/
dojo.declare("dojo.widget.DomWidget", dojo.widget.Widget,
function() {
if((arguments.length>0)&&(typeof arguments[0] == "object")){
this.create(arguments[0]);
}
},
{
templateNode: null,
templateString: null,
templateCssString: null,
preventClobber: false,
domNode: null, // this is our visible representation of the widget!
containerNode: null, // holds child elements
// Process the given child widget, inserting it's dom node as a child of our dom node
// FIXME: should we support addition at an index in the children arr and
// order the display accordingly? Right now we always append.
addChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
if(!this.isContainer){ // we aren't allowed to contain other widgets, it seems
dojo.debug("dojo.widget.DomWidget.addChild() attempted on non-container widget");
return null;
}else{
if(insertIndex == undefined){
insertIndex = this.children.length;
}
this.addWidgetAsDirectChild(widget, overrideContainerNode, pos, ref, insertIndex);
this.registerChild(widget, insertIndex);
}
return widget;
},
addWidgetAsDirectChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
if((!this.containerNode)&&(!overrideContainerNode)){
this.containerNode = this.domNode;
}
var cn = (overrideContainerNode) ? overrideContainerNode : this.containerNode;
if(!pos){ pos = "after"; }
if(!ref){
if(!cn){ cn = dojo.body(); }
ref = cn.lastChild;
}
if(!insertIndex) { insertIndex = 0; }
widget.domNode.setAttribute("dojoinsertionindex", insertIndex);
// insert the child widget domNode directly underneath my domNode, in the
// specified position (by default, append to end)
if(!ref){
cn.appendChild(widget.domNode);
}else{
// FIXME: was this meant to be the (ugly hack) way to support insert @ index?
//dojo.dom[pos](widget.domNode, ref, insertIndex);
// CAL: this appears to be the intended way to insert a node at a given position...
if (pos == 'insertAtIndex'){
// dojo.debug("idx:", insertIndex, "isLast:", ref === cn.lastChild);
dojo.dom.insertAtIndex(widget.domNode, ref.parentNode, insertIndex);
}else{
// dojo.debug("pos:", pos, "isLast:", ref === cn.lastChild);
if((pos == "after")&&(ref === cn.lastChild)){
cn.appendChild(widget.domNode);
}else{
dojo.dom.insertAtPosition(widget.domNode, cn, pos);
}
}
}
},
// Record that given widget descends from me
registerChild: function(widget, insertionIndex){
// we need to insert the child at the right point in the parent's
// 'children' array, based on the insertionIndex
widget.dojoInsertionIndex = insertionIndex;
var idx = -1;
for(var i=0; i<this.children.length; i++){
if (this.children[i].dojoInsertionIndex < insertionIndex){
idx = i;
}
}
this.children.splice(idx+1, 0, widget);
widget.parent = this;
widget.addedTo(this, idx+1);
// If this widget was created programatically, then it was erroneously added
// to dojo.widget.manager.topWidgets. Fix that here.
delete dojo.widget.manager.topWidgets[widget.widgetId];
},
removeChild: function(widget){
// detach child domNode from parent domNode
dojo.dom.removeNode(widget.domNode);
// remove child widget from parent widget
return dojo.widget.DomWidget.superclass.removeChild.call(this, widget);
},
getFragNodeRef: function(frag){
if(!frag || !frag[this.namespace+":"+this.widgetType.toLowerCase()]){
dojo.raise("Error: no frag for widget type " + this.widgetType
+ " with namespace "+this.namespace + ", id " + this.widgetId
+ " (maybe a widget has set it's type incorrectly)");
}
return frag ? frag[this.namespace+":"+this.widgetType.toLowerCase()]["nodeRef"] : null;
},
// Replace source domNode with generated dom structure, and register
// widget with parent.
postInitialize: function(args, frag, parentComp){
//dojo.profile.start(this.widgetType + " postInitialize");
var sourceNodeRef = this.getFragNodeRef(frag);
// Stick my generated dom into the output tree
//alert(this.widgetId + ": replacing " + sourceNodeRef + " with " + this.domNode.innerHTML);
if (parentComp && (parentComp.snarfChildDomOutput || !sourceNodeRef)){
// Add my generated dom as a direct child of my parent widget
// This is important for generated widgets, and also cases where I am generating an
// <li> node that can't be inserted back into the original DOM tree
parentComp.addWidgetAsDirectChild(this, "", "insertAtIndex", "", args["dojoinsertionindex"], sourceNodeRef);
} else if (sourceNodeRef){
// Do in-place replacement of the my source node with my generated dom
if(this.domNode && (this.domNode !== sourceNodeRef)){
var oldNode = sourceNodeRef.parentNode.replaceChild(this.domNode, sourceNodeRef);
}
}
// Register myself with my parent, or with the widget manager if
// I have no parent
// TODO: the code below erroneously adds all programatically generated widgets
// to topWidgets (since we don't know who the parent is until after creation finishes)
if ( parentComp ) {
parentComp.registerChild(this, args.dojoinsertionindex);
} else {
dojo.widget.manager.topWidgets[this.widgetId]=this;
}
//dojo.profile.end(this.widgetType + " postInitialize");
// Expand my children widgets
/* dojoDontFollow is important for a very special case
* basically if you have a widget that you instantiate from script
* and that widget is a container, and it contains a reference to a parent
* instance, the parser will start recursively parsing until the browser
* complains. So the solution is to set an initialization property of
* dojoDontFollow: true and then it won't recurse where it shouldn't
*/
if(this.isContainer && !frag["dojoDontFollow"]){
//alert("recurse from " + this.widgetId);
// build any sub-components with us as the parent
var fragParser = dojo.widget.getParser();
fragParser.createSubComponents(frag, this);
}
},
// method over-ride
buildRendering: function(args, frag){
// DOM widgets construct themselves from a template
var ts = dojo.widget._templateCache[this.widgetType];
// Handle style for this widget here, as even if templatePath
// is not set, style specified by templateCssString or templateCssPath
// should be applied. templateCssString has higher priority
// than templateCssPath
if(args["templatecsspath"]){
args["templateCssPath"] = args["templatecsspath"];
}
var cpath = args["templateCssPath"] || this.templateCssPath;
// DEPRECATED: use Uri objects, not strings
if (cpath && !(cpath instanceof dojo.uri.Uri)) {
cpath = dojo.uri.dojoUri(cpath);
dojo.deprecated("templateCssPath should be of type dojo.uri.Uri", null, "0.4");
}
if(cpath && !dojo.widget._cssFiles[cpath.toString()]){
if((!this.templateCssString)&&(cpath)){
this.templateCssString = dojo.hostenv.getText(cpath);
this.templateCssPath = null;
}
dojo.widget._cssFiles[cpath.toString()] = true;
}
if((this["templateCssString"])&&(!this.templateCssString["loaded"])){
dojo.html.insertCssText(this.templateCssString, null, cpath);
if(!this.templateCssString){ this.templateCssString = ""; }
this.templateCssString.loaded = true;
}
if(
(!this.preventClobber)&&(
(this.templatePath)||
(this.templateNode)||
(
(this["templateString"])&&(this.templateString.length)
)||
(
(typeof ts != "undefined")&&( (ts["string"])||(ts["node"]) )
)
)
){
// if it looks like we can build the thing from a template, do it!
this.buildFromTemplate(args, frag);
}else{
// otherwise, assign the DOM node that was the source of the widget
// parsing to be the root node
this.domNode = this.getFragNodeRef(frag);
}
this.fillInTemplate(args, frag); // this is where individual widgets
// will handle population of data
// from properties, remote data
// sets, etc.
},
buildFromTemplate: function(args, frag){
// var start = new Date();
// copy template properties if they're already set in the templates object
// dojo.debug("buildFromTemplate:", this);
var avoidCache = false;
if(args["templatepath"]){
avoidCache = true;
args["templatePath"] = args["templatepath"];
}
dojo.widget.fillFromTemplateCache( this,
args["templatePath"],
null,
avoidCache);
var ts = dojo.widget._templateCache[this.widgetType];
if((ts)&&(!avoidCache)){
if(!this.templateString.length){
this.templateString = ts["string"];
}
if(!this.templateNode){
this.templateNode = ts["node"];
}
}
var matches = false;
var node = null;
// var tstr = new String(this.templateString);
var tstr = this.templateString;
// attempt to clone a template node, if there is one
if((!this.templateNode)&&(this.templateString)){
matches = this.templateString.match(/\$\{([^\}]+)\}/g);
if(matches) {
// if we do property replacement, don't create a templateNode
// to clone from.
var hash = this.strings || {};
// FIXME: should this hash of default replacements be cached in
// templateString?
for(var key in dojo.widget.defaultStrings) {
if(dojo.lang.isUndefined(hash[key])) {
hash[key] = dojo.widget.defaultStrings[key];
}
}
// FIXME: this is a lot of string munging. Can we make it faster?
for(var i = 0; i < matches.length; i++) {
var key = matches[i];
key = key.substring(2, key.length-1);
var kval = (key.substring(0, 5) == "this.") ? dojo.lang.getObjPathValue(key.substring(5), this) : hash[key];
var value;
if((kval)||(dojo.lang.isString(kval))){
value = (dojo.lang.isFunction(kval)) ? kval.call(this, key, this.templateString) : kval;
tstr = tstr.replace(matches[i], value);
}
}
}else{
// otherwise, we are required to instantiate a copy of the template
// string if one is provided.
// FIXME: need to be able to distinguish here what should be done
// or provide a generic interface across all DOM implementations
// FIMXE: this breaks if the template has whitespace as its first
// characters
// node = this.createNodesFromText(this.templateString, true);
// this.templateNode = node[0].cloneNode(true); // we're optimistic here
this.templateNode = this.createNodesFromText(this.templateString, true)[0];
if(!avoidCache){
ts.node = this.templateNode;
}
}
}
if((!this.templateNode)&&(!matches)){
dojo.debug("DomWidget.buildFromTemplate: could not create template");
return false;
}else if(!matches){
node = this.templateNode.cloneNode(true);
if(!node){ return false; }
}else{
node = this.createNodesFromText(tstr, true)[0];
}
// recurse through the node, looking for, and attaching to, our
// attachment points which should be defined on the template node.
this.domNode = node;
// dojo.profile.start("attachTemplateNodes");
this.attachTemplateNodes(this.domNode, this);
// dojo.profile.end("attachTemplateNodes");
// relocate source contents to templated container node
// this.containerNode must be able to receive children, or exceptions will be thrown
if (this.isContainer && this.containerNode){
var src = this.getFragNodeRef(frag);
if (src){
dojo.dom.moveChildren(src, this.containerNode);
}
}
},
attachTemplateNodes: function(baseNode, targetObj){
if(!targetObj){ targetObj = this; }
return dojo.widget.attachTemplateNodes(baseNode, targetObj,
dojo.widget.getDojoEventsFromStr(this.templateString));
},
fillInTemplate: function(){
// dojo.unimplemented("dojo.widget.DomWidget.fillInTemplate");
},
// method over-ride
destroyRendering: function(){
try{
delete this.domNode;
}catch(e){ /* squelch! */ }
},
// FIXME: method over-ride
cleanUp: function(){},
getContainerHeight: function(){
dojo.unimplemented("dojo.widget.DomWidget.getContainerHeight");
},
getContainerWidth: function(){
dojo.unimplemented("dojo.widget.DomWidget.getContainerWidth");
},
createNodesFromText: function(){
dojo.unimplemented("dojo.widget.DomWidget.createNodesFromText");
}
});
dojo.provide("dojo.html.common");
dojo.lang.mixin(dojo.html, dojo.dom);
dojo.html.body = function(){
dojo.deprecated("dojo.html.body() moved to dojo.body()", "0.5");
return dojo.body();
}
// FIXME: we are going to assume that we can throw any and every rendering
// engine into the IE 5.x box model. In Mozilla, we do this w/ CSS.
// Need to investigate for KHTML and Opera
dojo.html.getEventTarget = function(evt){
if(!evt) { evt = dojo.global().event || {} };
var t = (evt.srcElement ? evt.srcElement : (evt.target ? evt.target : null));
while((t)&&(t.nodeType!=1)){ t = t.parentNode; }
return t;
}
dojo.html.getViewport = function(){
var _window = dojo.global();
var _document = dojo.doc();
var w = 0;
var h = 0;
if(dojo.render.html.mozilla){
// mozilla
w = _document.documentElement.clientWidth;
h = _window.innerHeight;
}else if(!dojo.render.html.opera && _window.innerWidth){
//in opera9, dojo.body().clientWidth should be used, instead
//of window.innerWidth/document.documentElement.clientWidth
//so we have to check whether it is opera
w = _window.innerWidth;
h = _window.innerHeight;
} else if (!dojo.render.html.opera && dojo.exists(_document, "documentElement.clientWidth")){
// IE6 Strict
var w2 = _document.documentElement.clientWidth;
// this lets us account for scrollbars
if(!w || w2 && w2 < w) {
w = w2;
}
h = _document.documentElement.clientHeight;
} else if (dojo.body().clientWidth){
// IE, Opera
w = dojo.body().clientWidth;
h = dojo.body().clientHeight;
}
return { width: w, height: h };
}
dojo.html.getScroll = function(){
var _window = dojo.global();
var _document = dojo.doc();
var top = _window.pageYOffset || _document.documentElement.scrollTop || dojo.body().scrollTop || 0;
var left = _window.pageXOffset || _document.documentElement.scrollLeft || dojo.body().scrollLeft || 0;
return {
top: top,
left: left,
offset:{ x: left, y: top } // note the change, NOT an Array with added properties.
};
}
dojo.html.getParentByType = function(node, type) {
var _document = dojo.doc();
var parent = dojo.byId(node);
type = type.toLowerCase();
while((parent)&&(parent.nodeName.toLowerCase()!=type)){
if(parent==(_document["body"]||_document["documentElement"])){
return null;
}
parent = parent.parentNode;
}
return parent;
}
dojo.html.getAttribute = function(node, attr){
node = dojo.byId(node);
// FIXME: need to add support for attr-specific accessors
if((!node)||(!node.getAttribute)){
// if(attr !== 'nwType'){
// alert("getAttr of '" + attr + "' with bad node");
// }
return null;
}
var ta = typeof attr == 'string' ? attr : new String(attr);
// first try the approach most likely to succeed
var v = node.getAttribute(ta.toUpperCase());
if((v)&&(typeof v == 'string')&&(v!="")){ return v; }
// try returning the attributes value, if we couldn't get it as a string
if(v && v.value){ return v.value; }
// this should work on Opera 7, but it's a little on the crashy side
if((node.getAttributeNode)&&(node.getAttributeNode(ta))){
return (node.getAttributeNode(ta)).value;
}else if(node.getAttribute(ta)){
return node.getAttribute(ta);
}else if(node.getAttribute(ta.toLowerCase())){
return node.getAttribute(ta.toLowerCase());
}
return null;
}
/**
* Determines whether or not the specified node carries a value for the
* attribute in question.
*/
dojo.html.hasAttribute = function(node, attr){
return dojo.html.getAttribute(dojo.byId(node), attr) ? true : false;
}
/**
* Returns the mouse position relative to the document (not the viewport).
* For example, if you have a document that is 10000px tall,
* but your browser window is only 100px tall,
* if you scroll to the bottom of the document and call this function it
* will return {x: 0, y: 10000}
*/
dojo.html.getCursorPosition = function(e){
e = e || dojo.global().event;
var cursor = {x:0, y:0};
if(e.pageX || e.pageY){
cursor.x = e.pageX;
cursor.y = e.pageY;
}else{
var de = dojo.doc().documentElement;
var db = dojo.body();
cursor.x = e.clientX + ((de||db)["scrollLeft"]) - ((de||db)["clientLeft"]);
cursor.y = e.clientY + ((de||db)["scrollTop"]) - ((de||db)["clientTop"]);
}
return cursor;
}
/**
* Like dojo.dom.isTag, except case-insensitive
**/
dojo.html.isTag = function(node /* ... */) {
node = dojo.byId(node);
if(node && node.tagName) {
for (var i=1; i<arguments.length; i++){
if (node.tagName.toLowerCase()==String(arguments[i]).toLowerCase()){
return String(arguments[i]).toLowerCase();
}
}
}
return "";
}
//define dojo.html.createExternalElement for IE to workaround the annoying activation "feature" in new IE
//details: http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/overview/activating_activex.asp
if(dojo.render.html.ie){
//only define createExternalElement for IE in none https to avoid "mixed content" warning dialog
if(window.location.href.substr(0,6).toLowerCase() != "https:"){
(function(){
//The trick is to define a function in a script.src property:
// <script src="javascript:'function createExternalElement(){...}'"></script>,
//which will be treated as an external javascript file in IE
var xscript = dojo.doc().createElement('script');
xscript.src = "javascript:'dojo.html.createExternalElement=function(doc, tag){return doc.createElement(tag);}'";
dojo.doc().getElementsByTagName("head")[0].appendChild(xscript);
})();
}
}else{
//for other browsers, simply use document.createElement
//is enough
dojo.html.createExternalElement = function(doc, tag){
return doc.createElement(tag);
}
}
dojo.html._callDeprecated = function(inFunc, replFunc, args, argName, retValue){
dojo.deprecated("dojo.html." + inFunc,
"replaced by dojo.html." + replFunc + "(" + (argName ? "node, {"+ argName + ": " + argName + "}" : "" ) + ")" + (retValue ? "." + retValue : ""), "0.5");
var newArgs = [];
if(argName){ var argsIn = {}; argsIn[argName] = args[1]; newArgs.push(args[0]); newArgs.push(argsIn); }
else { newArgs = args }
var ret = dojo.html[replFunc].apply(dojo.html, args);
if(retValue){ return ret[retValue]; }
else { return ret; }
}
dojo.html.getViewportWidth = function(){
return dojo.html._callDeprecated("getViewportWidth", "getViewport", arguments, null, "width");
}
dojo.html.getViewportHeight = function(){
return dojo.html._callDeprecated("getViewportHeight", "getViewport", arguments, null, "height");
}
dojo.html.getViewportSize = function(){
return dojo.html._callDeprecated("getViewportSize", "getViewport", arguments);
}
dojo.html.getScrollTop = function(){
return dojo.html._callDeprecated("getScrollTop", "getScroll", arguments, null, "top");
}
dojo.html.getScrollLeft = function(){
return dojo.html._callDeprecated("getScrollLeft", "getScroll", arguments, null, "left");
}
dojo.html.getScrollOffset = function(){
return dojo.html._callDeprecated("getScrollOffset", "getScroll", arguments, null, "offset");
}
dojo.provide("dojo.html.layout");
dojo.html.sumAncestorProperties = function(node, prop){
node = dojo.byId(node);
if(!node){ return 0; } // FIXME: throw an error?
var retVal = 0;
while(node){
if(dojo.html.getComputedStyle(node, 'position') == 'fixed'){
return 0;
}
var val = node[prop];
if(val){
retVal += val - 0;
if(node==dojo.body()){ break; }// opera and khtml #body & #html has the same values, we only need one value
}
node = node.parentNode;
}
return retVal;
}
dojo.html.setStyleAttributes = function(node, attributes) {
node = dojo.byId(node);
var splittedAttribs=attributes.replace(/(;)?\s*$/, "").split(";");
for(var i=0; i<splittedAttribs.length; i++){
var nameValue=splittedAttribs[i].split(":");
var name=nameValue[0].replace(/\s*$/, "").replace(/^\s*/, "").toLowerCase();
var value=nameValue[1].replace(/\s*$/, "").replace(/^\s*/, "");
switch(name){
case "opacity":
dojo.html.setOpacity(node, value);
break;
case "content-height":
dojo.html.setContentBox(node, {height: value});
break;
case "content-width":
dojo.html.setContentBox(node, {width: value});
break;
case "outer-height":
dojo.html.setMarginBox(node, {height: value});
break;
case "outer-width":
dojo.html.setMarginBox(node, {width: value});
break;
default:
node.style[dojo.html.toCamelCase(name)]=value;
}
}
}
dojo.html.boxSizing = {
MARGIN_BOX: "margin-box",
BORDER_BOX: "border-box",
PADDING_BOX: "padding-box",
CONTENT_BOX: "content-box"
};
dojo.html.getAbsolutePosition = dojo.html.abs = function(node, includeScroll, boxType){
node = dojo.byId(node, node.ownerDocument);
var ret = {
x: 0,
y: 0
};
var bs = dojo.html.boxSizing;
if(!boxType) { boxType = bs.CONTENT_BOX; }
var nativeBoxType = 2; //BORDER box
var targetBoxType;
switch(boxType){
case bs.MARGIN_BOX:
targetBoxType = 3;
break;
case bs.BORDER_BOX:
targetBoxType = 2;
break;
case bs.PADDING_BOX:
default:
targetBoxType = 1;
break;
case bs.CONTENT_BOX:
targetBoxType = 0;
break;
}
var h = dojo.render.html;
var db = document["body"]||document["documentElement"];
if(h.ie){
with(node.getBoundingClientRect()){
ret.x = left-2;
ret.y = top-2;
}
}else if(document.getBoxObjectFor){
// mozilla
nativeBoxType = 1; //getBoxObjectFor return padding box coordinate
try{
var bo = document.getBoxObjectFor(node);
ret.x = bo.x - dojo.html.sumAncestorProperties(node, "scrollLeft");
ret.y = bo.y - dojo.html.sumAncestorProperties(node, "scrollTop");
}catch(e){
// squelch
}
}else{
if(node["offsetParent"]){
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
if( (h.safari)&&
(node.style.getPropertyValue("position") == "absolute")&&
(node.parentNode == db)){
endNode = db;
}else{
endNode = db.parentNode;
}
//TODO: set correct nativeBoxType for safari/konqueror
if(node.parentNode != db){
var nd = node;
if(dojo.render.html.opera){ nd = db; }
ret.x -= dojo.html.sumAncestorProperties(nd, "scrollLeft");
ret.y -= dojo.html.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(!h.opera || 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 != null));
}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(includeScroll){
var scroll = dojo.html.getScroll();
ret.y += scroll.top;
ret.x += scroll.left;
}
var extentFuncArray=[dojo.html.getPaddingExtent, dojo.html.getBorderExtent, dojo.html.getMarginExtent];
if(nativeBoxType > targetBoxType){
for(var i=targetBoxType;i<nativeBoxType;++i){
ret.y += extentFuncArray[i](node, 'top');
ret.x += extentFuncArray[i](node, 'left');
}
}else if(nativeBoxType < targetBoxType){
for(var i=targetBoxType;i>nativeBoxType;--i){
ret.y -= extentFuncArray[i-1](node, 'top');
ret.x -= extentFuncArray[i-1](node, 'left');
}
}
ret.top = ret.y;
ret.left = ret.x;
return ret;
}
dojo.html.isPositionAbsolute = function(node){
return (dojo.html.getComputedStyle(node, 'position') == 'absolute')
}
dojo.html._sumPixelValues = function(node, selectors, autoIsZero){
var total = 0;
for(var x=0; x<selectors.length; x++){
total += dojo.html.getPixelValue(node, selectors[x], autoIsZero);
}
return total;
}
dojo.html.getMargin = function(node){
return {
width: dojo.html._sumPixelValues(node, ["margin-left", "margin-right"], (dojo.html.getComputedStyle(node, 'position') == 'absolute')),
height: dojo.html._sumPixelValues(node, ["margin-top", "margin-bottom"], (dojo.html.getComputedStyle(node, 'position') == 'absolute'))
};
}
dojo.html.getBorder = function(node){
return {
width: dojo.html.getBorderExtent(node, 'left') + dojo.html.getBorderExtent(node, 'right'),
height: dojo.html.getBorderExtent(node, 'top') + dojo.html.getBorderExtent(node, 'bottom')
};
}
dojo.html.getBorderExtent = function(node, side){
return (dojo.html.getStyle(node, 'border-' + side + '-style') == 'none' ? 0 : dojo.html.getPixelValue(node, 'border-' + side + '-width'));
}
dojo.html.getMarginExtent = function(node, side){
return dojo.html._sumPixelValues(node, ["margin-" + side], dojo.html.isPositionAbsolute(node));
}
dojo.html.getPaddingExtent = function(node, side){
return dojo.html._sumPixelValues(node, ["padding-" + side], true);
}
dojo.html.getPadding = function(node){
return {
width: dojo.html._sumPixelValues(node, ["padding-left", "padding-right"], true),
height: dojo.html._sumPixelValues(node, ["padding-top", "padding-bottom"], true)
};
}
dojo.html.getPadBorder = function(node){
var pad = dojo.html.getPadding(node);
var border = dojo.html.getBorder(node);
return { width: pad.width + border.width, height: pad.height + border.height };
}
dojo.html.getBoxSizing = function(node){
var h = dojo.render.html;
var bs = dojo.html.boxSizing;
if((h.ie)||(h.opera)){
var cm = document["compatMode"];
if((cm == "BackCompat")||(cm == "QuirksMode")){
return bs.BORDER_BOX;
}else{
return bs.CONTENT_BOX;
}
}else{
if(arguments.length == 0){ node = document.documentElement; }
var sizing = dojo.html.getStyle(node, "-moz-box-sizing");
if(!sizing){ sizing = dojo.html.getStyle(node, "box-sizing"); }
return (sizing ? sizing : bs.CONTENT_BOX);
}
}
dojo.html.isBorderBox = function(node){
return (dojo.html.getBoxSizing(node) == dojo.html.boxSizing.BORDER_BOX);
}
dojo.html.getBorderBox = function(node){
node = dojo.byId(node);
return { width: node.offsetWidth, height: node.offsetHeight };
}
dojo.html.getPaddingBox = function(node){
var box = dojo.html.getBorderBox(node);
var border = dojo.html.getBorder(node);
return {
width: box.width - border.width,
height:box.height - border.height
};
}
dojo.html.getContentBox = function(node){
node = dojo.byId(node);
var padborder = dojo.html.getPadBorder(node);
return {
width: node.offsetWidth - padborder.width,
height: node.offsetHeight - padborder.height
};
}
dojo.html.setContentBox = function(node, args){
node = dojo.byId(node);
var width = 0; var height = 0;
var isbb = dojo.html.isBorderBox(node);
var padborder = (isbb ? dojo.html.getPadBorder(node) : { width: 0, height: 0});
var ret = {};
if(typeof args.width != undefined){
width = args.width + padborder.width;
ret.width = dojo.html.setPositivePixelValue(node, "width", width);
}
if(typeof args.height != undefined){
height = args.height + padborder.height;
ret.height = dojo.html.setPositivePixelValue(node, "height", height);
}
return ret;
}
dojo.html.getMarginBox = function(node){
var borderbox = dojo.html.getBorderBox(node);
var margin = dojo.html.getMargin(node);
return { width: borderbox.width + margin.width, height: borderbox.height + margin.height };
}
dojo.html.setMarginBox = function(node, args){
node = dojo.byId(node);
var width = 0; var height = 0;
var isbb = dojo.html.isBorderBox(node);
var padborder = (!isbb ? dojo.html.getPadBorder(node) : { width: 0, height: 0 });
var margin = dojo.html.getMargin(node);
var ret = {};
if(typeof args.width != undefined){
width = args.width - padborder.width;
width -= margin.width;
ret.width = dojo.html.setPositivePixelValue(node, "width", width);
}
if(typeof args.height != undefined){
height = args.height - padborder.height;
height -= margin.height;
ret.height = dojo.html.setPositivePixelValue(node, "height", height);
}
return ret;
}
dojo.html.getElementBox = function(node, type){
var bs = dojo.html.boxSizing;
switch(type){
case bs.MARGIN_BOX:
return dojo.html.getMarginBox(node);
case bs.BORDER_BOX:
return dojo.html.getBorderBox(node);
case bs.PADDING_BOX:
return dojo.html.getPaddingBox(node);
case bs.CONTENT_BOX:
default:
return dojo.html.getContentBox(node);
}
}
// in: coordinate array [x,y,w,h] or dom node
// return: coordinate object
dojo.html.toCoordinateObject = dojo.html.toCoordinateArray = function(coords, includeScroll) {
if(coords instanceof Array || typeof coords == "array"){
dojo.deprecated("dojo.html.toCoordinateArray", "use dojo.html.toCoordinateObject({left: , top: , width: , height: }) instead", "0.5");
// coords is already an array (of format [x,y,w,h]), just return it
while ( coords.length < 4 ) { coords.push(0); }
while ( coords.length > 4 ) { coords.pop(); }
var ret = {
left: coords[0],
top: coords[1],
width: coords[2],
height: coords[3]
};
}else if(!coords.nodeType && !(coords instanceof String || typeof coords == "string") &&
('width' in coords || 'height' in coords || 'left' in coords ||
'x' in coords || 'top' in coords || 'y' in coords)){
// coords is a coordinate object or at least part of one
var ret = {
left: coords.left||coords.x||0,
top: coords.top||coords.y||0,
width: coords.width||0,
height: coords.height||0
};
}else{
// coords is an dom object (or dom object id); return it's coordinates
var node = dojo.byId(coords);
var pos = dojo.html.abs(node, includeScroll);
var marginbox = dojo.html.getMarginBox(node);
var ret = {
left: pos.left,
top: pos.top,
width: marginbox.width,
height: marginbox.height
};
}
ret.x = ret.left;
ret.y = ret.top;
return ret;
}
dojo.html.setMarginBoxWidth = dojo.html.setOuterWidth = function(node, width){
return dojo.html._callDeprecated("setMarginBoxWidth", "setMarginBox", arguments, "width");
}
dojo.html.setMarginBoxHeight = dojo.html.setOuterHeight = function(){
return dojo.html._callDeprecated("setMarginBoxHeight", "setMarginBox", arguments, "height");
}
dojo.html.getMarginBoxWidth = dojo.html.getOuterWidth = function(){
return dojo.html._callDeprecated("getMarginBoxWidth", "getMarginBox", arguments, null, "width");
}
dojo.html.getMarginBoxHeight = dojo.html.getOuterHeight = function(){
return dojo.html._callDeprecated("getMarginBoxHeight", "getMarginBox", arguments, null, "height");
}
dojo.html.getTotalOffset = function(node, type, includeScroll){
return dojo.html._callDeprecated("getTotalOffset", "getAbsolutePosition", arguments, null, type);
}
dojo.html.getAbsoluteX = function(node, includeScroll){
return dojo.html._callDeprecated("getAbsoluteX", "getAbsolutePosition", arguments, null, "x");
}
dojo.html.getAbsoluteY = function(node, includeScroll){
return dojo.html._callDeprecated("getAbsoluteY", "getAbsolutePosition", arguments, null, "y");
}
dojo.html.totalOffsetLeft = function(node, includeScroll){
return dojo.html._callDeprecated("totalOffsetLeft", "getAbsolutePosition", arguments, null, "left");
}
dojo.html.totalOffsetTop = function(node, includeScroll){
return dojo.html._callDeprecated("totalOffsetTop", "getAbsolutePosition", arguments, null, "top");
}
dojo.html.getMarginWidth = function(node){
return dojo.html._callDeprecated("getMarginWidth", "getMargin", arguments, null, "width");
}
dojo.html.getMarginHeight = function(node){
return dojo.html._callDeprecated("getMarginHeight", "getMargin", arguments, null, "height");
}
dojo.html.getBorderWidth = function(node){
return dojo.html._callDeprecated("getBorderWidth", "getBorder", arguments, null, "width");
}
dojo.html.getBorderHeight = function(node){
return dojo.html._callDeprecated("getBorderHeight", "getBorder", arguments, null, "height");
}
dojo.html.getPaddingWidth = function(node){
return dojo.html._callDeprecated("getPaddingWidth", "getPadding", arguments, null, "width");
}
dojo.html.getPaddingHeight = function(node){
return dojo.html._callDeprecated("getPaddingHeight", "getPadding", arguments, null, "height");
}
dojo.html.getPadBorderWidth = function(node){
return dojo.html._callDeprecated("getPadBorderWidth", "getPadBorder", arguments, null, "width");
}
dojo.html.getPadBorderHeight = function(node){
return dojo.html._callDeprecated("getPadBorderHeight", "getPadBorder", arguments, null, "height");
}
dojo.html.getBorderBoxWidth = dojo.html.getInnerWidth = function(){
return dojo.html._callDeprecated("getBorderBoxWidth", "getBorderBox", arguments, null, "width");
}
dojo.html.getBorderBoxHeight = dojo.html.getInnerHeight = function(){
return dojo.html._callDeprecated("getBorderBoxHeight", "getBorderBox", arguments, null, "height");
}
dojo.html.getContentBoxWidth = dojo.html.getContentWidth = function(){
return dojo.html._callDeprecated("getContentBoxWidth", "getContentBox", arguments, null, "width");
}
dojo.html.getContentBoxHeight = dojo.html.getContentHeight = function(){
return dojo.html._callDeprecated("getContentBoxHeight", "getContentBox", arguments, null, "height");
}
dojo.html.setContentBoxWidth = dojo.html.setContentWidth = function(node, width){
return dojo.html._callDeprecated("setContentBoxWidth", "setContentBox", arguments, "width");
}
dojo.html.setContentBoxHeight = dojo.html.setContentHeight = function(node, height){
return dojo.html._callDeprecated("setContentBoxHeight", "setContentBox", arguments, "height");
}
dojo.provide("dojo.html.util");
// Get the window object where the element is placed in.
dojo.html.getElementWindow = function(element){
return dojo.html.getDocumentWindow( element.ownerDocument );
}
// Get window object associated with document doc
dojo.html.getDocumentWindow = function(doc){
// With Safari, there is not wa to retrieve the window from the document, so we must fix it.
if(dojo.render.html.safari && !doc._parentWindow){
/*
This is a Safari specific function that fix the reference to the parent
window from the document object.
*/
var fix=function(win){
win.document._parentWindow=win;
for(var i=0; i<win.frames.length; i++){
fix(win.frames[i]);
}
}
fix(window.top);
}
//In some IE versions (at least 6.0), document.parentWindow does not return a
//reference to the real window object (maybe a copy), so we must fix it as well
if(dojo.render.html.ie && window !== document.parentWindow && !doc._parentWindow){
/*
In IE 6, only the variable "window" can be used to connect events (others
may be only copies). We use IE specific execScript to attach the real window
reference to document._parentWindow for later use
*/
doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
}
return doc._parentWindow || doc.parentWindow || doc.defaultView;
}
/**
* Calculates the mouse's direction of gravity relative to the centre
* of the given node.
* <p>
* If you wanted to insert a node into a DOM tree based on the mouse
* position you might use the following code:
* <pre>
* if (gravity(node, e) & gravity.NORTH) { [insert before]; }
* else { [insert after]; }
* </pre>
*
* @param node The node
* @param e The event containing the mouse coordinates
* @return The directions, NORTH or SOUTH and EAST or WEST. These
* are properties of the function.
*/
dojo.html.gravity = function(node, e){
node = dojo.byId(node);
var mouse = dojo.html.getCursorPosition(e);
with (dojo.html) {
var absolute = getAbsolutePosition(node, true);
var bb = getBorderBox(node);
var nodecenterx = absolute.x + (bb.width / 2);
var nodecentery = absolute.y + (bb.height / 2);
}
with (dojo.html.gravity) {
return ((mouse.x < nodecenterx ? WEST : EAST) |
(mouse.y < nodecentery ? NORTH : SOUTH));
}
}
dojo.html.gravity.NORTH = 1;
dojo.html.gravity.SOUTH = 1 << 1;
dojo.html.gravity.EAST = 1 << 2;
dojo.html.gravity.WEST = 1 << 3;
dojo.html.overElement = function(element, e){
element = dojo.byId(element);
var mouse = dojo.html.getCursorPosition(e);
with(dojo.html){
var bb = getBorderBox(element);
var absolute = getAbsolutePosition(element, true);
var top = absolute.y;
var bottom = top + bb.height;
var left = absolute.x;
var right = left + bb.width;
}
return (mouse.x >= left && mouse.x <= right &&
mouse.y >= top && mouse.y <= bottom);
}
/**
* Attempts to return the text as it would be rendered, with the line breaks
* sorted out nicely. Unfinished.
*/
dojo.html.renderedTextContent = function(node){
node = dojo.byId(node);
var result = "";
if (node == null) { return result; }
for (var i = 0; i < node.childNodes.length; i++) {
switch (node.childNodes[i].nodeType) {
case 1: // ELEMENT_NODE
case 5: // ENTITY_REFERENCE_NODE
var display = "unknown";
try {
display = dojo.html.getStyle(node.childNodes[i], "display");
} catch(E) {}
switch (display) {
case "block": case "list-item": case "run-in":
case "table": case "table-row-group": case "table-header-group":
case "table-footer-group": case "table-row": case "table-column-group":
case "table-column": case "table-cell": case "table-caption":
// TODO: this shouldn't insert double spaces on aligning blocks
result += "\n";
result += dojo.html.renderedTextContent(node.childNodes[i]);
result += "\n";
break;
case "none": break;
default:
if(node.childNodes[i].tagName && node.childNodes[i].tagName.toLowerCase() == "br") {
result += "\n";
} else {
result += dojo.html.renderedTextContent(node.childNodes[i]);
}
break;
}
break;
case 3: // TEXT_NODE
case 2: // ATTRIBUTE_NODE
case 4: // CDATA_SECTION_NODE
var text = node.childNodes[i].nodeValue;
var textTransform = "unknown";
try {
textTransform = dojo.html.getStyle(node, "text-transform");
} catch(E) {}
switch (textTransform){
case "capitalize":
var words = text.split(' ');
for(var i=0; i<words.length; i++){
words[i] = words[i].charAt(0).toUpperCase() + words[i].substring(1);
}
text = words.join(" ");
break;
case "uppercase": text = text.toUpperCase(); break;
case "lowercase": text = text.toLowerCase(); break;
default: break; // leave as is
}
// TODO: implement
switch (textTransform){
case "nowrap": break;
case "pre-wrap": break;
case "pre-line": break;
case "pre": break; // leave as is
default:
// remove whitespace and collapse first space
text = text.replace(/\s+/, " ");
if (/\s$/.test(result)) { text.replace(/^\s/, ""); }
break;
}
result += text;
break;
default:
break;
}
}
return result;
}
dojo.html.createNodesFromText = function(txt, trim){
if(trim) { txt = txt.replace(/^\s+|\s+$/g, ""); }
var tn = dojo.doc().createElement("div");
// tn.style.display = "none";
tn.style.visibility= "hidden";
dojo.body().appendChild(tn);
var tableType = "none";
if((/^<t[dh][\s\r\n>]/i).test(txt.replace(/^\s+/))) {
txt = "<table><tbody><tr>" + txt + "</tr></tbody></table>";
tableType = "cell";
} else if((/^<tr[\s\r\n>]/i).test(txt.replace(/^\s+/))) {
txt = "<table><tbody>" + txt + "</tbody></table>";
tableType = "row";
} else if((/^<(thead|tbody|tfoot)[\s\r\n>]/i).test(txt.replace(/^\s+/))) {
txt = "<table>" + txt + "</table>";
tableType = "section";
}
tn.innerHTML = txt;
if(tn["normalize"]){
tn.normalize();
}
var parent = null;
switch(tableType) {
case "cell":
parent = tn.getElementsByTagName("tr")[0];
break;
case "row":
parent = tn.getElementsByTagName("tbody")[0];
break;
case "section":
parent = tn.getElementsByTagName("table")[0];
break;
default:
parent = tn;
break;
}
/* this doesn't make much sense, I'm assuming it just meant trim() so wrap was replaced with trim
if(wrap){
var ret = [];
// start hack
var fc = tn.firstChild;
ret[0] = ((fc.nodeValue == " ")||(fc.nodeValue == "\t")) ? fc.nextSibling : fc;
// end hack
// tn.style.display = "none";
dojo.body().removeChild(tn);
return ret;
}
*/
var nodes = [];
for(var x=0; x<parent.childNodes.length; x++){
nodes.push(parent.childNodes[x].cloneNode(true));
}
tn.style.display = "none"; // FIXME: why do we do this?
dojo.body().removeChild(tn);
return nodes;
}
/* TODO: make this function have variable call sigs
*
* kes(node, ptArray, cornerArray, padding, hasScroll)
* kes(node, ptX, ptY, cornerA, cornerB, cornerC, paddingArray, hasScroll)
*/
/**
* Keeps 'node' in the visible area of the screen while trying to
* place closest to desiredX, desiredY. The input coordinates are
* expected to be the desired screen position, not accounting for
* scrolling. If you already accounted for scrolling, set 'hasScroll'
* to true. Set padding to either a number or array for [paddingX, paddingY]
* to put some buffer around the element you want to position.
* Set which corner(s) you want to bind to, such as
*
* placeOnScreen(node, desiredX, desiredY, padding, hasScroll, "TR")
* placeOnScreen(node, [desiredX, desiredY], padding, hasScroll, ["TR", "BL"])
*
* The desiredX/desiredY will be treated as the topleft(TL)/topright(TR) or
* BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested
* and if a perfect match is found, it will be used. Otherwise, it goes through
* all of the specified corners, and choose the most appropriate one.
* By default, corner = ['TL'].
* If tryOnly is set to true, the node will not be moved to the place.
*
* NOTE: node is assumed to be absolutely or relatively positioned.
*
* Alternate call sig:
* placeOnScreen(node, [x, y], padding, hasScroll)
*
* Examples:
* placeOnScreen(node, 100, 200)
* placeOnScreen("myId", [800, 623], 5)
* placeOnScreen(node, 234, 3284, [2, 5], true)
*/
dojo.html.placeOnScreen = function(node, desiredX, desiredY, padding, hasScroll, corners, tryOnly) {
if(desiredX instanceof Array || typeof desiredX == "array") {
tryOnly = corners;
corners = hasScroll;
hasScroll = padding;
padding = desiredY;
desiredY = desiredX[1];
desiredX = desiredX[0];
}
if(corners instanceof String || typeof corners == "string"){
corners = corners.split(",");
}
if(!isNaN(padding)) {
padding = [Number(padding), Number(padding)];
} else if(!(padding instanceof Array || typeof padding == "array")) {
padding = [0, 0];
}
var scroll = dojo.html.getScroll().offset;
var view = dojo.html.getViewport();
node = dojo.byId(node);
var oldDisplay = node.style.display;
node.style.display="";
var bb = dojo.html.getBorderBox(node);
var w = bb.width;
var h = bb.height;
node.style.display=oldDisplay;
if(!(corners instanceof Array || typeof corners == "array")){
corners = ['TL'];
}
var bestx, besty, bestDistance = Infinity;
for(var cidex=0; cidex<corners.length; ++cidex){
var corner = corners[cidex];
var match = true;
var tryX = desiredX - (corner.charAt(1)=='L' ? 0 : w) + padding[0] * (corner.charAt(1)=='L' ? 1 : -1);
var tryY = desiredY - (corner.charAt(0)=='T' ? 0 : h) + padding[1] * (corner.charAt(0)=='T' ? 1 : -1);
if(hasScroll) {
tryX -= scroll.x;
tryY -= scroll.y;
}
var x = tryX + w;
if(x > view.width) {
x = view.width - w;
match = false;
} else {
x = tryX;
}
x = Math.max(padding[0], x) + scroll.x;
var y = tryY + h;
if(y > view.height) {
y = view.height - h;
match = false;
} else {
y = tryY;
}
y = Math.max(padding[1], y) + scroll.y;
if(match){ //perfect match, return now
bestx = x;
besty = y;
bestDistance = 0;
break;
}else{
//not perfect, find out whether it is better than the saved one
var dist = Math.pow(x-tryX-scroll.x,2)+Math.pow(y-tryY-scroll.y,2);
if(bestDistance > dist){
bestDistance = dist;
bestx = x;
besty = y;
}
}
}
if(!tryOnly){
node.style.left = bestx + "px";
node.style.top = besty + "px";
}
return { left: bestx, top: besty, x: bestx, y: besty, dist: bestDistance };
}
/**
* Like placeOnScreenPoint except that it attempts to keep one of the node's
* corners at desiredX, desiredY. Favors the bottom right position
*
* Examples placing node at mouse position (where e = [Mouse event]):
* placeOnScreenPoint(node, e.clientX, e.clientY);
*/
dojo.html.placeOnScreenPoint = function(node, desiredX, desiredY, padding, hasScroll) {
dojo.deprecated("dojo.html.placeOnScreenPoint", "use dojo.html.placeOnScreen() instead", "0.5");
return dojo.html.placeOnScreen(node, desiredX, desiredY, padding, hasScroll, ['TL', 'TR', 'BL', 'BR']);
}
/**
* Like placeOnScreen, except it accepts aroundNode instead of x.y
* and attempts to place node around it. aroundType (see
* dojo.html.boxSizing in html/layout.js) determines which box of the
* aroundNode should be used to calculate the outer box.
* aroundCorners specify Which corner of aroundNode should be
* used to place the node => which corner(s) of node to use (see the
* corners parameter in dojo.html.placeOnScreen)
* aroundCorners: {'TL': 'BL', 'BL': 'TL'}
*/
dojo.html.placeOnScreenAroundElement = function(node, aroundNode, padding, aroundType, aroundCorners, tryOnly){
var best, bestDistance=Infinity;
aroundNode = dojo.byId(aroundNode);
var oldDisplay = aroundNode.style.display;
aroundNode.style.display="";
var mb = dojo.html.getElementBox(aroundNode, aroundType);
var aroundNodeW = mb.width;
var aroundNodeH = mb.height;
var aroundNodePos = dojo.html.getAbsolutePosition(aroundNode, true, aroundType);
aroundNode.style.display=oldDisplay;
for(var nodeCorner in aroundCorners){
var pos, desiredX, desiredY;
var corners = aroundCorners[nodeCorner];
desiredX = aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW);
desiredY = aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH);
pos = dojo.html.placeOnScreen(node, desiredX, desiredY, padding, true, corners, true);
if(pos.dist == 0){
best = pos;
break;
}else{
//not perfect, find out whether it is better than the saved one
if(bestDistance > pos.dist){
bestDistance = pos.dist;
best = pos;
}
}
}
if(!tryOnly){
node.style.left = best.left + "px";
node.style.top = best.top + "px";
}
return best;
}
//scrollIntoView in some implementation is broken, use our own
dojo.html.scrollIntoView = function(node){
if(!node){ return; }
// don't rely on that node.scrollIntoView works just because the function is there
// it doesnt work in Konqueror or Opera even though the function is there and probably
// not safari either
// dont like browser sniffs implementations but sometimes you have to use it
if(dojo.render.html.ie){
//only call scrollIntoView if there is a scrollbar for this menu,
//otherwise, scrollIntoView will scroll the window scrollbar
if(dojo.html.getBorderBox(node.parentNode).height < node.parentNode.scrollHeight){
node.scrollIntoView(false);
}
}else if(dojo.render.html.mozilla){
// IE, mozilla
node.scrollIntoView(false);
}else{
var parent = node.parentNode;
var parentBottom = parent.scrollTop + dojo.html.getBorderBox(parent).height;
var nodeBottom = node.offsetTop + dojo.html.getMarginBox(node).height;
if(parentBottom < nodeBottom){
parent.scrollTop += (nodeBottom - parentBottom);
}else if(parent.scrollTop > node.offsetTop){
parent.scrollTop -= (parent.scrollTop - node.offsetTop);
}
}
}
dojo.provide("dojo.html.display");
dojo.html._toggle = function(node, tester, setter){
node = dojo.byId(node);
setter(node, !tester(node));
return tester(node);
}
// show/hide are library constructs
// show()
// if the node.style.display == 'none' then
// set style.display to '' or the value cached by hide()
dojo.html.show = function(node){
node = dojo.byId(node);
if(dojo.html.getStyleProperty(node, 'display')=='none'){
dojo.html.setStyle(node, 'display', (node.dojoDisplayCache||''));
node.dojoDisplayCache = undefined; // cannot use delete on a node in IE6
}
}
// if the node.style.display == 'none' then
// set style.display to '' or the value cached by hide()
dojo.html.hide = function(node){
node = dojo.byId(node);
if(typeof node["dojoDisplayCache"] == "undefined"){ // it could == '', so we cannot say !node.dojoDisplayCount
var d = dojo.html.getStyleProperty(node, 'display')
if(d!='none'){
node.dojoDisplayCache = d;
}
}
dojo.html.setStyle(node, 'display', 'none');
}
// setShowing() calls show() if showing is true, hide() otherwise
dojo.html.setShowing = function(node, showing){
dojo.html[(showing ? 'show' : 'hide')](node);
}
// isShowing() is true if the node.style.display is not 'none'
// FIXME: returns true if node is bad, isHidden would be easier to make correct
dojo.html.isShowing = function(node){
return (dojo.html.getStyleProperty(node, 'display') != 'none');
}
// Call setShowing() on node with the complement of isShowing(), then return the new value of isShowing()
dojo.html.toggleShowing = function(node){
return dojo.html._toggle(node, dojo.html.isShowing, dojo.html.setShowing);
}
// display is a CSS concept
// Simple mapping of tag names to display values
// FIXME: simplistic
dojo.html.displayMap = { tr: '', td: '', th: '', img: 'inline', span: 'inline', input: 'inline', button: 'inline' };
// Suggest a value for the display property that will show 'node' based on it's tag
dojo.html.suggestDisplayByTagName = function(node)
{
node = dojo.byId(node);
if(node && node.tagName){
var tag = node.tagName.toLowerCase();
return (tag in dojo.html.displayMap ? dojo.html.displayMap[tag] : 'block');
}
}
// setDisplay() sets the value of style.display to value of 'display' parameter if it is a string.
// Otherwise, if 'display' is false, set style.display to 'none'.
// Finally, set 'display' to a suggested display value based on the node's tag
dojo.html.setDisplay = function(node, display){
dojo.html.setStyle(node, 'display', ((display instanceof String || typeof display == "string") ? display : (display ? dojo.html.suggestDisplayByTagName(node) : 'none')));
}
// isDisplayed() is true if the the computed display style for node is not 'none'
// FIXME: returns true if node is bad, isNotDisplayed would be easier to make correct
dojo.html.isDisplayed = function(node){
return (dojo.html.getComputedStyle(node, 'display') != 'none');
}
// Call setDisplay() on node with the complement of isDisplayed(), then
// return the new value of isDisplayed()
dojo.html.toggleDisplay = function(node){
return dojo.html._toggle(node, dojo.html.isDisplayed, dojo.html.setDisplay);
}
// visibility is a CSS concept
// setVisibility() sets the value of style.visibility to value of
// 'visibility' parameter if it is a string.
// Otherwise, if 'visibility' is false, set style.visibility to 'hidden'.
// Finally, set style.visibility to 'visible'.
dojo.html.setVisibility = function(node, visibility){
dojo.html.setStyle(node, 'visibility', ((visibility instanceof String || typeof visibility == "string") ? visibility : (visibility ? 'visible' : 'hidden')));
}
// isVisible() is true if the the computed visibility style for node is not 'hidden'
// FIXME: returns true if node is bad, isInvisible would be easier to make correct
dojo.html.isVisible = function(node){
return (dojo.html.getComputedStyle(node, 'visibility') != 'hidden');
}
// Call setVisibility() on node with the complement of isVisible(), then
// return the new value of isVisible()
dojo.html.toggleVisibility = function(node){
return dojo.html._toggle(node, dojo.html.isVisible, dojo.html.setVisibility);
}
/* float between 0.0 (transparent) and 1.0 (opaque) */
dojo.html.setOpacity = function(node, opacity, dontFixOpacity){
node = dojo.byId(node);
var h = dojo.render.html;
if(!dontFixOpacity){
if( opacity >= 1.0){
if(h.ie){
dojo.html.clearOpacity(node);
return;
}else{
opacity = 0.999999;
}
}else if( opacity < 0.0){ opacity = 0; }
}
if(h.ie){
if(node.nodeName.toLowerCase() == "tr"){
// FIXME: is this too naive? will we get more than we want?
var tds = node.getElementsByTagName("td");
for(var x=0; x<tds.length; x++){
tds[x].style.filter = "Alpha(Opacity="+opacity*100+")";
}
}
node.style.filter = "Alpha(Opacity="+opacity*100+")";
}else if(h.moz){
node.style.opacity = opacity; // ffox 1.0 directly supports "opacity"
node.style.MozOpacity = opacity;
}else if(h.safari){
node.style.opacity = opacity; // 1.3 directly supports "opacity"
node.style.KhtmlOpacity = opacity;
}else{
node.style.opacity = opacity;
}
}
dojo.html.clearOpacity = function clearOpacity(node){
node = dojo.byId(node);
var ns = node.style;
var h = dojo.render.html;
if(h.ie){
try {
if( node.filters && node.filters.alpha ){
ns.filter = ""; // FIXME: may get rid of other filter effects
}
} catch(e) {
/*
* IE7 gives error if node.filters not set;
* don't know why or how to workaround (other than this)
*/
}
}else if(h.moz){
ns.opacity = 1;
ns.MozOpacity = 1;
}else if(h.safari){
ns.opacity = 1;
ns.KhtmlOpacity = 1;
}else{
ns.opacity = 1;
}
}
dojo.html.getOpacity = function getOpacity (node){
node = dojo.byId(node);
var h = dojo.render.html;
if(h.ie){
var opac = (node.filters && node.filters.alpha &&
typeof node.filters.alpha.opacity == "number"
? node.filters.alpha.opacity : 100) / 100;
}else{
var opac = node.style.opacity || node.style.MozOpacity ||
node.style.KhtmlOpacity || 1;
}
return opac >= 0.999999 ? 1.0 : Number(opac);
}
dojo.provide("dojo.lfx.Animation");
dojo.provide("dojo.lfx.Line");
/*
Animation package based on Dan Pupius' work: http://pupius.co.uk/js/Toolkit.Drawing.js
*/
dojo.lfx.Line = function(start, end){
this.start = start;
this.end = end;
if(dojo.lang.isArray(start)){
var diff = [];
dojo.lang.forEach(this.start, function(s,i){
diff[i] = this.end[i] - s;
}, this);
this.getValue = function(/*float*/ n){
var res = [];
dojo.lang.forEach(this.start, function(s, i){
res[i] = (diff[i] * n) + s;
}, this);
return res;
}
}else{
var diff = end - start;
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 (diff * n) + this.start;
}
}
}
dojo.lfx.easeDefault = function(n){
// sin wave easing. All the cool kids are doing it.
return (0.5+((Math.sin( (n+1.5) * Math.PI))/2));
}
dojo.lfx.easeIn = function(n){
// summary: returns the point on an easing curve
// n: a floating point number greater than 0 and less than 1
return Math.pow(n, 3);
}
dojo.lfx.easeOut = function(n){
// summary: returns the point on the line
// n: a floating point number greater than 0 and less than 1
return ( 1 - Math.pow(1 - n, 3) );
}
dojo.lfx.easeInOut = function(n){
// summary: returns the point on the line
// n: a floating point number greater than 0 and less than 1
return ( (3 * Math.pow(n, 2)) - (2 * Math.pow(n, 3)) );
}
dojo.lfx.IAnimation = function(){}
dojo.lang.extend(dojo.lfx.IAnimation, {
// public properties
curve: null,
duration: 1000,
easing: null,
repeatCount: 0,
rate: 25,
// events
handler: null,
beforeBegin: null,
onBegin: null,
onAnimate: null,
onEnd: null,
onPlay: null,
onPause: null,
onStop: null,
// public methods
play: null,
pause: null,
stop: null,
connect: function(evt, scope, newFunc){
if(!newFunc){
newFunc = scope;
scope = this;
}
newFunc = dojo.lang.hitch(scope, newFunc);
var oldFunc = this[evt]||function(){};
this[evt] = function(){
var ret = oldFunc.apply(this, arguments);
newFunc.apply(this, arguments);
return ret;
}
return this;
},
fire: function(evt, args){
if(this[evt]){
this[evt].apply(this, (args||[]));
}
return this;
},
repeat: function(count){
this.repeatCount = count;
return this;
},
// private properties
_active: false,
_paused: false
});
dojo.lfx.Animation = function( /*Object*/ handlers,
/*int*/ duration,
/*Array*/ curve,
/*function*/ easing,
/*int*/ repeatCount,
/*int*/ rate){
// summary
// a generic animation object that fires callbacks into it's handlers
// object at various states
// handlers
// object {
// handler: function(){},
// onstart: function(){},
// onstop: function(){},
// onanimate: function(){}
// }
dojo.lfx.IAnimation.call(this);
if(dojo.lang.isNumber(handlers)||(!handlers && duration.getValue)){
// no handlers argument:
rate = repeatCount;
repeatCount = easing;
easing = curve;
curve = duration;
duration = handlers;
handlers = null;
}else if(handlers.getValue||dojo.lang.isArray(handlers)){
// no handlers or duration:
rate = easing;
repeatCount = curve;
easing = duration;
curve = handlers;
duration = null;
handlers = null;
}
if(dojo.lang.isArray(curve)){
this.curve = new dojo.lfx.Line(curve[0], curve[1]);
}else{
this.curve = curve;
}
if(duration != null && duration > 0){ this.duration = duration; }
if(repeatCount){ this.repeatCount = repeatCount; }
if(rate){ this.rate = rate; }
if(handlers){
dojo.lang.forEach([
"handler", "beforeBegin", "onBegin",
"onEnd", "onPlay", "onStop", "onAnimate"
], function(item){
if(handlers[item]){
this.connect(item, handlers[item]);
}
}, this);
}
if(easing && dojo.lang.isFunction(easing)){
this.easing=easing;
}
}
dojo.inherits(dojo.lfx.Animation, dojo.lfx.IAnimation);
dojo.lang.extend(dojo.lfx.Animation, {
// "private" properties
_startTime: null,
_endTime: null,
_timer: null,
_percent: 0,
_startRepeatCount: 0,
// public methods
play: function(delay, gotoStart){
if(gotoStart){
clearTimeout(this._timer);
this._active = false;
this._paused = false;
this._percent = 0;
}else if(this._active && !this._paused){
return this;
}
this.fire("handler", ["beforeBegin"]);
this.fire("beforeBegin");
if(delay > 0){
setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
return this;
}
this._startTime = new Date().valueOf();
if(this._paused){
this._startTime -= (this.duration * this._percent / 100);
}
this._endTime = this._startTime + this.duration;
this._active = true;
this._paused = false;
var step = this._percent / 100;
var value = this.curve.getValue(step);
if(this._percent == 0 ){
if(!this._startRepeatCount){
this._startRepeatCount = this.repeatCount;
}
this.fire("handler", ["begin", value]);
this.fire("onBegin", [value]);
}
this.fire("handler", ["play", value]);
this.fire("onPlay", [value]);
this._cycle();
return this;
},
pause: function(){
clearTimeout(this._timer);
if(!this._active){ return this; }
this._paused = true;
var value = this.curve.getValue(this._percent / 100);
this.fire("handler", ["pause", value]);
this.fire("onPause", [value]);
return this;
},
gotoPercent: function(pct, andPlay){
clearTimeout(this._timer);
this._active = true;
this._paused = true;
this._percent = pct;
if(andPlay){ this.play(); }
return this;
},
stop: function(gotoEnd){
clearTimeout(this._timer);
var step = this._percent / 100;
if(gotoEnd){
step = 1;
}
var value = this.curve.getValue(step);
this.fire("handler", ["stop", value]);
this.fire("onStop", [value]);
this._active = false;
this._paused = false;
return this;
},
status: function(){
if(this._active){
return this._paused ? "paused" : "playing";
}else{
return "stopped";
}
return this;
},
// "private" methods
_cycle: function(){
clearTimeout(this._timer);
if(this._active){
var curr = new Date().valueOf();
var step = (curr - this._startTime) / (this._endTime - this._startTime);
if(step >= 1){
step = 1;
this._percent = 100;
}else{
this._percent = step * 100;
}
// Perform easing
if((this.easing)&&(dojo.lang.isFunction(this.easing))){
step = this.easing(step);
}
var value = this.curve.getValue(step);
this.fire("handler", ["animate", value]);
this.fire("onAnimate", [value]);
if( step < 1 ){
this._timer = setTimeout(dojo.lang.hitch(this, "_cycle"), this.rate);
}else{
this._active = false;
this.fire("handler", ["end"]);
this.fire("onEnd");
if(this.repeatCount > 0){
this.repeatCount--;
this.play(null, true);
}else if(this.repeatCount == -1){
this.play(null, true);
}else{
if(this._startRepeatCount){
this.repeatCount = this._startRepeatCount;
this._startRepeatCount = 0;
}
}
}
}
return this;
}
});
dojo.lfx.Combine = function(){
dojo.lfx.IAnimation.call(this);
this._anims = [];
this._animsEnded = 0;
var anims = arguments;
if(anims.length == 1 && (dojo.lang.isArray(anims[0]) || dojo.lang.isArrayLike(anims[0]))){
anims = anims[0];
}
dojo.lang.forEach(anims, function(anim){
this._anims.push(anim);
anim.connect("onEnd", dojo.lang.hitch(this, "_onAnimsEnded"));
}, this);
}
dojo.inherits(dojo.lfx.Combine, dojo.lfx.IAnimation);
dojo.lang.extend(dojo.lfx.Combine, {
// private members
_animsEnded: 0,
// public methods
play: function(delay, gotoStart){
if( !this._anims.length ){ return this; }
this.fire("beforeBegin");
if(delay > 0){
setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
return this;
}
if(gotoStart || this._anims[0].percent == 0){
this.fire("onBegin");
}
this.fire("onPlay");
this._animsCall("play", null, gotoStart);
return this;
},
pause: function(){
this.fire("onPause");
this._animsCall("pause");
return this;
},
stop: function(gotoEnd){
this.fire("onStop");
this._animsCall("stop", gotoEnd);
return this;
},
// private methods
_onAnimsEnded: function(){
this._animsEnded++;
if(this._animsEnded >= this._anims.length){
this.fire("onEnd");
}
return this;
},
_animsCall: function(funcName){
var args = [];
if(arguments.length > 1){
for(var i = 1 ; i < arguments.length ; i++){
args.push(arguments[i]);
}
}
var _this = this;
dojo.lang.forEach(this._anims, function(anim){
anim[funcName](args);
}, _this);
return this;
}
});
dojo.lfx.Chain = function() {
dojo.lfx.IAnimation.call(this);
this._anims = [];
this._currAnim = -1;
var anims = arguments;
if(anims.length == 1 && (dojo.lang.isArray(anims[0]) || dojo.lang.isArrayLike(anims[0]))){
anims = anims[0];
}
var _this = this;
dojo.lang.forEach(anims, function(anim, i, anims_arr){
this._anims.push(anim);
if(i < anims_arr.length - 1){
anim.connect("onEnd", dojo.lang.hitch(this, "_playNext") );
}else{
anim.connect("onEnd", dojo.lang.hitch(this, function(){ this.fire("onEnd"); }) );
}
}, this);
}
dojo.inherits(dojo.lfx.Chain, dojo.lfx.IAnimation);
dojo.lang.extend(dojo.lfx.Chain, {
// private members
_currAnim: -1,
// public methods
play: function(delay, gotoStart){
if( !this._anims.length ) { return this; }
if( gotoStart || !this._anims[this._currAnim] ) {
this._currAnim = 0;
}
var currentAnimation = this._anims[this._currAnim];
this.fire("beforeBegin");
if(delay > 0){
setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
return this;
}
if(currentAnimation){
if(this._currAnim == 0){
this.fire("handler", ["begin", this._currAnim]);
this.fire("onBegin", [this._currAnim]);
}
this.fire("onPlay", [this._currAnim]);
currentAnimation.play(null, gotoStart);
}
return this;
},
pause: function(){
if( this._anims[this._currAnim] ) {
this._anims[this._currAnim].pause();
this.fire("onPause", [this._currAnim]);
}
return this;
},
playPause: function(){
if(this._anims.length == 0){ return this; }
if(this._currAnim == -1){ this._currAnim = 0; }
var currAnim = this._anims[this._currAnim];
if( currAnim ) {
if( !currAnim._active || currAnim._paused ) {
this.play();
} else {
this.pause();
}
}
return this;
},
stop: function(){
var currAnim = this._anims[this._currAnim];
if(currAnim){
currAnim.stop();
this.fire("onStop", [this._currAnim]);
}
return currAnim;
},
// private methods
_playNext: function(){
if( this._currAnim == -1 || this._anims.length == 0 ) { return this; }
this._currAnim++;
if( this._anims[this._currAnim] ){
this._anims[this._currAnim].play(null, true);
}
return this;
}
});
dojo.lfx.combine = function(){
var anims = arguments;
if(dojo.lang.isArray(arguments[0])){
anims = arguments[0];
}
if(anims.length == 1){ return anims[0]; }
return new dojo.lfx.Combine(anims);
}
dojo.lfx.chain = function(){
var anims = arguments;
if(dojo.lang.isArray(arguments[0])){
anims = arguments[0];
}
if(anims.length == 1){ return anims[0]; }
return new dojo.lfx.Chain(anims);
}
dojo.provide("dojo.graphics.color");
// TODO: rewrite the "x2y" methods to take advantage of the parsing
// abilities of the Color object. Also, beef up the Color
// object (as possible) to parse most common formats
// takes an r, g, b, a(lpha) value, [r, g, b, a] array, "rgb(...)" string, hex string (#aaa, #aaaaaa, aaaaaaa)
dojo.graphics.color.Color = function(r, g, b, a) {
// dojo.debug("r:", r[0], "g:", r[1], "b:", r[2]);
if(dojo.lang.isArray(r)) {
this.r = r[0];
this.g = r[1];
this.b = r[2];
this.a = r[3]||1.0;
} else if(dojo.lang.isString(r)) {
var rgb = dojo.graphics.color.extractRGB(r);
this.r = rgb[0];
this.g = rgb[1];
this.b = rgb[2];
this.a = g||1.0;
} else if(r instanceof dojo.graphics.color.Color) {
this.r = r.r;
this.b = r.b;
this.g = r.g;
this.a = r.a;
} else {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
}
dojo.graphics.color.Color.fromArray = function(arr) {
return new dojo.graphics.color.Color(arr[0], arr[1], arr[2], arr[3]);
}
dojo.lang.extend(dojo.graphics.color.Color, {
toRgb: function(includeAlpha) {
if(includeAlpha) {
return this.toRgba();
} else {
return [this.r, this.g, this.b];
}
},
toRgba: function() {
return [this.r, this.g, this.b, this.a];
},
toHex: function() {
return dojo.graphics.color.rgb2hex(this.toRgb());
},
toCss: function() {
return "rgb(" + this.toRgb().join() + ")";
},
toString: function() {
return this.toHex(); // decent default?
},
blend: function(color, weight) {
return dojo.graphics.color.blend(this.toRgb(), new dojo.graphics.color.Color(color).toRgb(), weight);
}
});
dojo.graphics.color.named = {
white: [255,255,255],
black: [0,0,0],
red: [255,0,0],
green: [0,255,0],
blue: [0,0,255],
navy: [0,0,128],
gray: [128,128,128],
silver: [192,192,192]
};
// blend colors a and b (both as RGB array or hex strings) with weight from -1 to +1, 0 being a 50/50 blend
dojo.graphics.color.blend = function(a, b, weight) {
if(typeof a == "string") { return dojo.graphics.color.blendHex(a, b, weight); }
if(!weight) { weight = 0; }
else if(weight > 1) { weight = 1; }
else if(weight < -1) { weight = -1; }
var c = new Array(3);
for(var i = 0; i < 3; i++) {
var half = Math.abs(a[i] - b[i])/2;
c[i] = Math.floor(Math.min(a[i], b[i]) + half + (half * weight));
}
return c;
}
// very convenient blend that takes and returns hex values
// (will get called automatically by blend when blend gets strings)
dojo.graphics.color.blendHex = function(a, b, weight) {
return dojo.graphics.color.rgb2hex(dojo.graphics.color.blend(dojo.graphics.color.hex2rgb(a), dojo.graphics.color.hex2rgb(b), weight));
}
// get RGB array from css-style color declarations
dojo.graphics.color.extractRGB = function(color) {
var hex = "0123456789abcdef";
color = color.toLowerCase();
if( color.indexOf("rgb") == 0 ) {
var matches = color.match(/rgba*\((\d+), *(\d+), *(\d+)/i);
var ret = matches.splice(1, 3);
return ret;
} else {
var colors = dojo.graphics.color.hex2rgb(color);
if(colors) {
return colors;
} else {
// named color (how many do we support?)
return dojo.graphics.color.named[color] || [255, 255, 255];
}
}
}
dojo.graphics.color.hex2rgb = function(hex) {
var hexNum = "0123456789ABCDEF";
var rgb = new Array(3);
if( hex.indexOf("#") == 0 ) { hex = hex.substring(1); }
hex = hex.toUpperCase();
if(hex.replace(new RegExp("["+hexNum+"]", "g"), "") != "") {
return null;
}
if( hex.length == 3 ) {
rgb[0] = hex.charAt(0) + hex.charAt(0)
rgb[1] = hex.charAt(1) + hex.charAt(1)
rgb[2] = hex.charAt(2) + hex.charAt(2);
} else {
rgb[0] = hex.substring(0, 2);
rgb[1] = hex.substring(2, 4);
rgb[2] = hex.substring(4);
}
for(var i = 0; i < rgb.length; i++) {
rgb[i] = hexNum.indexOf(rgb[i].charAt(0)) * 16 + hexNum.indexOf(rgb[i].charAt(1));
}
return rgb;
}
dojo.graphics.color.rgb2hex = function(r, g, b) {
if(dojo.lang.isArray(r)) {
g = r[1] || 0;
b = r[2] || 0;
r = r[0] || 0;
}
var ret = dojo.lang.map([r, g, b], function(x) {
x = new Number(x);
var s = x.toString(16);
while(s.length < 2) { s = "0" + s; }
return s;
});
ret.unshift("#");
return ret.join("");
}
dojo.provide("dojo.html.color");
dojo.html.getBackgroundColor = function(node){
node = dojo.byId(node);
var color;
do{
color = dojo.html.getStyle(node, "background-color");
// Safari doesn't say "transparent"
if(color.toLowerCase() == "rgba(0, 0, 0, 0)") { color = "transparent"; }
if(node == document.getElementsByTagName("body")[0]) { node = null; break; }
node = node.parentNode;
}while(node && dojo.lang.inArray(["transparent", ""], color));
if(color == "transparent"){
color = [255, 255, 255, 0];
}else{
color = dojo.graphics.color.extractRGB(color);
}
return color;
}
dojo.provide("dojo.lfx.html");
dojo.lfx.html._byId = function(nodes){
if(!nodes){ return []; }
if(dojo.lang.isArrayLike(nodes)){
if(!nodes.alreadyChecked){
var n = [];
dojo.lang.forEach(nodes, function(node){
n.push(dojo.byId(node));
});
n.alreadyChecked = true;
return n;
}else{
return nodes;
}
}else{
var n = [];
n.push(dojo.byId(nodes));
n.alreadyChecked = true;
return n;
}
}
dojo.lfx.html.propertyAnimation = function( /*DOMNode*/ nodes,
/*Array*/ propertyMap,
/*int*/ duration,
/*function*/ easing,
/*Object*/ handlers){
nodes = dojo.lfx.html._byId(nodes);
var targs = {
"propertyMap": propertyMap,
"nodes": nodes,
"duration": duration,
"easing": easing||dojo.lfx.easeDefault
};
var setEmUp = function(args){
if(args.nodes.length==1){
// FIXME: we're only supporting start-value filling when one node is
// passed
var pm = args.propertyMap;
if(!dojo.lang.isArray(args.propertyMap)){
// it's stupid to have to pack an array with a set of objects
// when you can just pass in an object list
var parr = [];
for(var pname in pm){
pm[pname].property = pname;
parr.push(pm[pname]);
}
pm = args.propertyMap = parr;
}
dojo.lang.forEach(pm, function(prop){
if(dj_undef("start", prop)){
if(prop.property != "opacity"){
prop.start = parseInt(dojo.html.getComputedStyle(args.nodes[0], prop.property));
}else{
prop.start = dojo.html.getOpacity(args.nodes[0]);
}
}
});
}
}
var coordsAsInts = function(coords){
var cints = [];
dojo.lang.forEach(coords, function(c){
cints.push(Math.round(c));
});
return cints;
}
var setStyle = function(n, style){
n = dojo.byId(n);
if(!n || !n.style){ return; }
for(var s in style){
if(s == "opacity"){
dojo.html.setOpacity(n, style[s]);
}else{
n.style[s] = style[s];
}
}
}
var propLine = function(properties){
this._properties = properties;
this.diffs = new Array(properties.length);
dojo.lang.forEach(properties, function(prop, i){
// calculate the end - start to optimize a bit
if(dojo.lang.isFunction(prop.start)){
prop.start = prop.start(prop, i);
}
if(dojo.lang.isFunction(prop.end)){
prop.end = prop.end(prop, i);
}
if(dojo.lang.isArray(prop.start)){
// don't loop through the arrays
this.diffs[i] = null;
}else if(prop.start instanceof dojo.graphics.color.Color){
// save these so we don't have to call toRgb() every getValue() call
prop.startRgb = prop.start.toRgb();
prop.endRgb = prop.end.toRgb();
}else{
this.diffs[i] = prop.end - prop.start;
}
}, this);
this.getValue = function(n){
var ret = {};
dojo.lang.forEach(this._properties, function(prop, i){
var value = null;
if(dojo.lang.isArray(prop.start)){
// FIXME: what to do here?
}else if(prop.start instanceof dojo.graphics.color.Color){
value = (prop.units||"rgb") + "(";
for(var j = 0 ; j < prop.startRgb.length ; j++){
value += Math.round(((prop.endRgb[j] - prop.startRgb[j]) * n) + prop.startRgb[j]) + (j < prop.startRgb.length - 1 ? "," : "");
}
value += ")";
}else{
value = ((this.diffs[i]) * n) + prop.start + (prop.property != "opacity" ? prop.units||"px" : "");
}
ret[dojo.html.toCamelCase(prop.property)] = value;
}, this);
return ret;
}
}
var anim = new dojo.lfx.Animation({
beforeBegin: function(){
setEmUp(targs);
anim.curve = new propLine(targs.propertyMap);
},
onAnimate: function(propValues){
dojo.lang.forEach(targs.nodes, function(node){
setStyle(node, propValues);
});
}
},
targs.duration,
null,
targs.easing
);
if(handlers){
for(var x in handlers){
if(dojo.lang.isFunction(handlers[x])){
anim.connect(x, anim, handlers[x]);
}
}
}
return anim;
}
dojo.lfx.html._makeFadeable = function(nodes){
var makeFade = function(node){
if(dojo.render.html.ie){
// only set the zoom if the "tickle" value would be the same as the
// default
if( (node.style.zoom.length == 0) &&
(dojo.html.getStyle(node, "zoom") == "normal") ){
// make sure the node "hasLayout"
// NOTE: this has been tested with larger and smaller user-set text
// sizes and works fine
node.style.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( (node.style.width.length == 0) &&
(dojo.html.getStyle(node, "width") == "auto") ){
node.style.width = "auto";
}
}
}
if(dojo.lang.isArrayLike(nodes)){
dojo.lang.forEach(nodes, makeFade);
}else{
makeFade(nodes);
}
}
dojo.lfx.html.fade = function(nodes, values, duration, easing, callback){
nodes = dojo.lfx.html._byId(nodes);
var props = { property: "opacity" };
if(!dj_undef("start", values)){
props.start = values.start;
}else{
props.start = function(){ return dojo.html.getOpacity(nodes[0]); };
}
if(!dj_undef("end", values)){
props.end = values.end;
}else{
dojo.raise("dojo.lfx.html.fade needs an end value");
}
var anim = dojo.lfx.propertyAnimation(nodes, [ props ], duration, easing);
anim.connect("beforeBegin", function(){
dojo.lfx.html._makeFadeable(nodes);
});
if(callback){
anim.connect("onEnd", function(){ callback(nodes, anim); });
}
return anim;
}
dojo.lfx.html.fadeIn = function(nodes, duration, easing, callback){
return dojo.lfx.html.fade(nodes, { end: 1 }, duration, easing, callback);
}
dojo.lfx.html.fadeOut = function(nodes, duration, easing, callback){
return dojo.lfx.html.fade(nodes, { end: 0 }, duration, easing, callback);
}
dojo.lfx.html.fadeShow = function(nodes, duration, easing, callback){
nodes=dojo.lfx.html._byId(nodes);
dojo.lang.forEach(nodes, function(node){
dojo.html.setOpacity(node, 0.0);
});
var anim = dojo.lfx.html.fadeIn(nodes, duration, easing, callback);
anim.connect("beforeBegin", function(){
if(dojo.lang.isArrayLike(nodes)){
dojo.lang.forEach(nodes, dojo.html.show);
}else{
dojo.html.show(nodes);
}
});
return anim;
}
dojo.lfx.html.fadeHide = function(nodes, duration, easing, callback){
var anim = dojo.lfx.html.fadeOut(nodes, duration, easing, function(){
if(dojo.lang.isArrayLike(nodes)){
dojo.lang.forEach(nodes, dojo.html.hide);
}else{
dojo.html.hide(nodes);
}
if(callback){ callback(nodes, anim); }
});
return anim;
}
dojo.lfx.html.wipeIn = function(nodes, duration, easing, callback){
nodes = dojo.lfx.html._byId(nodes);
var anims = [];
dojo.lang.forEach(nodes, function(node){
var oprop = { overflow: null };
var anim = dojo.lfx.propertyAnimation(node,
{ "height": {
start: 0,
end: function(){ return node.scrollHeight; }
}
},
duration,
easing);
anim.connect("beforeBegin", function(){
oprop.overflow = dojo.html.getStyle(node, "overflow");
with(node.style){
if(oprop.overflow == "visible") {
overflow = "hidden";
}
visibility = "visible";
height = "0px";
}
dojo.html.show(node);
});
anim.connect("onEnd", function(){
with(node.style){
overflow = oprop.overflow;
// height = "auto";
height = "";
visibility = "visible";
}
if(callback){ callback(node, anim); }
});
anims.push(anim);
});
return dojo.lfx.combine(anims);
}
dojo.lfx.html.wipeOut = function(nodes, duration, easing, callback){
nodes = dojo.lfx.html._byId(nodes);
var anims = [];
dojo.lang.forEach(nodes, function(node){
var oprop = { overflow: null };
var anim = dojo.lfx.propertyAnimation(node,
{ "height": {
start: function(){ return dojo.html.getContentBox(node).height; },
end: 0
}
},
duration,
easing,
{
"beforeBegin": function(){
oprop.overflow = dojo.html.getStyle(node, "overflow");
if(oprop.overflow == "visible") {
node.style.overflow = "hidden";
}
node.style.visibility = "visible";
dojo.html.show(node);
},
"onEnd": function(){
// dojo.html.hide(node);
with(node.style){
overflow = oprop.overflow;
visibility = "hidden";
height = "";
}
if(callback){ callback(node, anim); }
}
}
);
anims.push(anim);
});
return dojo.lfx.combine(anims);
}
dojo.lfx.html.slideTo = function(nodes, coords, duration, easing, callback){
nodes = dojo.lfx.html._byId(nodes);
var anims = [];
var compute = dojo.html.getComputedStyle;
if(dojo.lang.isArray(coords)){
dojo.deprecated('dojo.lfx.html.slideTo(node, array)', 'use dojo.lfx.html.slideTo(node, {top: value, left: value});', '0.5');
coords = { top: coords[0], left: coords[1] };
}
dojo.lang.forEach(nodes, function(node){
var top = null;
var left = null;
var init = (function(){
var innerNode = node;
return function(){
var pos = compute(innerNode, 'position');
top = (pos == 'absolute' ? node.offsetTop : parseInt(compute(node, 'top')) || 0);
left = (pos == 'absolute' ? node.offsetLeft : parseInt(compute(node, 'left')) || 0);
if (!dojo.lang.inArray(['absolute', 'relative'], pos)) {
var ret = dojo.html.abs(innerNode, true);
dojo.html.setStyleAttributes(innerNode, "position:absolute;top:"+ret.y+"px;left:"+ret.x+"px;");
top = ret.y;
left = ret.x;
}
}
})();
init();
var anim = dojo.lfx.propertyAnimation(node,
{ "top": { start: top, end: (coords.top||0) },
"left": { start: left, end: (coords.left||0) }
},
duration,
easing,
{ "beforeBegin": init }
);
if(callback){
anim.connect("onEnd", function(){ callback(nodes, anim); });
}
anims.push(anim);
});
return dojo.lfx.combine(anims);
}
dojo.lfx.html.slideBy = function(nodes, coords, duration, easing, callback){
nodes = dojo.lfx.html._byId(nodes);
var anims = [];
var compute = dojo.html.getComputedStyle;
if(dojo.lang.isArray(coords)){
dojo.deprecated('dojo.lfx.html.slideBy(node, array)', 'use dojo.lfx.html.slideBy(node, {top: value, left: value});', '0.5');
coords = { top: coords[0], left: coords[1] };
}
dojo.lang.forEach(nodes, function(node){
var top = null;
var left = null;
var init = (function(){
var innerNode = node;
return function(){
var pos = compute(innerNode, 'position');
top = (pos == 'absolute' ? node.offsetTop : parseInt(compute(node, 'top')) || 0);
left = (pos == 'absolute' ? node.offsetLeft : parseInt(compute(node, 'left')) || 0);
if (!dojo.lang.inArray(['absolute', 'relative'], pos)) {
var ret = dojo.html.abs(innerNode, true);
dojo.html.setStyleAttributes(innerNode, "position:absolute;top:"+ret.y+"px;left:"+ret.x+"px;");
top = ret.y;
left = ret.x;
}
}
})();
init();
var anim = dojo.lfx.propertyAnimation(node,
{
"top": { start: top, end: top+(coords.top||0) },
"left": { start: left, end: left+(coords.left||0) }
},
duration,
easing).connect("beforeBegin", init);
if(callback){
anim.connect("onEnd", function(){ callback(nodes, anim); });
}
anims.push(anim);
});
return dojo.lfx.combine(anims);
}
dojo.lfx.html.explode = function(start, endNode, duration, easing, callback){
var h = dojo.html;
start = dojo.byId(start);
endNode = dojo.byId(endNode);
var startCoords = h.toCoordinateObject(start, true);
var outline = document.createElement("div");
h.copyStyle(outline, endNode);
with(outline.style){
position = "absolute";
display = "none";
// border = "1px solid black";
}
dojo.body().appendChild(outline);
with(endNode.style){
visibility = "hidden";
display = "block";
}
var endCoords = h.toCoordinateObject(endNode, true);
outline.style.backgroundColor = h.getStyle(endNode, "background-color").toLowerCase();
with(endNode.style){
display = "none";
visibility = "visible";
}
var props = { opacity: { start: 0.3, end: 1.0 } };
dojo.lang.forEach(["height", "width", "top", "left"], function(type){
props[type] = { start: startCoords[type], end: endCoords[type] }
});
var anim = new dojo.lfx.propertyAnimation(outline,
props,
duration,
easing,
{
"beforeBegin": function(){
h.setDisplay(outline, "block");
},
"onEnd": function(){
h.setDisplay(endNode, "block");
outline.parentNode.removeChild(outline);
}
}
);
if(callback){
anim.connect("onEnd", function(){ callback(endNode, anim); });
}
return anim;
}
dojo.lfx.html.implode = function(startNode, end, duration, easing, callback){
var h = dojo.html;
startNode = dojo.byId(startNode);
end = dojo.byId(end);
var startCoords = dojo.html.toCoordinateObject(startNode, true);
var endCoords = dojo.html.toCoordinateObject(end, true);
var outline = document.createElement("div");
dojo.html.copyStyle(outline, startNode);
dojo.html.setOpacity(outline, 0.3);
with(outline.style){
position = "absolute";
display = "none";
backgroundColor = h.getStyle(startNode, "background-color").toLowerCase();
}
dojo.body().appendChild(outline);
var props = { opacity: { start: 1.0, end: 0.3 } };
dojo.lang.forEach(["height", "width", "top", "left"], function(type){
props[type] = { start: startCoords[type], end: endCoords[type] }
});
var anim = new dojo.lfx.propertyAnimation(outline,
props,
duration,
easing,
{
"beforeBegin": function(){
dojo.html.hide(startNode);
dojo.html.show(outline);
},
"onEnd": function(){
outline.parentNode.removeChild(outline);
}
}
);
if(callback){
anim.connect("onEnd", function(){ callback(startNode, anim); });
}
return anim;
}
dojo.lfx.html.highlight = function(nodes, startColor, duration, easing, callback){
nodes = dojo.lfx.html._byId(nodes);
var anims = [];
dojo.lang.forEach(nodes, function(node){
var color = dojo.html.getBackgroundColor(node);
var bg = dojo.html.getStyle(node, "background-color").toLowerCase();
var bgImage = dojo.html.getStyle(node, "background-image");
var wasTransparent = (bg == "transparent" || bg == "rgba(0, 0, 0, 0)");
while(color.length > 3) { color.pop(); }
var rgb = new dojo.graphics.color.Color(startColor);
var endRgb = new dojo.graphics.color.Color(color);
var anim = dojo.lfx.propertyAnimation(node,
{ "background-color": { start: rgb, end: endRgb } },
duration,
easing,
{
"beforeBegin": function(){
if(bgImage){
node.style.backgroundImage = "none";
}
node.style.backgroundColor = "rgb(" + rgb.toRgb().join(",") + ")";
},
"onEnd": function(){
if(bgImage){
node.style.backgroundImage = bgImage;
}
if(wasTransparent){
node.style.backgroundColor = "transparent";
}
if(callback){
callback(node, anim);
}
}
}
);
anims.push(anim);
});
return dojo.lfx.combine(anims);
}
dojo.lfx.html.unhighlight = function(nodes, endColor, duration, easing, callback){
nodes = dojo.lfx.html._byId(nodes);
var anims = [];
dojo.lang.forEach(nodes, function(node){
var color = new dojo.graphics.color.Color(dojo.html.getBackgroundColor(node));
var rgb = new dojo.graphics.color.Color(endColor);
var bgImage = dojo.html.getStyle(node, "background-image");
var anim = dojo.lfx.propertyAnimation(node,
{ "background-color": { start: color, end: rgb } },
duration,
easing,
{
"beforeBegin": function(){
if(bgImage){
node.style.backgroundImage = "none";
}
node.style.backgroundColor = "rgb(" + color.toRgb().join(",") + ")";
},
"onEnd": function(){
if(callback){
callback(node, anim);
}
}
}
);
anims.push(anim);
});
return dojo.lfx.combine(anims);
}
dojo.lang.mixin(dojo.lfx, dojo.lfx.html);
dojo.provide("dojo.lfx.*");
dojo.provide("dojo.lfx.toggle");
dojo.lfx.toggle.plain = {
show: function(node, duration, easing, callback){
dojo.html.show(node);
if(dojo.lang.isFunction(callback)){ callback(); }
},
hide: function(node, duration, easing, callback){
dojo.html.hide(node);
if(dojo.lang.isFunction(callback)){ callback(); }
}
}
dojo.lfx.toggle.fade = {
show: function(node, duration, easing, callback){
dojo.lfx.fadeShow(node, duration, easing, callback).play();
},
hide: function(node, duration, easing, callback){
dojo.lfx.fadeHide(node, duration, easing, callback).play();
}
}
dojo.lfx.toggle.wipe = {
show: function(node, duration, easing, callback){
dojo.lfx.wipeIn(node, duration, easing, callback).play();
},
hide: function(node, duration, easing, callback){
dojo.lfx.wipeOut(node, duration, easing, callback).play();
}
}
dojo.lfx.toggle.explode = {
show: function(node, duration, easing, callback, explodeSrc){
dojo.lfx.explode(explodeSrc||{x:0,y:0,width:0,height:0}, node, duration, easing, callback).play();
},
hide: function(node, duration, easing, callback, explodeSrc){
dojo.lfx.implode(node, explodeSrc||{x:0,y:0,width:0,height:0}, duration, easing, callback).play();
}
}
dojo.provide("dojo.widget.HtmlWidget");
dojo.declare("dojo.widget.HtmlWidget", dojo.widget.DomWidget, {
widgetType: "HtmlWidget",
templateCssPath: null,
templatePath: null,
// for displaying/hiding widget
toggle: "plain",
toggleDuration: 150,
animationInProgress: false,
initialize: function(args, frag){
},
postMixInProperties: function(args, frag){
// now that we know the setting for toggle, get toggle object
// (default to plain toggler if user specified toggler not present)
this.toggleObj =
dojo.lfx.toggle[this.toggle.toLowerCase()] || dojo.lfx.toggle.plain;
},
getContainerHeight: function(){
// NOTE: container height must be returned as the INNER height
dojo.unimplemented("dojo.widget.HtmlWidget.getContainerHeight");
},
getContainerWidth: function(){
return this.parent.domNode.offsetWidth;
},
setNativeHeight: function(height){
var ch = this.getContainerHeight();
},
createNodesFromText: function(txt, wrap){
return dojo.html.createNodesFromText(txt, wrap);
},
destroyRendering: function(finalize){
try{
if(!finalize && this.domNode){
dojo.event.browser.clean(this.domNode);
}
this.domNode.parentNode.removeChild(this.domNode);
delete this.domNode;
}catch(e){ /* squelch! */ }
},
/////////////////////////////////////////////////////////
// Displaying/hiding the widget
/////////////////////////////////////////////////////////
isShowing: function(){
return dojo.html.isShowing(this.domNode);
},
toggleShowing: function(){
// dojo.html.toggleShowing(this.domNode);
if(this.isHidden){
this.show();
}else{
this.hide();
}
},
show: function(){
this.animationInProgress=true;
this.isHidden = false;
this.toggleObj.show(this.domNode, this.toggleDuration, null,
dojo.lang.hitch(this, this.onShow), this.explodeSrc);
},
// called after the show() animation has completed
onShow: function(){
this.animationInProgress=false;
this.checkSize();
},
hide: function(){
this.animationInProgress = true;
this.isHidden = true;
this.toggleObj.hide(this.domNode, this.toggleDuration, null,
dojo.lang.hitch(this, this.onHide), this.explodeSrc);
},
// called after the hide() animation has completed
onHide: function(){
this.animationInProgress=false;
},
//////////////////////////////////////////////////////////////////////////////
// Sizing related methods
// If the parent changes size then for each child it should call either
// - resizeTo(): size the child explicitly
// - or checkSize(): notify the child the the parent has changed size
//////////////////////////////////////////////////////////////////////////////
// Test if my size has changed.
// If width & height are specified then that's my new size; otherwise,
// query outerWidth/outerHeight of my domNode
_isResized: function(w, h){
// If I'm not being displayed then disregard (show() must
// check if the size has changed)
if(!this.isShowing()){ return false; }
// If my parent has been resized and I have style="height: 100%"
// or something similar then my size has changed too.
var wh = dojo.html.getMarginBox(this.domNode);
var width=w||wh.width;
var height=h||wh.height;
if(this.width == width && this.height == height){ return false; }
this.width=width;
this.height=height;
return true;
},
// Called when my parent has changed size, but my parent won't call resizeTo().
// This is useful if my size is height:100% or something similar.
// Also called whenever I am shown, because the first time I am shown I may need
// to do size calculations.
checkSize: function(){
if(!this._isResized()){ return; }
this.onResized();
},
// Explicitly set this widget's size (in pixels).
resizeTo: function(w, h){
if(!this._isResized(w,h)){ return; }
dojo.html.setMarginBox(this.domNode, { width: w, height: h });
this.onResized();
},
resizeSoon: function(){
if(this.isShowing()){
dojo.lang.setTimeout(this, this.onResized, 0);
}
},
// Called when my size has changed.
// Must notify children if their size has (possibly) changed
onResized: function(){
dojo.lang.forEach(this.children, function(child){ if (child["checkSize"]) child.checkSize(); });
}
});
dojo.provide("dojo.widget.*");