diff --git a/project-build.xml b/project-build.xml deleted file mode 100644 index 87b958dc84..0000000000 --- a/project-build.xml +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - isTomcat = ${isTomcat} - isJBoss = ${isJBoss} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/project-override.properties b/project-override.properties deleted file mode 100644 index 2c25b41451..0000000000 --- a/project-override.properties +++ /dev/null @@ -1,4 +0,0 @@ -file.name.war=alfresco.war - -javadoc.title.window=Alfresco Web Client API -javadoc.title.document=Alfresco Web Client API Specification diff --git a/project.properties b/project.properties deleted file mode 100644 index c4417501cc..0000000000 --- a/project.properties +++ /dev/null @@ -1,2 +0,0 @@ -webinf.delete.tomcat=jboss*.xml,portlet*.xml,alfresco-object.xml -webinf.lib.delete.jboss=log4j-1.2.8.jar,portlet-api-lib.jar,myfaces-api.jar,myfaces-impl.jar diff --git a/source/meta-inf/manifest.mf b/source/meta-inf/manifest.mf deleted file mode 100644 index fb56593e14..0000000000 --- a/source/meta-inf/manifest.mf +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 -Class-Path: core.jar repository.jar \ No newline at end of file diff --git a/source/web/scripts/ajax/dojo/dojo.js b/source/web/scripts/ajax/dojo/dojo.js new file mode 100644 index 0000000000..5fea346ec7 --- /dev/null +++ b/source/web/scripts/ajax/dojo/dojo.js @@ -0,0 +1,6414 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +/* + This is a compiled version of Dojo, built for deployment and not for + development. To get an editable version, please visit: + + http://dojotoolkit.org + + for documentation and information on getting the source. +*/ + +if(typeof dojo=="undefined"){ +var dj_global=this; +var dj_currentContext=this; +function dj_undef(_1,_2){ +return (typeof (_2||dj_currentContext)[_1]=="undefined"); +} +if(dj_undef("djConfig",this)){ +var djConfig={}; +} +if(dj_undef("dojo",this)){ +var dojo={}; +} +dojo.global=function(){ +return dj_currentContext; +}; +dojo.locale=djConfig.locale; +dojo.version={major:0,minor:4,patch:1,flag:"",revision:Number("$Rev: 6824 $".match(/[0-9]+/)[0]),toString:function(){ +with(dojo.version){ +return major+"."+minor+"."+patch+flag+" ("+revision+")"; +} +}}; +dojo.evalProp=function(_3,_4,_5){ +if((!_4)||(!_3)){ +return undefined; +} +if(!dj_undef(_3,_4)){ +return _4[_3]; +} +return (_5?(_4[_3]={}):undefined); +}; +dojo.parseObjPath=function(_6,_7,_8){ +var _9=(_7||dojo.global()); +var _a=_6.split("."); +var _b=_a.pop(); +for(var i=0,l=_a.length;i1){ +dh.modulesLoadedListeners.push(function(){ +obj[_3d](); +}); +} +} +if(dh.post_load_&&dh.inFlightCount==0&&!dh.loadNotifying){ +dh.callLoaded(); +} +}; +dojo.addOnUnload=function(obj,_40){ +var dh=dojo.hostenv; +if(arguments.length==1){ +dh.unloadListeners.push(obj); +}else{ +if(arguments.length>1){ +dh.unloadListeners.push(function(){ +obj[_40](); +}); +} +} +}; +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(_42){ +var _43=_42.split("."); +for(var i=_43.length;i>0;i--){ +var _45=_43.slice(0,i).join("."); +if((i==1)&&!this.moduleHasPrefix(_45)){ +_43[0]="../"+_43[0]; +}else{ +var _46=this.getModulePrefix(_45); +if(_46!=_45){ +_43.splice(0,i,_46); +break; +} +} +} +return _43; +}; +dojo.hostenv._global_omit_module_check=false; +dojo.hostenv.loadModule=function(_47,_48,_49){ +if(!_47){ +return; +} +_49=this._global_omit_module_check||_49; +var _4a=this.findModule(_47,false); +if(_4a){ +return _4a; +} +if(dj_undef(_47,this.loading_modules_)){ +this.addedToLoadingCount.push(_47); +} +this.loading_modules_[_47]=1; +var _4b=_47.replace(/\./g,"/")+".js"; +var _4c=_47.split("."); +var _4d=this.getModuleSymbols(_47); +var _4e=((_4d[0].charAt(0)!="/")&&!_4d[0].match(/^\w+:/)); +var _4f=_4d[_4d.length-1]; +var ok; +if(_4f=="*"){ +_47=_4c.slice(0,-1).join("."); +while(_4d.length){ +_4d.pop(); +_4d.push(this.pkgFileName); +_4b=_4d.join("/")+".js"; +if(_4e&&_4b.charAt(0)=="/"){ +_4b=_4b.slice(1); +} +ok=this.loadPath(_4b,!_49?_47:null); +if(ok){ +break; +} +_4d.pop(); +} +}else{ +_4b=_4d.join("/")+".js"; +_47=_4c.join("."); +var _51=!_49?_47:null; +ok=this.loadPath(_4b,_51); +if(!ok&&!_48){ +_4d.pop(); +while(_4d.length){ +_4b=_4d.join("/")+".js"; +ok=this.loadPath(_4b,_51); +if(ok){ +break; +} +_4d.pop(); +_4b=_4d.join("/")+"/"+this.pkgFileName+".js"; +if(_4e&&_4b.charAt(0)=="/"){ +_4b=_4b.slice(1); +} +ok=this.loadPath(_4b,_51); +if(ok){ +break; +} +} +} +if(!ok&&!_49){ +dojo.raise("Could not load '"+_47+"'; last tried '"+_4b+"'"); +} +} +if(!_49&&!this["isXDomain"]){ +_4a=this.findModule(_47,false); +if(!_4a){ +dojo.raise("symbol '"+_47+"' is not defined after loading '"+_4b+"'"); +} +} +return _4a; +}; +dojo.hostenv.startPackage=function(_52){ +var _53=String(_52); +var _54=_53; +var _55=_52.split(/\./); +if(_55[_55.length-1]=="*"){ +_55.pop(); +_54=_55.join("."); +} +var _56=dojo.evalObjPath(_54,true); +this.loaded_modules_[_53]=_56; +this.loaded_modules_[_54]=_56; +return _56; +}; +dojo.hostenv.findModule=function(_57,_58){ +var lmn=String(_57); +if(this.loaded_modules_[lmn]){ +return this.loaded_modules_[lmn]; +} +if(_58){ +dojo.raise("no loaded module named '"+_57+"'"); +} +return null; +}; +dojo.kwCompoundRequire=function(_5a){ +var _5b=_5a["common"]||[]; +var _5c=_5a[dojo.hostenv.name_]?_5b.concat(_5a[dojo.hostenv.name_]||[]):_5b.concat(_5a["default"]||[]); +for(var x=0;x<_5c.length;x++){ +var _5e=_5c[x]; +if(_5e.constructor==Array){ +dojo.hostenv.loadModule.apply(dojo.hostenv,_5e); +}else{ +dojo.hostenv.loadModule(_5e); +} +} +}; +dojo.require=function(_5f){ +dojo.hostenv.loadModule.apply(dojo.hostenv,arguments); +}; +dojo.requireIf=function(_60,_61){ +var _62=arguments[0]; +if((_62===true)||(_62=="common")||(_62&&dojo.render[_62].capable)){ +var _63=[]; +for(var i=1;i0;i--){ +_74.push(_73.slice(0,i).join("-")); +} +_74.push(false); +if(_71){ +_74.reverse(); +} +for(var j=_74.length-1;j>=0;j--){ +var loc=_74[j]||"ROOT"; +var _78=_72(loc); +if(_78){ +break; +} +} +}; +dojo.hostenv.localesGenerated; +dojo.hostenv.registerNlsPrefix=function(){ +dojo.registerModulePath("nls","nls"); +}; +dojo.hostenv.preloadLocalizations=function(){ +if(dojo.hostenv.localesGenerated){ +dojo.hostenv.registerNlsPrefix(); +function preload(_79){ +_79=dojo.hostenv.normalizeLocale(_79); +dojo.hostenv.searchLocalePath(_79,true,function(loc){ +for(var i=0;i_84.length){ +_84=_85[i]; +} +} +} +if(!_84){ +_84="ROOT"; +} +} +var _87=_81?_84:_82; +var _88=dojo.hostenv.findModule(_83); +var _89=null; +if(_88){ +if(djConfig.localizationComplete&&_88._built){ +return; +} +var _8a=_87.replace("-","_"); +var _8b=_83+"."+_8a; +_89=dojo.hostenv.findModule(_8b); +} +if(!_89){ +_88=dojo.hostenv.startPackage(_83); +var _8c=dojo.hostenv.getModuleSymbols(_7e); +var _8d=_8c.concat("nls").join("/"); +var _8e; +dojo.hostenv.searchLocalePath(_87,_81,function(loc){ +var _90=loc.replace("-","_"); +var _91=_83+"."+_90; +var _92=false; +if(!dojo.hostenv.findModule(_91)){ +dojo.hostenv.startPackage(_91); +var _93=[_8d]; +if(loc!="ROOT"){ +_93.push(loc); +} +_93.push(_7f); +var _94=_93.join("/")+".js"; +_92=dojo.hostenv.loadPath(_94,null,function(_95){ +var _96=function(){ +}; +_96.prototype=_8e; +_88[_90]=new _96(); +for(var j in _95){ +_88[_90][j]=_95[j]; +} +}); +}else{ +_92=true; +} +if(_92&&_88[_90]){ +_8e=_88[_90]; +}else{ +_88[_90]=_8e; +} +if(_81){ +return true; +} +}); +} +if(_81&&_82!=_84){ +_88[_82.replace("-","_")]=_88[_84.replace("-","_")]; +} +}; +(function(){ +var _98=djConfig.extraLocale; +if(_98){ +if(!_98 instanceof Array){ +_98=[_98]; +} +var req=dojo.requireLocalization; +dojo.requireLocalization=function(m,b,_9c,_9d){ +req(m,b,_9c,_9d); +if(_9c){ +return; +} +for(var i=0;i<_98.length;i++){ +req(m,b,_98[i],_9d); +} +}; +} +})(); +} +if(typeof window!="undefined"){ +(function(){ +if(djConfig.allowQueryConfig){ +var _9f=document.location.toString(); +var _a0=_9f.split("?",2); +if(_a0.length>1){ +var _a1=_a0[1]; +var _a2=_a1.split("&"); +for(var x in _a2){ +var sp=_a2[x].split("="); +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 _a6=document.getElementsByTagName("script"); +var _a7=/(__package__|dojo|bootstrap1)\.js([\?\.]|$)/i; +for(var i=0;i<_a6.length;i++){ +var src=_a6[i].getAttribute("src"); +if(!src){ +continue; +} +var m=src.match(_a7); +if(m){ +var _ab=src.substring(0,m.index); +if(src.indexOf("bootstrap1")>-1){ +_ab+="../"; +} +if(!this["djConfig"]){ +djConfig={}; +} +if(djConfig["baseScriptUri"]==""){ +djConfig["baseScriptUri"]=_ab; +} +if(djConfig["baseRelativePath"]==""){ +djConfig["baseRelativePath"]=_ab; +} +break; +} +} +} +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; +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 _b3=dua.indexOf("Gecko"); +drh.mozilla=drh.moz=(_b3>=0)&&(!drh.khtml); +if(drh.mozilla){ +drh.geckoVersion=dua.substring(_b3+6,_b3+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; +var cm=document["compatMode"]; +drh.quirks=(cm=="BackCompat")||(cm=="QuirksMode")||drh.ie55||drh.ie50; +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 _b5=window["document"]; +var tdi=_b5["implementation"]; +if((tdi)&&(tdi["hasFeature"])&&(tdi.hasFeature("org.w3c.dom.svg","1.0"))){ +drs.capable=t; +drs.support.builtin=t; +drs.support.plugin=f; +} +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; +} +}else{ +} +})(); +dojo.hostenv.startPackage("dojo.hostenv"); +dojo.render.name=dojo.hostenv.name_="browser"; +dojo.hostenv.searchIds=[]; +dojo.hostenv._XMLHTTP_PROGIDS=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"]; +dojo.hostenv.getXmlhttpObject=function(){ +var _b9=null; +var _ba=null; +try{ +_b9=new XMLHttpRequest(); +} +catch(e){ +} +if(!_b9){ +for(var i=0;i<3;++i){ +var _bc=dojo.hostenv._XMLHTTP_PROGIDS[i]; +try{ +_b9=new ActiveXObject(_bc); +} +catch(e){ +_ba=e; +} +if(_b9){ +dojo.hostenv._XMLHTTP_PROGIDS=[_bc]; +break; +} +} +} +if(!_b9){ +return dojo.raise("XMLHTTP not available",_ba); +} +return _b9; +}; +dojo.hostenv._blockAsync=false; +dojo.hostenv.getText=function(uri,_be,_bf){ +if(!_be){ +this._blockAsync=true; +} +var _c0=this.getXmlhttpObject(); +function isDocumentOk(_c1){ +var _c2=_c1["status"]; +return Boolean((!_c2)||((200<=_c2)&&(300>_c2))||(_c2==304)); +} +if(_be){ +var _c3=this,_c4=null,gbl=dojo.global(); +var xhr=dojo.evalObjPath("dojo.io.XMLHTTPTransport"); +_c0.onreadystatechange=function(){ +if(_c4){ +gbl.clearTimeout(_c4); +_c4=null; +} +if(_c3._blockAsync||(xhr&&xhr._blockAsync)){ +_c4=gbl.setTimeout(function(){ +_c0.onreadystatechange.apply(this); +},10); +}else{ +if(4==_c0.readyState){ +if(isDocumentOk(_c0)){ +_be(_c0.responseText); +} +} +} +}; +} +_c0.open("GET",uri,_be?true:false); +try{ +_c0.send(null); +if(_be){ +return null; +} +if(!isDocumentOk(_c0)){ +var err=Error("Unable to load "+uri+" status:"+_c0.status); +err.status=_c0.status; +err.responseText=_c0.responseText; +throw err; +} +} +catch(e){ +this._blockAsync=false; +if((_bf)&&(!_be)){ +return null; +}else{ +throw e; +} +} +this._blockAsync=false; +return _c0.responseText; +}; +dojo.hostenv.defaultDebugContainerId="dojoDebug"; +dojo.hostenv._println_buffer=[]; +dojo.hostenv._println_safe=false; +dojo.hostenv.println=function(_c8){ +if(!dojo.hostenv._println_safe){ +dojo.hostenv._println_buffer.push(_c8); +}else{ +try{ +var _c9=document.getElementById(djConfig.debugContainerId?djConfig.debugContainerId:dojo.hostenv.defaultDebugContainerId); +if(!_c9){ +_c9=dojo.body(); +} +var div=document.createElement("div"); +div.appendChild(document.createTextNode(_c8)); +_c9.appendChild(div); +} +catch(e){ +try{ +document.write("
"+_c8+"
"); +} +catch(e2){ +window.status=_c8; +} +} +} +}; +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(_cb,_cc,fp){ +var _ce=_cb["on"+_cc]||function(){ +}; +_cb["on"+_cc]=function(){ +fp.apply(_cb,arguments); +_ce.apply(_cb,arguments); +}; +return true; +} +function dj_load_init(e){ +var _d0=(e&&e.type)?e.type.toLowerCase():"load"; +if(arguments.callee.initialized||(_d0!="domcontentloaded"&&_d0!="load")){ +return; +} +arguments.callee.initialized=true; +if(typeof (_timer)!="undefined"){ +clearInterval(_timer); +delete _timer; +} +var _d1=function(){ +if(dojo.render.html.ie){ +dojo.hostenv.makeWidgets(); +} +}; +if(dojo.hostenv.inFlightCount==0){ +_d1(); +dojo.hostenv.modulesLoaded(); +}else{ +dojo.hostenv.modulesLoadedListeners.unshift(_d1); +} +} +if(document.addEventListener){ +if(dojo.render.html.opera||(dojo.render.html.moz&&!djConfig.delayMozLoadingFix)){ +document.addEventListener("DOMContentLoaded",dj_load_init,null); +} +window.addEventListener("load",dj_load_init,null); +} +if(dojo.render.html.ie&&dojo.render.os.win){ +document.attachEvent("onreadystatechange",function(e){ +if(document.readyState=="complete"){ +dj_load_init(); +} +}); +} +if(/(WebKit|khtml)/i.test(navigator.userAgent)){ +var _timer=setInterval(function(){ +if(/loaded|complete/.test(document.readyState)){ +dj_load_init(); +} +},10); +} +if(dojo.render.html.ie){ +dj_addNodeEvtHdlr(window,"beforeunload",function(){ +dojo.hostenv._unloading=true; +window.setTimeout(function(){ +dojo.hostenv._unloading=false; +},0); +}); +} +dj_addNodeEvtHdlr(window,"unload",function(){ +dojo.hostenv.unloaded(); +if((!dojo.render.html.ie)||(dojo.render.html.ie&&dojo.hostenv._unloading)){ +dojo.hostenv.unloaded(); +} +}); +dojo.hostenv.makeWidgets=function(){ +var _d3=[]; +if(djConfig.searchIds&&djConfig.searchIds.length>0){ +_d3=_d3.concat(djConfig.searchIds); +} +if(dojo.hostenv.searchIds&&dojo.hostenv.searchIds.length>0){ +_d3=_d3.concat(dojo.hostenv.searchIds); +} +if((djConfig.parseWidgets)||(_d3.length>0)){ +if(dojo.evalObjPath("dojo.widget.Parse")){ +var _d4=new dojo.xml.Parse(); +if(_d3.length>0){ +for(var x=0;x<_d3.length;x++){ +var _d6=document.getElementById(_d3[x]); +if(!_d6){ +continue; +} +var _d7=_d4.parseElement(_d6,null,true); +dojo.widget.getParser().createComponents(_d7); +} +}else{ +if(djConfig.parseWidgets){ +var _d7=_d4.parseElement(dojo.body(),null,true); +dojo.widget.getParser().createComponents(_d7); +} +} +} +} +}; +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){ +} +dojo.hostenv.writeIncludes=function(){ +}; +if(!dj_undef("document",this)){ +dj_currentDocument=this.document; +} +dojo.doc=function(){ +return dj_currentDocument; +}; +dojo.body=function(){ +return dojo.doc().body||dojo.doc().getElementsByTagName("body")[0]; +}; +dojo.byId=function(id,doc){ +if((id)&&((typeof id=="string")||(id instanceof String))){ +if(!doc){ +doc=dj_currentDocument; +} +var ele=doc.getElementById(id); +if(ele&&(ele.id!=id)&&doc.all){ +ele=null; +eles=doc.all[id]; +if(eles){ +if(eles.length){ +for(var i=0;i"); +} +catch(e){ +var _f5=document.createElement("script"); +_f5.src=_f4; +document.getElementsByTagName("head")[0].appendChild(_f5); +} +} +} +})(); +dojo.provide("dojo.string.common"); +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,""); +}; +dojo.string.trimStart=function(str){ +return dojo.string.trim(str,1); +}; +dojo.string.trimEnd=function(str){ +return dojo.string.trim(str,-1); +}; +dojo.string.repeat=function(str,_fc,_fd){ +var out=""; +for(var i=0;i<_fc;i++){ +out+=str; +if(_fd&&i<_fc-1){ +out+=_fd; +} +} +return out; +}; +dojo.string.pad=function(str,len,c,dir){ +var out=String(str); +if(!c){ +c="0"; +} +if(!dir){ +dir=1; +} +while(out.length0){ +out=c+out; +}else{ +out+=c; +} +} +return out; +}; +dojo.string.padLeft=function(str,len,c){ +return 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"); +dojo.lang.inherits=function(_10b,_10c){ +if(!dojo.lang.isFunction(_10c)){ +dojo.raise("dojo.inherits: superclass argument ["+_10c+"] must be a function (subclass: ["+_10b+"']"); +} +_10b.prototype=new _10c(); +_10b.prototype.constructor=_10b; +_10b.superclass=_10c.prototype; +_10b["super"]=_10c.prototype; +}; +dojo.lang._mixin=function(obj,_10e){ +var tobj={}; +for(var x in _10e){ +if((typeof tobj[x]=="undefined")||(tobj[x]!=_10e[x])){ +obj[x]=_10e[x]; +} +} +if(dojo.render.html.ie&&(typeof (_10e["toString"])=="function")&&(_10e["toString"]!=obj["toString"])&&(_10e["toString"]!=tobj["toString"])){ +obj.toString=_10e.toString; +} +return obj; +}; +dojo.lang.mixin=function(obj,_112){ +for(var i=1,l=arguments.length;i-1; +}; +dojo.lang.isObject=function(it){ +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){ +return (it&&it instanceof Array||typeof it=="array"); +}; +dojo.lang.isArrayLike=function(it){ +if((!it)||(dojo.lang.isUndefined(it))){ +return false; +} +if(dojo.lang.isString(it)){ +return false; +} +if(dojo.lang.isFunction(it)){ +return false; +} +if(dojo.lang.isArray(it)){ +return true; +} +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){ +return (it instanceof Function||typeof it=="function"); +}; +(function(){ +if((dojo.render.html.capable)&&(dojo.render.html["safari"])){ +dojo.lang.isFunction=function(it){ +if((typeof (it)=="function")&&(it=="[object NodeList]")){ +return false; +} +return (it instanceof Function||typeof it=="function"); +}; +} +})(); +dojo.lang.isString=function(it){ +return (typeof it=="string"||it instanceof String); +}; +dojo.lang.isAlien=function(it){ +if(!it){ +return false; +} +return !dojo.lang.isFunction(it)&&/\{\s*\[native code\]\s*\}/.test(String(it)); +}; +dojo.lang.isBoolean=function(it){ +return (it instanceof Boolean||typeof it=="boolean"); +}; +dojo.lang.isNumber=function(it){ +return (it instanceof Number||typeof it=="number"); +}; +dojo.lang.isUndefined=function(it){ +return ((typeof (it)=="undefined")&&(it==undefined)); +}; +dojo.provide("dojo.lang.extras"); +dojo.lang.setTimeout=function(func,_132){ +var _133=window,_134=2; +if(!dojo.lang.isFunction(func)){ +_133=func; +func=_132; +_132=arguments[2]; +_134++; +} +if(dojo.lang.isString(func)){ +func=_133[func]; +} +var args=[]; +for(var i=_134;i0){ +dojo.io.bind(dojo.io._bindQueue.shift()); +}else{ +dojo.io._queueBindInFlight=false; +} +} +}; +dojo.io._bindQueue=[]; +dojo.io._queueBindInFlight=false; +dojo.io.argsFromMap=function(map,_170,last){ +var enc=/utf/i.test(_170||"")?encodeURIComponent:dojo.string.encodeAscii; +var _173=[]; +var _174=new Object(); +for(var name in map){ +var _176=function(elt){ +var val=enc(name)+"="+enc(elt); +_173[(last==name)?"push":"unshift"](val); +}; +if(!_174[name]){ +var _179=map[name]; +if(dojo.lang.isArray(_179)){ +dojo.lang.forEach(_179,_176); +}else{ +_176(_179); +} +} +} +return _173.join("&"); +}; +dojo.io.setIFrameSrc=function(_17a,src,_17c){ +try{ +var r=dojo.render.html; +if(!_17c){ +if(r.safari){ +_17a.location=src; +}else{ +frames[_17a.name].location=src; +} +}else{ +var idoc; +if(r.ie){ +idoc=_17a.contentWindow.document; +}else{ +if(r.safari){ +idoc=_17a.document; +}else{ +idoc=_17a.contentWindow; +} +} +if(!idoc){ +_17a.location=src; +return; +}else{ +idoc.location.replace(src); +} +} +} +catch(e){ +dojo.debug(e); +dojo.debug("setIFrameSrc: "+e); +} +}; +dojo.provide("dojo.lang.array"); +dojo.lang.mixin(dojo.lang,{has:function(obj,name){ +try{ +return typeof obj[name]!="undefined"; +} +catch(e){ +return false; +} +},isEmpty:function(obj){ +if(dojo.lang.isObject(obj)){ +var tmp={}; +var _183=0; +for(var x in obj){ +if(obj[x]&&(!tmp[x])){ +_183++; +break; +} +} +return _183==0; +}else{ +if(dojo.lang.isArrayLike(obj)||dojo.lang.isString(obj)){ +return obj.length==0; +} +} +},map:function(arr,obj,_187){ +var _188=dojo.lang.isString(arr); +if(_188){ +arr=arr.split(""); +} +if(dojo.lang.isFunction(obj)&&(!_187)){ +_187=obj; +obj=dj_global; +}else{ +if(dojo.lang.isFunction(obj)&&_187){ +var _189=obj; +obj=_187; +_187=_189; +} +} +if(Array.map){ +var _18a=Array.map(arr,_187,obj); +}else{ +var _18a=[]; +for(var i=0;i=3){ +dojo.raise("thisObject doesn't exist!"); +} +_1a8=dj_global; +} +_1aa=[]; +for(var i=0;i/gm,">").replace(/"/gm,"""); +if(!_1e9){ +str=str.replace(/'/gm,"'"); +} +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"); +}; +dojo.string.summary=function(str,len){ +if(!len||str.length<=len){ +return str; +} +return str.substring(0,len).replace(/\.+$/,"")+"..."; +}; +dojo.string.endsWith=function(str,end,_1f2){ +if(_1f2){ +str=str.toLowerCase(); +end=end.toLowerCase(); +} +if((str.length-end.length)<0){ +return false; +} +return str.lastIndexOf(end)==str.length-end.length; +}; +dojo.string.endsWithAny=function(str){ +for(var i=1;i-1){ +return true; +} +} +return false; +}; +dojo.string.normalizeNewlines=function(text,_1fd){ +if(_1fd=="\n"){ +text=text.replace(/\r\n/g,"\n"); +text=text.replace(/\r/g,"\n"); +}else{ +if(_1fd=="\r"){ +text=text.replace(/\r\n/g,"\r"); +text=text.replace(/\n/g,"\r"); +}else{ +text=text.replace(/([^\r])\n/g,"$1\r\n").replace(/\r([^\n])/g,"\r\n$1"); +} +} +return text; +}; +dojo.string.splitEscaped=function(str,_1ff){ +var _200=[]; +for(var i=0,_202=0;i0){ +return _225[0]; +} +node=node.parentNode; +} +if(_224){ +return null; +} +return _225; +}; +dojo.dom.getAncestorsByTag=function(node,tag,_229){ +tag=tag.toLowerCase(); +return dojo.dom.getAncestors(node,function(el){ +return ((el.tagName)&&(el.tagName.toLowerCase()==tag)); +},_229); +}; +dojo.dom.getFirstAncestorByTag=function(node,tag){ +return dojo.dom.getAncestorsByTag(node,tag,true); +}; +dojo.dom.isDescendantOf=function(node,_22e,_22f){ +if(_22f&&node){ +node=node.parentNode; +} +while(node){ +if(node==_22e){ +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 _232=dojo.doc(); +if(!dj_undef("ActiveXObject")){ +var _233=["MSXML2","Microsoft","MSXML","MSXML3"]; +for(var i=0;i<_233.length;i++){ +try{ +doc=new ActiveXObject(_233[i]+".XMLDOM"); +} +catch(e){ +} +if(doc){ +break; +} +} +}else{ +if((_232.implementation)&&(_232.implementation.createDocument)){ +doc=_232.implementation.createDocument("","",null); +} +} +return doc; +}; +dojo.dom.createDocumentFromText=function(str,_236){ +if(!_236){ +_236="text/xml"; +} +if(!dj_undef("DOMParser")){ +var _237=new DOMParser(); +return _237.parseFromString(str,_236); +}else{ +if(!dj_undef("ActiveXObject")){ +var _238=dojo.dom.createDocument(); +if(_238){ +_238.async=false; +_238.loadXML(str); +return _238; +}else{ +dojo.debug("toXml didn't work?"); +} +}else{ +var _239=dojo.doc(); +if(_239.createElement){ +var tmp=_239.createElement("xml"); +tmp.innerHTML=str; +if(_239.implementation&&_239.implementation.createDocument){ +var _23b=_239.implementation.createDocument("foo","",null); +for(var i=0;i1){ +var _250=dojo.doc(); +dojo.dom.replaceChildren(node,_250.createTextNode(text)); +return text; +}else{ +if(node.textContent!=undefined){ +return node.textContent; +} +var _251=""; +if(node==null){ +return _251; +} +for(var i=0;i"); +} +} +catch(e){ +} +if(dojo.render.html.opera){ +dojo.debug("Opera is not supported with dojo.undo.browser, so back/forward detection will not work."); +} +dojo.undo.browser={initialHref:(!dj_undef("window"))?window.location.href:"",initialHash:(!dj_undef("window"))?window.location.hash:"",moveForward:false,historyStack:[],forwardStack:[],historyIframe:null,bookmarkAnchor:null,locationTimer:null,setInitialState:function(args){ +this.initialState=this._createState(this.initialHref,args,this.initialHash); +},addToHistory:function(args){ +this.forwardStack=[]; +var hash=null; +var url=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"]){ +hash="#"+((args["changeUrl"]!==true)?args["changeUrl"]:(new Date()).getTime()); +if(this.historyStack.length==0&&this.initialState.urlHash==hash){ +this.initialState=this._createState(url,args,hash); +return; +}else{ +if(this.historyStack.length>0&&this.historyStack[this.historyStack.length-1].urlHash==hash){ +this.historyStack[this.historyStack.length-1]=this._createState(url,args,hash); +return; +} +} +this.changingUrl=true; +setTimeout("window.location.href = '"+hash+"'; dojo.undo.browser.changingUrl = false;",1); +this.bookmarkAnchor.href=hash; +if(dojo.render.html.ie){ +url=this._loadIframeHistory(); +var _260=args["back"]||args["backButton"]||args["handle"]; +var tcb=function(_262){ +if(window.location.hash!=""){ +setTimeout("window.location.href = '"+hash+"';",1); +} +_260.apply(this,[_262]); +}; +if(args["back"]){ +args.back=tcb; +}else{ +if(args["backButton"]){ +args.backButton=tcb; +}else{ +if(args["handle"]){ +args.handle=tcb; +} +} +} +var _263=args["forward"]||args["forwardButton"]||args["handle"]; +var tfw=function(_265){ +if(window.location.hash!=""){ +window.location.href=hash; +} +if(_263){ +_263.apply(this,[_265]); +} +}; +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){ +if(!this.locationTimer){ +this.locationTimer=setInterval("dojo.undo.browser.checkLocation();",200); +} +} +} +}else{ +url=this._loadIframeHistory(); +} +this.historyStack.push(this._createState(url,args,hash)); +},checkLocation:function(){ +if(!this.changingUrl){ +var hsl=this.historyStack.length; +if((window.location.hash==this.initialHash||window.location.href==this.initialHref)&&(hsl==1)){ +this.handleBackButton(); +return; +} +if(this.forwardStack.length>0){ +if(this.forwardStack[this.forwardStack.length-1].urlHash==window.location.hash){ +this.handleForwardButton(); +return; +} +} +if((hsl>=2)&&(this.historyStack[hsl-2])){ +if(this.historyStack[hsl-2].urlHash==window.location.hash){ +this.handleBackButton(); +return; +} +} +} +},iframeLoaded:function(evt,_268){ +if(!dojo.render.html.opera){ +var _269=this._getUrlQuery(_268.href); +if(_269==null){ +if(this.historyStack.length==1){ +this.handleBackButton(); +} +return; +} +if(this.moveForward){ +this.moveForward=false; +return; +} +if(this.historyStack.length>=2&&_269==this._getUrlQuery(this.historyStack[this.historyStack.length-2].url)){ +this.handleBackButton(); +}else{ +if(this.forwardStack.length>0&&_269==this._getUrlQuery(this.forwardStack[this.forwardStack.length-1].url)){ +this.handleForwardButton(); +} +} +} +},handleBackButton:function(){ +var _26a=this.historyStack.pop(); +if(!_26a){ +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(_26a); +},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); +},_createState:function(url,args,hash){ +return {"url":url,"kwArgs":args,"urlHash":hash}; +},_getUrlQuery:function(url){ +var _271=url.split("?"); +if(_271.length<2){ +return null; +}else{ +return _271[1]; +} +},_loadIframeHistory:function(){ +var url=dojo.hostenv.getBaseScriptUri()+"iframe_history.html?"+(new Date()).getTime(); +this.moveForward=true; +dojo.io.setIFrameSrc(this.historyIframe,url,false); +return url; +}}; +dojo.provide("dojo.io.BrowserIO"); +if(!dj_undef("window")){ +dojo.io.checkChildrenForFile=function(node){ +var _274=false; +var _275=node.getElementsByTagName("input"); +dojo.lang.forEach(_275,function(_276){ +if(_274){ +return; +} +if(_276.getAttribute("type")=="file"){ +_274=true; +} +}); +return _274; +}; +dojo.io.formHasFile=function(_277){ +return dojo.io.checkChildrenForFile(_277); +}; +dojo.io.updateNode=function(node,_279){ +node=dojo.byId(node); +var args=_279; +if(dojo.lang.isString(_279)){ +args={url:_279}; +} +args.mimetype="text/html"; +args.load=function(t,d,e){ +while(node.firstChild){ +dojo.dom.destroyNode(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); +}; +dojo.io.encodeForm=function(_280,_281,_282){ +if((!_280)||(!_280.tagName)||(!_280.tagName.toLowerCase()=="form")){ +dojo.raise("Attempted to encode a non-form element."); +} +if(!_282){ +_282=dojo.io.formFilter; +} +var enc=/utf/i.test(_281||"")?encodeURIComponent:dojo.string.encodeAscii; +var _284=[]; +for(var i=0;i<_280.elements.length;i++){ +var elm=_280.elements[i]; +if(!elm||elm.tagName.toLowerCase()=="fieldset"||!_282(elm)){ +continue; +} +var name=enc(elm.name); +var type=elm.type.toLowerCase(); +if(type=="select-multiple"){ +for(var j=0;j=200)&&(http.status<300))||(http.status==304)||(location.protocol=="file:"&&(http.status==0||http.status==undefined))||(location.protocol=="chrome:"&&(http.status==0||http.status==undefined))){ +var ret; +if(_2ab.method.toLowerCase()=="head"){ +var _2b1=http.getAllResponseHeaders(); +ret={}; +ret.toString=function(){ +return _2b1; +}; +var _2b2=_2b1.split(/[\r\n]+/g); +for(var i=0;i<_2b2.length;i++){ +var pair=_2b2[i].match(/^([^:]+)\s*:\s*(.+)$/i); +if(pair){ +ret[pair[1]]=pair[2]; +} +} +}else{ +if(_2ab.mimetype=="text/javascript"){ +try{ +ret=dj_eval(http.responseText); +} +catch(e){ +dojo.debug(e); +dojo.debug(http.responseText); +ret=null; +} +}else{ +if(_2ab.mimetype=="text/json"||_2ab.mimetype=="application/json"){ +try{ +ret=dj_eval("("+http.responseText+")"); +} +catch(e){ +dojo.debug(e); +dojo.debug(http.responseText); +ret=false; +} +}else{ +if((_2ab.mimetype=="application/xml")||(_2ab.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(_2af){ +addToCache(url,_2ae,_2ab.method,http); +} +_2ab[(typeof _2ab.load=="function")?"load":"handle"]("load",ret,http,_2ab); +}else{ +var _2b5=new dojo.io.Error("XMLHttpTransport Error: "+http.status+" "+http.statusText); +_2ab[(typeof _2ab.error=="function")?"error":"handle"]("error",_2b5,http,_2ab); +} +} +function setHeaders(http,_2b7){ +if(_2b7["headers"]){ +for(var _2b8 in _2b7["headers"]){ +if(_2b8.toLowerCase()=="content-type"&&!_2b7["contentType"]){ +_2b7["contentType"]=_2b7["headers"][_2b8]; +}else{ +http.setRequestHeader(_2b8,_2b7["headers"][_2b8]); +} +} +} +} +this.inFlight=[]; +this.inFlightTimer=null; +this.startWatchingInFlight=function(){ +if(!this.inFlightTimer){ +this.inFlightTimer=setTimeout("dojo.io.XMLHTTPTransport.watchInFlight();",10); +} +}; +this.watchInFlight=function(){ +var now=null; +if(!dojo.hostenv._blockAsync&&!_29f._blockAsync){ +for(var x=this.inFlight.length-1;x>=0;x--){ +try{ +var tif=this.inFlight[x]; +if(!tif||tif.http._aborted||!tif.http.readyState){ +this.inFlight.splice(x,1); +continue; +} +if(4==tif.http.readyState){ +this.inFlight.splice(x,1); +doLoad(tif.req,tif.http,tif.url,tif.query,tif.useCache); +}else{ +if(tif.startTime){ +if(!now){ +now=(new Date()).getTime(); +} +if(tif.startTime+(tif.req.timeoutSeconds*1000)-1){ +dojo.debug("Warning: dojo.io.bind: stripping hash values from url:",url); +url=url.split("#")[0]; +} +if(_2bf["file"]){ +_2bf.method="post"; +} +if(!_2bf["method"]){ +_2bf.method="get"; +} +if(_2bf.method.toLowerCase()=="get"){ +_2bf.multipart=false; +}else{ +if(_2bf["file"]){ +_2bf.multipart=true; +}else{ +if(!_2bf["multipart"]){ +_2bf.multipart=false; +} +} +} +if(_2bf["backButton"]||_2bf["back"]||_2bf["changeUrl"]){ +dojo.undo.browser.addToHistory(_2bf); +} +var _2c4=_2bf["content"]||{}; +if(_2bf.sendTransport){ +_2c4["dojo.transport"]="xmlhttp"; +} +do{ +if(_2bf.postContent){ +_2c1=_2bf.postContent; +break; +} +if(_2c4){ +_2c1+=dojo.io.argsFromMap(_2c4,_2bf.encoding); +} +if(_2bf.method.toLowerCase()=="get"||!_2bf.multipart){ +break; +} +var t=[]; +if(_2c1.length){ +var q=_2c1.split("&"); +for(var i=0;i-1?"&":"?")+_2c1; +} +if(_2cb){ +_2d1+=(dojo.string.endsWithAny(_2d1,"?","&")?"":(_2d1.indexOf("?")>-1?"&":"?"))+"dojo.preventCache="+new Date().valueOf(); +} +if(!_2bf.user){ +http.open(_2bf.method.toUpperCase(),_2d1,_2ca); +}else{ +http.open(_2bf.method.toUpperCase(),_2d1,_2ca,_2bf.user,_2bf.password); +} +setHeaders(http,_2bf); +try{ +http.send(null); +} +catch(e){ +if(typeof http.abort=="function"){ +http.abort(); +} +doLoad(_2bf,{status:404},url,_2c1,_2cc); +} +} +if(!_2ca){ +doLoad(_2bf,http,url,_2c1,_2cc); +_29f._blockAsync=false; +} +_2bf.abort=function(){ +try{ +http._aborted=true; +} +catch(e){ +} +return http.abort(); +}; +return; +}; +dojo.io.transports.addTransport("XMLHTTPTransport"); +}; +} +dojo.provide("dojo.io.cookie"); +dojo.io.cookie.setCookie=function(name,_2d3,days,path,_2d6,_2d7){ +var _2d8=-1; +if((typeof days=="number")&&(days>=0)){ +var d=new Date(); +d.setTime(d.getTime()+(days*24*60*60*1000)); +_2d8=d.toGMTString(); +} +_2d3=escape(_2d3); +document.cookie=name+"="+_2d3+";"+(_2d8!=-1?" expires="+_2d8+";":"")+(path?"path="+path:"")+(_2d6?"; domain="+_2d6:"")+(_2d7?"; secure":""); +}; +dojo.io.cookie.set=dojo.io.cookie.setCookie; +dojo.io.cookie.getCookie=function(name){ +var idx=document.cookie.lastIndexOf(name+"="); +if(idx==-1){ +return null; +} +var _2dc=document.cookie.substring(idx+name.length+1); +var end=_2dc.indexOf(";"); +if(end==-1){ +end=_2dc.length; +} +_2dc=_2dc.substring(0,end); +_2dc=unescape(_2dc); +return _2dc; +}; +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,_2e3,_2e4,_2e5){ +if(arguments.length==5){ +_2e5=_2e3; +_2e3=null; +_2e4=null; +} +var _2e6=[],_2e7,_2e8=""; +if(!_2e5){ +_2e7=dojo.io.cookie.getObjectCookie(name); +} +if(days>=0){ +if(!_2e7){ +_2e7={}; +} +for(var prop in obj){ +if(obj[prop]==null){ +delete _2e7[prop]; +}else{ +if((typeof obj[prop]=="string")||(typeof obj[prop]=="number")){ +_2e7[prop]=obj[prop]; +} +} +} +prop=null; +for(var prop in _2e7){ +_2e6.push(escape(prop)+"="+escape(_2e7[prop])); +} +_2e8=_2e6.join("&"); +} +dojo.io.cookie.setCookie(name,_2e8,days,path,_2e3,_2e4); +}; +dojo.io.cookie.getObjectCookie=function(name){ +var _2eb=null,_2ec=dojo.io.cookie.getCookie(name); +if(_2ec){ +_2eb={}; +var _2ed=_2ec.split("&"); +for(var i=0;i<_2ed.length;i++){ +var pair=_2ed[i].split("="); +var _2f0=pair[1]; +if(isNaN(_2f0)){ +_2f0=unescape(pair[1]); +} +_2eb[unescape(pair[0])]=_2f0; +} +} +return _2eb; +}; +dojo.io.cookie.isSupported=function(){ +if(typeof navigator.cookieEnabled!="boolean"){ +dojo.io.cookie.setCookie("__TestingYourBrowserForCookieSupport__","CookiesAllowed",90,null); +var _2f1=dojo.io.cookie.getCookie("__TestingYourBrowserForCookieSupport__"); +navigator.cookieEnabled=(_2f1=="CookiesAllowed"); +if(navigator.cookieEnabled){ +this.deleteCookie("__TestingYourBrowserForCookieSupport__"); +} +} +return navigator.cookieEnabled; +}; +if(!dojo.io.cookies){ +dojo.io.cookies=dojo.io.cookie; +} +dojo.provide("dojo.io.*"); +dojo.provide("dojo.event.common"); +dojo.event=new function(){ +this._canTimeout=dojo.lang.isFunction(dj_global["setTimeout"])||dojo.lang.isAlien(dj_global["setTimeout"]); +function interpolateArgs(args,_2f3){ +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 _2f6=dl.nameAnonFunc(args[2],ao.adviceObj,_2f3); +ao.adviceFunc=_2f6; +}else{ +if((dl.isFunction(args[0]))&&(dl.isObject(args[1]))&&(dl.isString(args[2]))){ +ao.adviceType="after"; +ao.srcObj=dj_global; +var _2f6=dl.nameAnonFunc(args[0],ao.srcObj,_2f3); +ao.srcFunc=_2f6; +ao.adviceObj=args[1]; +ao.adviceFunc=args[2]; +} +} +} +} +break; +case 4: +if((dl.isObject(args[0]))&&(dl.isObject(args[2]))){ +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 _2f6=dl.nameAnonFunc(args[1],dj_global,_2f3); +ao.srcFunc=_2f6; +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 _2f6=dl.nameAnonFunc(args[3],dj_global,_2f3); +ao.adviceObj=dj_global; +ao.adviceFunc=_2f6; +}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 _2f6=dl.nameAnonFunc(ao.aroundFunc,ao.aroundObj,_2f3); +ao.aroundFunc=_2f6; +} +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.isString(ao.srcFunc)&&(ao.srcFunc.toLowerCase()=="onkey")){ +if(dojo.render.html.ie){ +ao.srcFunc="onkeydown"; +this.connect(ao); +} +ao.srcFunc="onkeypress"; +} +if(dojo.lang.isArray(ao.srcObj)&&ao.srcObj!=""){ +var _2f8={}; +for(var x in ao){ +_2f8[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); +} +_2f8.srcObj=src; +mjps.push(dojo.event.connect.call(dojo.event,_2f8)); +}); +return mjps; +} +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; +}; +this.log=function(a1,a2){ +var _300; +if((arguments.length==1)&&(typeof a1=="object")){ +_300=a1; +}else{ +_300={srcObj:a1,srcFunc:a2}; +} +_300.adviceFunc=function(){ +var _301=[]; +for(var x=0;x=this.jp_.around.length){ +return this.jp_.object[this.jp_.methodname].apply(this.jp_.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,_318){ +this.object=obj||dj_global; +this.methodname=_318; +this.methodfunc=this.object[_318]; +this.squelch=false; +}; +dojo.event.MethodJoinPoint.getForMethod=function(obj,_31a){ +if(!obj){ +obj=dj_global; +} +if(!obj[_31a]){ +obj[_31a]=function(){ +}; +if(!obj[_31a]){ +dojo.raise("Cannot set do-nothing method on that object "+_31a); +} +}else{ +if((!dojo.lang.isFunction(obj[_31a]))&&(!dojo.lang.isAlien(obj[_31a]))){ +return null; +} +} +var _31b=_31a+"$joinpoint"; +var _31c=_31a+"$joinpoint$method"; +var _31d=obj[_31b]; +if(!_31d){ +var _31e=false; +if(dojo.event["browser"]){ +if((obj["attachEvent"])||(obj["nodeType"])||(obj["addEventListener"])){ +_31e=true; +dojo.event.browser.addClobberNodeAttrs(obj,[_31b,_31c,_31a]); +} +} +var _31f=obj[_31a].length; +obj[_31c]=obj[_31a]; +_31d=obj[_31b]=new dojo.event.MethodJoinPoint(obj,_31c); +obj[_31a]=function(){ +var args=[]; +if((_31e)&&(!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){ +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;x0)){ +dojo.lang.forEach(this.before.concat(new Array()),_337); +} +var _338; +try{ +if((this["around"])&&(this.around.length>0)){ +var mi=new dojo.event.MethodInvocation(this,obj,args); +_338=mi.proceed(); +}else{ +if(this.methodfunc){ +_338=this.object[this.methodname].apply(this.object,args); +} +} +} +catch(e){ +if(!this.squelch){ +dojo.debug(e,"when calling",this.methodname,"on",this.object,"with arguments",args); +dojo.raise(e); +} +} +if((this["after"])&&(this.after.length>0)){ +dojo.lang.forEach(this.after.concat(new Array()),_337); +} +return (this.methodfunc)?_338:null; +},getArr:function(kind){ +var type="after"; +if((typeof kind=="string")&&(kind.indexOf("before")!=-1)){ +type="before"; +}else{ +if(kind=="around"){ +type="around"; +} +} +if(!this[type]){ +this[type]=[]; +} +return this[type]; +},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(_33d,_33e,_33f,_340,_341,_342,once,_344,rate,_346){ +var arr=this.getArr(_341); +if(!arr){ +dojo.raise("bad this: "+this); +} +var ao=[_33d,_33e,_33f,_340,_344,rate,_346]; +if(once){ +if(this.hasAdvice(_33d,_33e,_341,arr)>=0){ +return; +} +} +if(_342=="first"){ +arr.unshift(ao); +}else{ +arr.push(ao); +} +},hasAdvice:function(_349,_34a,_34b,arr){ +if(!arr){ +arr=this.getArr(_34b); +} +var ind=-1; +for(var x=0;x=0;i=i-1){ +var el=na[i]; +try{ +if(el&&el["__clobberAttrs__"]){ +for(var j=0;j=65&&_39c<=90&&evt.shiftKey==false){ +_39c+=32; +} +if(_39c>=1&&_39c<=26&&evt.ctrlKey){ +_39c+=96; +} +evt.key=String.fromCharCode(_39c); +} +} +}else{ +if(evt["type"]=="keypress"){ +if(dojo.render.html.opera){ +if(evt.which==0){ +evt.key=evt.keyCode; +}else{ +if(evt.which>0){ +switch(evt.which){ +case evt.KEY_SHIFT: +case evt.KEY_CTRL: +case evt.KEY_ALT: +case evt.KEY_CAPS_LOCK: +case evt.KEY_NUM_LOCK: +case evt.KEY_SCROLL_LOCK: +break; +case evt.KEY_PAUSE: +case evt.KEY_TAB: +case evt.KEY_BACKSPACE: +case evt.KEY_ENTER: +case evt.KEY_ESCAPE: +evt.key=evt.which; +break; +default: +var _39c=evt.which; +if((evt.ctrlKey||evt.altKey||evt.metaKey)&&(evt.which>=65&&evt.which<=90&&evt.shiftKey==false)){ +_39c+=32; +} +evt.key=String.fromCharCode(_39c); +} +} +} +}else{ +if(dojo.render.html.ie){ +if(!evt.ctrlKey&&!evt.altKey&&evt.keyCode>=evt.KEY_SPACE){ +evt.key=String.fromCharCode(evt.keyCode); +} +}else{ +if(dojo.render.html.safari){ +switch(evt.keyCode){ +case 25: +evt.key=evt.KEY_TAB; +evt.shift=true; +break; +case 63232: +evt.key=evt.KEY_UP_ARROW; +break; +case 63233: +evt.key=evt.KEY_DOWN_ARROW; +break; +case 63234: +evt.key=evt.KEY_LEFT_ARROW; +break; +case 63235: +evt.key=evt.KEY_RIGHT_ARROW; +break; +case 63236: +evt.key=evt.KEY_F1; +break; +case 63237: +evt.key=evt.KEY_F2; +break; +case 63238: +evt.key=evt.KEY_F3; +break; +case 63239: +evt.key=evt.KEY_F4; +break; +case 63240: +evt.key=evt.KEY_F5; +break; +case 63241: +evt.key=evt.KEY_F6; +break; +case 63242: +evt.key=evt.KEY_F7; +break; +case 63243: +evt.key=evt.KEY_F8; +break; +case 63244: +evt.key=evt.KEY_F9; +break; +case 63245: +evt.key=evt.KEY_F10; +break; +case 63246: +evt.key=evt.KEY_F11; +break; +case 63247: +evt.key=evt.KEY_F12; +break; +case 63250: +evt.key=evt.KEY_PAUSE; +break; +case 63272: +evt.key=evt.KEY_DELETE; +break; +case 63273: +evt.key=evt.KEY_HOME; +break; +case 63275: +evt.key=evt.KEY_END; +break; +case 63276: +evt.key=evt.KEY_PAGE_UP; +break; +case 63277: +evt.key=evt.KEY_PAGE_DOWN; +break; +case 63302: +evt.key=evt.KEY_INSERT; +break; +case 63248: +case 63249: +case 63289: +break; +default: +evt.key=evt.charCode>=evt.KEY_SPACE?String.fromCharCode(evt.charCode):evt.keyCode; +} +}else{ +evt.key=evt.charCode>0?String.fromCharCode(evt.charCode):evt.keyCode; +} +} +} +} +} +} +if(dojo.render.html.ie){ +if(!evt.target){ +evt.target=evt.srcElement; +} +if(!evt.currentTarget){ +evt.currentTarget=(_39a?_39a:evt.srcElement); +} +if(!evt.layerX){ +evt.layerX=evt.offsetX; +} +if(!evt.layerY){ +evt.layerY=evt.offsetY; +} +var doc=(evt.srcElement&&evt.srcElement.ownerDocument)?evt.srcElement.ownerDocument:document; +var _39e=((dojo.render.html.ie55)||(doc["compatMode"]=="BackCompat"))?doc.body:doc.documentElement; +if(!evt.pageX){ +evt.pageX=evt.clientX+(_39e.scrollLeft||0); +} +if(!evt.pageY){ +evt.pageY=evt.clientY+(_39e.scrollTop||0); +} +if(evt.type=="mouseover"){ +evt.relatedTarget=evt.fromElement; +} +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(evt){ +if(window.event){ +evt.cancelBubble=true; +evt.returnValue=false; +}else{ +evt.preventDefault(); +evt.stopPropagation(); +} +}; +}; +dojo.provide("dojo.event.*"); +dojo.provide("dojo.gfx.color"); +dojo.gfx.color.Color=function(r,g,b,a){ +if(dojo.lang.isArray(r)){ +this.r=r[0]; +this.g=r[1]; +this.b=r[2]; +this.a=r[3]||1; +}else{ +if(dojo.lang.isString(r)){ +var rgb=dojo.gfx.color.extractRGB(r); +this.r=rgb[0]; +this.g=rgb[1]; +this.b=rgb[2]; +this.a=g||1; +}else{ +if(r instanceof dojo.gfx.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.gfx.color.Color.fromArray=function(arr){ +return new dojo.gfx.color.Color(arr[0],arr[1],arr[2],arr[3]); +}; +dojo.extend(dojo.gfx.color.Color,{toRgb:function(_3a6){ +if(_3a6){ +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.gfx.color.rgb2hex(this.toRgb()); +},toCss:function(){ +return "rgb("+this.toRgb().join()+")"; +},toString:function(){ +return this.toHex(); +},blend:function(_3a7,_3a8){ +var rgb=null; +if(dojo.lang.isArray(_3a7)){ +rgb=_3a7; +}else{ +if(_3a7 instanceof dojo.gfx.color.Color){ +rgb=_3a7.toRgb(); +}else{ +rgb=new dojo.gfx.color.Color(_3a7).toRgb(); +} +} +return dojo.gfx.color.blend(this.toRgb(),rgb,_3a8); +}}); +dojo.gfx.color.named={white:[255,255,255],black:[0,0,0],red:[255,0,0],green:[0,255,0],lime:[0,255,0],blue:[0,0,255],navy:[0,0,128],gray:[128,128,128],silver:[192,192,192]}; +dojo.gfx.color.blend=function(a,b,_3ac){ +if(typeof a=="string"){ +return dojo.gfx.color.blendHex(a,b,_3ac); +} +if(!_3ac){ +_3ac=0; +} +_3ac=Math.min(Math.max(-1,_3ac),1); +_3ac=((_3ac+1)/2); +var c=[]; +for(var x=0;x<3;x++){ +c[x]=parseInt(b[x]+((a[x]-b[x])*_3ac)); +} +return c; +}; +dojo.gfx.color.blendHex=function(a,b,_3b1){ +return dojo.gfx.color.rgb2hex(dojo.gfx.color.blend(dojo.gfx.color.hex2rgb(a),dojo.gfx.color.hex2rgb(b),_3b1)); +}; +dojo.gfx.color.extractRGB=function(_3b2){ +var hex="0123456789abcdef"; +_3b2=_3b2.toLowerCase(); +if(_3b2.indexOf("rgb")==0){ +var _3b4=_3b2.match(/rgba*\((\d+), *(\d+), *(\d+)/i); +var ret=_3b4.splice(1,3); +return ret; +}else{ +var _3b6=dojo.gfx.color.hex2rgb(_3b2); +if(_3b6){ +return _3b6; +}else{ +return dojo.gfx.color.named[_3b2]||[255,255,255]; +} +} +}; +dojo.gfx.color.hex2rgb=function(hex){ +var _3b8="0123456789ABCDEF"; +var rgb=new Array(3); +if(hex.indexOf("#")==0){ +hex=hex.substring(1); +} +hex=hex.toUpperCase(); +if(hex.replace(new RegExp("["+_3b8+"]","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;i0){ +this.duration=_3d8; +} +if(_3db){ +this.repeatCount=_3db; +} +if(rate){ +this.rate=rate; +} +if(_3d7){ +dojo.lang.forEach(["handler","beforeBegin","onBegin","onEnd","onPlay","onStop","onAnimate"],function(item){ +if(_3d7[item]){ +this.connect(item,_3d7[item]); +} +},this); +} +if(_3da&&dojo.lang.isFunction(_3da)){ +this.easing=_3da; +} +}; +dojo.inherits(dojo.lfx.Animation,dojo.lfx.IAnimation); +dojo.lang.extend(dojo.lfx.Animation,{_startTime:null,_endTime:null,_timer:null,_percent:0,_startRepeatCount:0,play:function(_3de,_3df){ +if(_3df){ +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(_3de>0){ +setTimeout(dojo.lang.hitch(this,function(){ +this.play(null,_3df); +}),_3de); +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 _3e1=this.curve.getValue(step); +if(this._percent==0){ +if(!this._startRepeatCount){ +this._startRepeatCount=this.repeatCount; +} +this.fire("handler",["begin",_3e1]); +this.fire("onBegin",[_3e1]); +} +this.fire("handler",["play",_3e1]); +this.fire("onPlay",[_3e1]); +this._cycle(); +return this; +},pause:function(){ +clearTimeout(this._timer); +if(!this._active){ +return this; +} +this._paused=true; +var _3e2=this.curve.getValue(this._percent/100); +this.fire("handler",["pause",_3e2]); +this.fire("onPause",[_3e2]); +return this; +},gotoPercent:function(pct,_3e4){ +clearTimeout(this._timer); +this._active=true; +this._paused=true; +this._percent=pct; +if(_3e4){ +this.play(); +} +return this; +},stop:function(_3e5){ +clearTimeout(this._timer); +var step=this._percent/100; +if(_3e5){ +step=1; +} +var _3e7=this.curve.getValue(step); +this.fire("handler",["stop",_3e7]); +this.fire("onStop",[_3e7]); +this._active=false; +this._paused=false; +return this; +},status:function(){ +if(this._active){ +return this._paused?"paused":"playing"; +}else{ +return "stopped"; +} +return this; +},_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; +} +if((this.easing)&&(dojo.lang.isFunction(this.easing))){ +step=this.easing(step); +} +var _3ea=this.curve.getValue(step); +this.fire("handler",["animate",_3ea]); +this.fire("onAnimate",[_3ea]); +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(_3eb){ +dojo.lfx.IAnimation.call(this); +this._anims=[]; +this._animsEnded=0; +var _3ec=arguments; +if(_3ec.length==1&&(dojo.lang.isArray(_3ec[0])||dojo.lang.isArrayLike(_3ec[0]))){ +_3ec=_3ec[0]; +} +dojo.lang.forEach(_3ec,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,{_animsEnded:0,play:function(_3ee,_3ef){ +if(!this._anims.length){ +return this; +} +this.fire("beforeBegin"); +if(_3ee>0){ +setTimeout(dojo.lang.hitch(this,function(){ +this.play(null,_3ef); +}),_3ee); +return this; +} +if(_3ef||this._anims[0].percent==0){ +this.fire("onBegin"); +} +this.fire("onPlay"); +this._animsCall("play",null,_3ef); +return this; +},pause:function(){ +this.fire("onPause"); +this._animsCall("pause"); +return this; +},stop:function(_3f0){ +this.fire("onStop"); +this._animsCall("stop",_3f0); +return this; +},_onAnimsEnded:function(){ +this._animsEnded++; +if(this._animsEnded>=this._anims.length){ +this.fire("onEnd"); +} +return this; +},_animsCall:function(_3f1){ +var args=[]; +if(arguments.length>1){ +for(var i=1;i0){ +setTimeout(dojo.lang.hitch(this,function(){ +this.play(null,_3fd); +}),_3fc); +return this; +} +if(_3fe){ +if(this._currAnim==0){ +this.fire("handler",["begin",this._currAnim]); +this.fire("onBegin",[this._currAnim]); +} +this.fire("onPlay",[this._currAnim]); +_3fe.play(null,_3fd); +} +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 _3ff=this._anims[this._currAnim]; +if(_3ff){ +if(!_3ff._active||_3ff._paused){ +this.play(); +}else{ +this.pause(); +} +} +return this; +},stop:function(){ +var _400=this._anims[this._currAnim]; +if(_400){ +_400.stop(); +this.fire("onStop",[this._currAnim]); +} +return _400; +},_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(_401){ +var _402=arguments; +if(dojo.lang.isArray(arguments[0])){ +_402=arguments[0]; +} +if(_402.length==1){ +return _402[0]; +} +return new dojo.lfx.Combine(_402); +}; +dojo.lfx.chain=function(_403){ +var _404=arguments; +if(dojo.lang.isArray(arguments[0])){ +_404=arguments[0]; +} +if(_404.length==1){ +return _404[0]; +} +return new dojo.lfx.Chain(_404); +}; +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(); +}; +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 _407=dojo.global(); +var _408=dojo.doc(); +var w=0; +var h=0; +if(dojo.render.html.mozilla){ +w=_408.documentElement.clientWidth; +h=_407.innerHeight; +}else{ +if(!dojo.render.html.opera&&_407.innerWidth){ +w=_407.innerWidth; +h=_407.innerHeight; +}else{ +if(!dojo.render.html.opera&&dojo.exists(_408,"documentElement.clientWidth")){ +var w2=_408.documentElement.clientWidth; +if(!w||w2&&w20&&!(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; +} +} +} +} +_431.path=segs.join("/"); +} +} +} +} +uri=""; +if(_431.scheme!=null){ +uri+=_431.scheme+":"; +} +if(_431.authority!=null){ +uri+="//"+_431.authority; +} +uri+=_431.path; +if(_431.query!=null){ +uri+="?"+_431.query; +} +if(_431.fragment!=null){ +uri+="#"+_431.fragment; +} +} +this.uri=uri.toString(); +var _436="^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"; +var r=this.uri.match(new RegExp(_436)); +this.scheme=r[2]||(r[1]?"":null); +this.authority=r[4]||(r[3]?"":null); +this.path=r[5]; +this.query=r[7]||(r[6]?"":null); +this.fragment=r[9]||(r[8]?"":null); +if(this.authority!=null){ +_436="^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$"; +r=this.authority.match(new RegExp(_436)); +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.html.style"); +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,""); +}; +dojo.html.getClasses=function(node){ +var c=dojo.html.getClass(node); +return (c=="")?[]:c.split(/\s+/g); +}; +dojo.html.hasClass=function(node,_43d){ +return (new RegExp("(^|\\s+)"+_43d+"(\\s+|$)")).test(dojo.html.getClass(node)); +}; +dojo.html.prependClass=function(node,_43f){ +_43f+=" "+dojo.html.getClass(node); +return dojo.html.setClass(node,_43f); +}; +dojo.html.addClass=function(node,_441){ +if(dojo.html.hasClass(node,_441)){ +return false; +} +_441=(dojo.html.getClass(node)+" "+_441).replace(/^\s+|\s+$/g,""); +return dojo.html.setClass(node,_441); +}; +dojo.html.setClass=function(node,_443){ +node=dojo.byId(node); +var cs=new String(_443); +try{ +if(typeof node.className=="string"){ +node.className=cs; +}else{ +if(node.setAttribute){ +node.setAttribute("class",_443); +node.className=cs; +}else{ +return false; +} +} +} +catch(e){ +dojo.debug("dojo.html.setClass() failed",e); +} +return true; +}; +dojo.html.removeClass=function(node,_446,_447){ +try{ +if(!_447){ +var _448=dojo.html.getClass(node).replace(new RegExp("(^|\\s+)"+_446+"(\\s+|$)"),"$1$2"); +}else{ +var _448=dojo.html.getClass(node).replace(_446,""); +} +dojo.html.setClass(node,_448); +} +catch(e){ +dojo.debug("dojo.html.removeClass() failed",e); +} +return true; +}; +dojo.html.replaceClass=function(node,_44a,_44b){ +dojo.html.removeClass(node,_44b); +dojo.html.addClass(node,_44a); +}; +dojo.html.classMatchType={ContainsAll:0,ContainsAny:1,IsOnly:2}; +dojo.html.getElementsByClass=function(_44c,_44d,_44e,_44f,_450){ +_450=false; +var _451=dojo.doc(); +_44d=dojo.byId(_44d)||_451; +var _452=_44c.split(/\s+/g); +var _453=[]; +if(_44f!=1&&_44f!=2){ +_44f=0; +} +var _454=new RegExp("(\\s|^)(("+_452.join(")|(")+"))(\\s|$)"); +var _455=_452.join(" ").length; +var _456=[]; +if(!_450&&_451.evaluate){ +var _457=".//"+(_44e||"*")+"[contains("; +if(_44f!=dojo.html.classMatchType.ContainsAny){ +_457+="concat(' ',@class,' '), ' "+_452.join(" ') and contains(concat(' ',@class,' '), ' ")+" ')"; +if(_44f==2){ +_457+=" and string-length(@class)="+_455+"]"; +}else{ +_457+="]"; +} +}else{ +_457+="concat(' ',@class,' '), ' "+_452.join(" ') or contains(concat(' ',@class,' '), ' ")+" ')]"; +} +var _458=_451.evaluate(_457,_44d,null,XPathResult.ANY_TYPE,null); +var _459=_458.iterateNext(); +while(_459){ +try{ +_456.push(_459); +_459=_458.iterateNext(); +} +catch(e){ +break; +} +} +return _456; +}else{ +if(!_44e){ +_44e="*"; +} +_456=_44d.getElementsByTagName(_44e); +var node,i=0; +outer: +while(node=_456[i++]){ +var _45c=dojo.html.getClasses(node); +if(_45c.length==0){ +continue outer; +} +var _45d=0; +for(var j=0;j<_45c.length;j++){ +if(_454.test(_45c[j])){ +if(_44f==dojo.html.classMatchType.ContainsAny){ +_453.push(node); +continue outer; +}else{ +_45d++; +} +}else{ +if(_44f==dojo.html.classMatchType.IsOnly){ +continue outer; +} +} +} +if(_45d==_452.length){ +if((_44f==dojo.html.classMatchType.IsOnly)&&(_45d==_45c.length)){ +_453.push(node); +}else{ +if(_44f==dojo.html.classMatchType.ContainsAll){ +_453.push(node); +} +} +} +} +return _453; +} +}; +dojo.html.getElementsByClassName=dojo.html.getElementsByClass; +dojo.html.toCamelCase=function(_45f){ +var arr=_45f.split("-"),cc=arr[0]; +for(var i=1;i=1){ +if(h.ie){ +dojo.html.clearOpacity(node); +return; +}else{ +_4c5=0.999999; +} +}else{ +if(_4c5<0){ +_4c5=0; +} +} +} +if(h.ie){ +if(node.nodeName.toLowerCase()=="tr"){ +var tds=node.getElementsByTagName("td"); +for(var x=0;x=0.999999?1:Number(opac); +}; +dojo.provide("dojo.html.color"); +dojo.html.getBackgroundColor=function(node){ +node=dojo.byId(node); +var _4d1; +do{ +_4d1=dojo.html.getStyle(node,"background-color"); +if(_4d1.toLowerCase()=="rgba(0, 0, 0, 0)"){ +_4d1="transparent"; +} +if(node==document.getElementsByTagName("body")[0]){ +node=null; +break; +} +node=node.parentNode; +}while(node&&dojo.lang.inArray(["transparent",""],_4d1)); +if(_4d1=="transparent"){ +_4d1=[255,255,255,0]; +}else{ +_4d1=dojo.gfx.color.extractRGB(_4d1); +} +return _4d1; +}; +dojo.provide("dojo.html.layout"); +dojo.html.sumAncestorProperties=function(node,prop){ +node=dojo.byId(node); +if(!node){ +return 0; +} +var _4d4=0; +while(node){ +if(dojo.html.getComputedStyle(node,"position")=="fixed"){ +return 0; +} +var val=node[prop]; +if(val){ +_4d4+=val-0; +if(node==dojo.body()){ +break; +} +} +node=node.parentNode; +} +return _4d4; +}; +dojo.html.setStyleAttributes=function(node,_4d7){ +node=dojo.byId(node); +var _4d8=_4d7.replace(/(;)?\s*$/,"").split(";"); +for(var i=0;i<_4d8.length;i++){ +var _4da=_4d8[i].split(":"); +var name=_4da[0].replace(/\s*$/,"").replace(/^\s*/,"").toLowerCase(); +var _4dc=_4da[1].replace(/\s*$/,"").replace(/^\s*/,""); +switch(name){ +case "opacity": +dojo.html.setOpacity(node,_4dc); +break; +case "content-height": +dojo.html.setContentBox(node,{height:_4dc}); +break; +case "content-width": +dojo.html.setContentBox(node,{width:_4dc}); +break; +case "outer-height": +dojo.html.setMarginBox(node,{height:_4dc}); +break; +case "outer-width": +dojo.html.setMarginBox(node,{width:_4dc}); +break; +default: +node.style[dojo.html.toCamelCase(name)]=_4dc; +} +} +}; +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,_4de,_4df){ +node=dojo.byId(node,node.ownerDocument); +var ret={x:0,y:0}; +var bs=dojo.html.boxSizing; +if(!_4df){ +_4df=bs.CONTENT_BOX; +} +var _4e2=2; +var _4e3; +switch(_4df){ +case bs.MARGIN_BOX: +_4e3=3; +break; +case bs.BORDER_BOX: +_4e3=2; +break; +case bs.PADDING_BOX: +default: +_4e3=1; +break; +case bs.CONTENT_BOX: +_4e3=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){ +_4e2=1; +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){ +} +}else{ +if(node["offsetParent"]){ +var _4e7; +if((h.safari)&&(node.style.getPropertyValue("position")=="absolute")&&(node.parentNode==db)){ +_4e7=db; +}else{ +_4e7=db.parentNode; +} +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 _4e9=node; +do{ +var n=_4e9["offsetLeft"]; +if(!h.opera||n>0){ +ret.x+=isNaN(n)?0:n; +} +var m=_4e9["offsetTop"]; +ret.y+=isNaN(m)?0:m; +_4e9=_4e9.offsetParent; +}while((_4e9!=_4e7)&&(_4e9!=null)); +}else{ +if(node["x"]&&node["y"]){ +ret.x+=isNaN(node.x)?0:node.x; +ret.y+=isNaN(node.y)?0:node.y; +} +} +} +} +if(_4de){ +var _4ec=dojo.html.getScroll(); +ret.y+=_4ec.top; +ret.x+=_4ec.left; +} +var _4ed=[dojo.html.getPaddingExtent,dojo.html.getBorderExtent,dojo.html.getMarginExtent]; +if(_4e2>_4e3){ +for(var i=_4e3;i<_4e2;++i){ +ret.y+=_4ed[i](node,"top"); +ret.x+=_4ed[i](node,"left"); +} +}else{ +if(_4e2<_4e3){ +for(var i=_4e3;i>_4e2;--i){ +ret.y-=_4ed[i-1](node,"top"); +ret.x-=_4ed[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,_4f1,_4f2){ +var _4f3=0; +for(var x=0;x<_4f1.length;x++){ +_4f3+=dojo.html.getPixelValue(node,_4f1[x],_4f2); +} +return _4f3; +}; +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 _500=dojo.html.getBorder(node); +return {width:pad.width+_500.width,height:pad.height+_500.height}; +}; +dojo.html.getBoxSizing=function(node){ +var h=dojo.render.html; +var bs=dojo.html.boxSizing; +if(((h.ie)||(h.opera))&&node.nodeName!="IMG"){ +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 _505=dojo.html.getStyle(node,"-moz-box-sizing"); +if(!_505){ +_505=dojo.html.getStyle(node,"box-sizing"); +} +return (_505?_505: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 _50a=dojo.html.getBorder(node); +return {width:box.width-_50a.width,height:box.height-_50a.height}; +}; +dojo.html.getContentBox=function(node){ +node=dojo.byId(node); +var _50c=dojo.html.getPadBorder(node); +return {width:node.offsetWidth-_50c.width,height:node.offsetHeight-_50c.height}; +}; +dojo.html.setContentBox=function(node,args){ +node=dojo.byId(node); +var _50f=0; +var _510=0; +var isbb=dojo.html.isBorderBox(node); +var _512=(isbb?dojo.html.getPadBorder(node):{width:0,height:0}); +var ret={}; +if(typeof args.width!="undefined"){ +_50f=args.width+_512.width; +ret.width=dojo.html.setPositivePixelValue(node,"width",_50f); +} +if(typeof args.height!="undefined"){ +_510=args.height+_512.height; +ret.height=dojo.html.setPositivePixelValue(node,"height",_510); +} +return ret; +}; +dojo.html.getMarginBox=function(node){ +var _515=dojo.html.getBorderBox(node); +var _516=dojo.html.getMargin(node); +return {width:_515.width+_516.width,height:_515.height+_516.height}; +}; +dojo.html.setMarginBox=function(node,args){ +node=dojo.byId(node); +var _519=0; +var _51a=0; +var isbb=dojo.html.isBorderBox(node); +var _51c=(!isbb?dojo.html.getPadBorder(node):{width:0,height:0}); +var _51d=dojo.html.getMargin(node); +var ret={}; +if(typeof args.width!="undefined"){ +_519=args.width-_51c.width; +_519-=_51d.width; +ret.width=dojo.html.setPositivePixelValue(node,"width",_519); +} +if(typeof args.height!="undefined"){ +_51a=args.height-_51c.height; +_51a-=_51d.height; +ret.height=dojo.html.setPositivePixelValue(node,"height",_51a); +} +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); +} +}; +dojo.html.toCoordinateObject=dojo.html.toCoordinateArray=function(_522,_523,_524){ +if(_522 instanceof Array||typeof _522=="array"){ +dojo.deprecated("dojo.html.toCoordinateArray","use dojo.html.toCoordinateObject({left: , top: , width: , height: }) instead","0.5"); +while(_522.length<4){ +_522.push(0); +} +while(_522.length>4){ +_522.pop(); +} +var ret={left:_522[0],top:_522[1],width:_522[2],height:_522[3]}; +}else{ +if(!_522.nodeType&&!(_522 instanceof String||typeof _522=="string")&&("width" in _522||"height" in _522||"left" in _522||"x" in _522||"top" in _522||"y" in _522)){ +var ret={left:_522.left||_522.x||0,top:_522.top||_522.y||0,width:_522.width||0,height:_522.height||0}; +}else{ +var node=dojo.byId(_522); +var pos=dojo.html.abs(node,_523,_524); +var _528=dojo.html.getMarginBox(node); +var ret={left:pos.left,top:pos.top,width:_528.width,height:_528.height}; +} +} +ret.x=ret.left; +ret.y=ret.top; +return ret; +}; +dojo.html.setMarginBoxWidth=dojo.html.setOuterWidth=function(node,_52a){ +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,_52d){ +return dojo.html._callDeprecated("getTotalOffset","getAbsolutePosition",arguments,null,type); +}; +dojo.html.getAbsoluteX=function(node,_52f){ +return dojo.html._callDeprecated("getAbsoluteX","getAbsolutePosition",arguments,null,"x"); +}; +dojo.html.getAbsoluteY=function(node,_531){ +return dojo.html._callDeprecated("getAbsoluteY","getAbsolutePosition",arguments,null,"y"); +}; +dojo.html.totalOffsetLeft=function(node,_533){ +return dojo.html._callDeprecated("totalOffsetLeft","getAbsolutePosition",arguments,null,"left"); +}; +dojo.html.totalOffsetTop=function(node,_535){ +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,_53f){ +return dojo.html._callDeprecated("setContentBoxWidth","setContentBox",arguments,"width"); +}; +dojo.html.setContentBoxHeight=dojo.html.setContentHeight=function(node,_541){ +return dojo.html._callDeprecated("setContentBoxHeight","setContentBox",arguments,"height"); +}; +dojo.provide("dojo.lfx.html"); +dojo.lfx.html._byId=function(_542){ +if(!_542){ +return []; +} +if(dojo.lang.isArrayLike(_542)){ +if(!_542.alreadyChecked){ +var n=[]; +dojo.lang.forEach(_542,function(node){ +n.push(dojo.byId(node)); +}); +n.alreadyChecked=true; +return n; +}else{ +return _542; +} +}else{ +var n=[]; +n.push(dojo.byId(_542)); +n.alreadyChecked=true; +return n; +} +}; +dojo.lfx.html.propertyAnimation=function(_545,_546,_547,_548,_549){ +_545=dojo.lfx.html._byId(_545); +var _54a={"propertyMap":_546,"nodes":_545,"duration":_547,"easing":_548||dojo.lfx.easeDefault}; +var _54b=function(args){ +if(args.nodes.length==1){ +var pm=args.propertyMap; +if(!dojo.lang.isArray(args.propertyMap)){ +var parr=[]; +for(var _54f in pm){ +pm[_54f].property=_54f; +parr.push(pm[_54f]); +} +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 _551=function(_552){ +var _553=[]; +dojo.lang.forEach(_552,function(c){ +_553.push(Math.round(c)); +}); +return _553; +}; +var _555=function(n,_557){ +n=dojo.byId(n); +if(!n||!n.style){ +return; +} +for(var s in _557){ +try{ +if(s=="opacity"){ +dojo.html.setOpacity(n,_557[s]); +}else{ +n.style[s]=_557[s]; +} +} +catch(e){ +dojo.debug(e); +} +} +}; +var _559=function(_55a){ +this._properties=_55a; +this.diffs=new Array(_55a.length); +dojo.lang.forEach(_55a,function(prop,i){ +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)){ +this.diffs[i]=null; +}else{ +if(prop.start instanceof dojo.gfx.color.Color){ +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 _561=null; +if(dojo.lang.isArray(prop.start)){ +}else{ +if(prop.start instanceof dojo.gfx.color.Color){ +_561=(prop.units||"rgb")+"("; +for(var j=0;j3){ +_5d6.pop(); +} +var rgb=new dojo.gfx.color.Color(_5d0); +var _5db=new dojo.gfx.color.Color(_5d6); +var anim=dojo.lfx.propertyAnimation(node,{"background-color":{start:rgb,end:_5db}},_5d1,_5d2,{"beforeBegin":function(){ +if(_5d8){ +node.style.backgroundImage="none"; +} +node.style.backgroundColor="rgb("+rgb.toRgb().join(",")+")"; +},"onEnd":function(){ +if(_5d8){ +node.style.backgroundImage=_5d8; +} +if(_5d9){ +node.style.backgroundColor="transparent"; +} +if(_5d3){ +_5d3(node,anim); +} +}}); +_5d4.push(anim); +}); +return dojo.lfx.combine(_5d4); +}; +dojo.lfx.html.unhighlight=function(_5dd,_5de,_5df,_5e0,_5e1){ +_5dd=dojo.lfx.html._byId(_5dd); +var _5e2=[]; +dojo.lang.forEach(_5dd,function(node){ +var _5e4=new dojo.gfx.color.Color(dojo.html.getBackgroundColor(node)); +var rgb=new dojo.gfx.color.Color(_5de); +var _5e6=dojo.html.getStyle(node,"background-image"); +var anim=dojo.lfx.propertyAnimation(node,{"background-color":{start:_5e4,end:rgb}},_5df,_5e0,{"beforeBegin":function(){ +if(_5e6){ +node.style.backgroundImage="none"; +} +node.style.backgroundColor="rgb("+_5e4.toRgb().join(",")+")"; +},"onEnd":function(){ +if(_5e1){ +_5e1(node,anim); +} +}}); +_5e2.push(anim); +}); +return dojo.lfx.combine(_5e2); +}; +dojo.lang.mixin(dojo.lfx,dojo.lfx.html); +dojo.provide("dojo.lfx.*"); + diff --git a/source/web/scripts/ajax/dojo/dojo.js.uncompressed.js b/source/web/scripts/ajax/dojo/dojo.js.uncompressed.js new file mode 100644 index 0000000000..764357e5ba --- /dev/null +++ b/source/web/scripts/ajax/dojo/dojo.js.uncompressed.js @@ -0,0 +1,9694 @@ +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: bootstrap1.js 6824 2006-12-06 09:34:32Z alex $ +*/ + +// 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). +var dj_global = this; + +//TODOC: HOW TO DOC THIS? +// @global: dj_currentContext +// summary: +// Private global context object. Where 'dj_global' always refers to the boot-time +// global context, 'dj_currentContext' can be modified for temporary context shifting. +// dojo.global() returns dj_currentContext. +// description: +// Refer to dojo.global() rather than referring to dj_global to ensure your +// code runs correctly in managed contexts. +var dj_currentContext = this; + + +// **************************************************************** +// global public utils +// TODOC: DO WE WANT TO NOTE THAT THESE ARE GLOBAL PUBLIC UTILS? +// **************************************************************** + +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. + return (typeof (object || dj_currentContext)[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 = {}; +} + +dojo.global = function(){ + // summary: + // return the current global context object + // (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 dj_currentContext; +} + +// 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: 4, patch: 1, flag: "", + revision: Number("$Rev: 6824 $".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. + if((!object)||(!name)) return undefined; // undefined + if(!dj_undef(name, object)) return object[name]; // mixed + return (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 'dojo.global()'. + // create: If true, Objects will be created at any point along the 'path' that is undefined. + var object = (context || dojo.global()); + var names = path.split('.'); + var prop = names.pop(); + for (var i=0,l=names.length;i 1) { + dh.modulesLoadedListeners.push(function() { + obj[functionName](); + }); + } + + //Added for xdomain loading. dojo.addOnLoad is used to + //indicate callbacks after doing some dojo.require() statements. + //In the xdomain case, if all the requires are loaded (after initial + //page load), then immediately call any listeners. + if(dh.post_load_ && dh.inFlightCount == 0 && !dh.loadNotifying){ + dh.callLoaded(); + } +} + +dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){ +// summary: registers a function to be triggered when the page unloads +// +// usage: +// dojo.addOnLoad(functionPointer) +// dojo.addOnLoad(object, "functionName") + var dh = dojo.hostenv; + if(arguments.length == 1){ + dh.unloadListeners.push(obj); + } else if(arguments.length > 1) { + dh.unloadListeners.push(function() { + obj[functionName](); + }); + } +} + +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(/*String*/modulename){ +// summary: +// Converts a module name in dotted JS notation to an array representing the path in the source tree + var syms = modulename.split("."); + for(var i = syms.length; i>0; i--){ + var parentModule = syms.slice(0, i).join("."); + if((i==1) && !this.moduleHasPrefix(parentModule)){ + // Support default module directory (sibling of dojo) for top-level modules + syms[0] = "../" + syms[0]; + }else{ + var parentModulePath = this.getModulePrefix(parentModule); + if(parentModulePath != parentModule){ + syms.splice(0, i, parentModulePath); + break; + } + } + } + return syms; // Array +} + +dojo.hostenv._global_omit_module_check = false; +dojo.hostenv.loadModule = function(/*String*/moduleName, /*Boolean?*/exactOnly, /*Boolean?*/omitModuleCheck){ +// summary: +// loads a Javascript module from the appropriate URI +// +// description: +// loadModule("A.B") first checks to see if symbol A.B is defined. +// If it is, it is simply returned (nothing to do). +// +// If it is not defined, it will look for "A/B.js" in the script root directory, +// 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 + + if(!moduleName){ return; } + omitModuleCheck = this._global_omit_module_check || omitModuleCheck; + 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("."); + + // this line allowed loading of a module manifest as if it were a namespace + // it's an interesting idea, but shouldn't be combined with 'namespaces' proper + // and leads to unwanted dependencies + // the effect can be achieved in other (albeit less-flexible) ways now, so I am + // removing this pending further design work + // perhaps we can explicitly define this idea of a 'module manifest', and subclass + // 'namespace manifest' from that + //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]; + var ok; + // 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, !omitModuleCheck ? moduleName : null); + if(ok){ break; } + syms.pop(); + } + }else{ + relpath = syms.join("/") + '.js'; + moduleName = nsyms.join('.'); + var modArg = !omitModuleCheck ? moduleName : null; + ok = this.loadPath(relpath, modArg); + if(!ok && !exactOnly){ + syms.pop(); + while(syms.length){ + relpath = syms.join('/') + '.js'; + ok = this.loadPath(relpath, modArg); + if(ok){ break; } + syms.pop(); + relpath = syms.join('/') + '/'+this.pkgFileName+'.js'; + if(startedRelative && relpath.charAt(0)=="/"){ + relpath = relpath.slice(1); + } + ok = this.loadPath(relpath, modArg); + if(ok){ break; } + } + } + + if(!ok && !omitModuleCheck){ + 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(!omitModuleCheck && !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; +} + +dojo.hostenv.startPackage = function(/*String*/packageName){ +// summary: +// Creates a JavaScript package +// +// description: +// startPackage("A.B") follows the path, and at each level creates a new empty +// object or uses what already exists. It returns the result. +// +// packageName: the package to be created as a String in dot notation + + //Make sure we have a string. + var fullPkgName = String(packageName); + var strippedPkgName = fullPkgName; + + var syms = packageName.split(/\./); + if(syms[syms.length-1]=="*"){ + syms.pop(); + strippedPkgName = syms.join("."); + } + var evaledPkg = dojo.evalObjPath(strippedPkgName, true); + this.loaded_modules_[fullPkgName] = evaledPkg; + this.loaded_modules_[strippedPkgName] = evaledPkg; + + return evaledPkg; // Object +} + +dojo.hostenv.findModule = function(/*String*/moduleName, /*Boolean?*/mustExist){ +// summary: +// Returns the Object representing the module, if it exists, otherwise null. +// +// moduleName A fully qualified module including package name, like 'A.B'. +// mustExist Optional, default false. throw instead of returning null +// if the module does not currently exist. + + var lmn = String(moduleName); + + if(this.loaded_modules_[lmn]){ + return this.loaded_modules_[lmn]; // Object + } + + if(mustExist){ + dojo.raise("no loaded module named '" + moduleName + "'"); + } + return null; // null +} + +//Start of old bootstrap2: + +dojo.kwCompoundRequire = function(/*Object containing Arrays*/modMap){ +// description: +// This method taks a "map" of arrays which one can use to optionally load dojo +// modules. The map is indexed by the possible dojo.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.*" ] +// }); + + 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, + // relative to Dojo root. For example, module acme is mapped to ../acme. + // If you want to use a different module name, use dojo.registerModulePath. + return dojo.hostenv.setModulePrefix(module, prefix); +} + +dojo.setModulePrefix = function(/*String*/module, /*String*/prefix){ + // summary: maps a module name to a path + dojo.deprecated('dojo.setModulePrefix("' + module + '", "' + prefix + '")', "replaced by dojo.registerModulePath", "0.5"); + return dojo.registerModulePath(module, prefix); +} + +dojo.exists = function(/*Object*/obj, /*String*/name){ + // summary: determine if an object supports a given method + // description: useful for longer api chains where you have to test each object in the chain + var p = name.split("."); + for(var i = 0; i < p.length; i++){ + if(!obj[p[i]]){ return false; } // Boolean + obj = obj[p[i]]; + } + return true; // Boolean +} + +// Localization routines + +dojo.hostenv.normalizeLocale = function(/*String?*/locale){ +// summary: +// Returns canonical form of locale, as used by Dojo. All variants are case-insensitive and are separated by '-' +// as specified in RFC 3066. If no locale is specified, the user agent's default is returned. + + var result = locale ? locale.toLowerCase() : dojo.locale; + if(result == "root"){ + result = "ROOT"; + } + return result;// String +}; + +dojo.hostenv.searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){ +// summary: +// A helper method to assist in searching for locale-based resources. Will iterate through +// the variants of a particular locale, either up or down, executing a callback function. +// For example, "en-us" and true will try "en-us" followed by "en" and finally "ROOT". + + locale = dojo.hostenv.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; } + } +} + +//These two functions are placed outside of preloadLocalizations +//So that the xd loading can use/override them. +dojo.hostenv.localesGenerated /***BUILD:localesGenerated***/; // value will be inserted here at build time, if necessary + +dojo.hostenv.registerNlsPrefix = function(){ +// summary: +// Register module "nls" to point where Dojo can find pre-built localization files + dojo.registerModulePath("nls","nls"); +} + +dojo.hostenv.preloadLocalizations = function(){ +// summary: +// Load built, flattened resource bundles, if available for all locales used in the page. +// Execute only once. Note that this is a no-op unless there is a build. + + if(dojo.hostenv.localesGenerated){ + dojo.hostenv.registerNlsPrefix(); + + function preload(locale){ + locale = dojo.hostenv.normalizeLocale(locale); + dojo.hostenv.searchLocalePath(locale, true, function(loc){ + for(var i=0; i bestLocale.length){ + bestLocale = flatLocales[i]; + } + } + } + if(!bestLocale){ + bestLocale = "ROOT"; + } + } + + //See if the desired locale is already loaded. + var tempLocale = availableFlatLocales ? bestLocale : targetLocale; + var bundle = dojo.hostenv.findModule(bundlePackage); + var localizedBundle = null; + if(bundle){ + if(djConfig.localizationComplete && bundle._built){return;} + var jsLoc = tempLocale.replace('-', '_'); + var translationPackage = bundlePackage+"."+jsLoc; + localizedBundle = dojo.hostenv.findModule(translationPackage); + } + + if(!localizedBundle){ + bundle = dojo.hostenv.startPackage(bundlePackage); + var syms = dojo.hostenv.getModuleSymbols(moduleName); + var modpath = syms.concat("nls").join("/"); + var parent; + + dojo.hostenv.searchLocalePath(tempLocale, availableFlatLocales, function(loc){ + var jsLoc = loc.replace('-', '_'); + var translationPackage = bundlePackage + "." + jsLoc; + var loaded = false; + if(!dojo.hostenv.findModule(translationPackage)){ + // Mark loaded whether it's found or not, so that further load attempts will not be made + dojo.hostenv.startPackage(translationPackage); + 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 parent bundle, then mix-in result from loadPath + var clazz = function(){}; + clazz.prototype = parent; + bundle[jsLoc] = new clazz(); + for(var j in hash){ bundle[jsLoc][j] = hash[j]; } + }); + }else{ + loaded = true; + } + if(loaded && bundle[jsLoc]){ + parent = bundle[jsLoc]; + }else{ + bundle[jsLoc] = parent; + } + + if(availableFlatLocales){ + //Stop the locale path searching if we know the availableFlatLocales, since + //the first call to this function will load the only bundle that is needed. + return true; + } + }); + } + + //Save the best locale bundle as the target locale bundle when we know the + //the available bundles. + if(availableFlatLocales && targetLocale != bestLocale){ + bundle[targetLocale.replace('-', '_')] = bundle[bestLocale.replace('-', '_')]; + } +}; + +(function(){ + // If other locales are used, dojo.requireLocalization should load them as well, by default. + // Override dojo.requireLocalization to do load the default bundle, then iterate through the + // extraLocale list and load those translations as well, unless a particular locale was requested. + + var extra = djConfig.extraLocale; + if(extra){ + if(!extra instanceof Array){ + extra = [extra]; + } + + var req = dojo.requireLocalization; + dojo.requireLocalization = function(m, b, locale, availableFlatLocales){ + req(m,b,locale, availableFlatLocales); + if(locale){return;} + for(var i=0; i 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; + + var cm = document["compatMode"]; + drh.quirks = (cm == "BackCompat")||(cm == "QuirksMode")||drh.ie55||drh.ie50; + + // 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; + } + }else{ + } + })(); + + 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(){ + // summary: does the work of portably generating a new XMLHTTPRequest object. + 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; // XMLHTTPRequest instance + } + + dojo.hostenv._blockAsync = false; + dojo.hostenv.getText = function(uri, async_cb, fail_ok){ + // summary: Read the contents of the specified uri and return those contents. + // uri: + // A relative or absolute uri. If absolute, it still must be in + // the same "domain" as we are. + // 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. + // fail_ok: + // Default false. If fail_ok and !async_cb and loading fails, + // return null instead of throwing. + + // 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; // String + } + + dojo.hostenv.defaultDebugContainerId = 'dojoDebug'; + dojo.hostenv._println_buffer = []; + dojo.hostenv._println_safe = false; + dojo.hostenv.println = function(/*String*/line){ + // summary: + // prints the provided line to whatever logging container is + // available. If the page isn't loaded yet, the line may be added + // to a buffer for printing later. + 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("
" + line + "
"); + }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(/*DomNode*/node, /*String*/evtName, /*Function*/fp){ + // summary: + // non-destructively adds the specified function to the node's + // evtName handler. + // node: the DomNode to add the handler to + // evtName: should be in the form "click" for "onclick" handlers + var oldHandler = node["on"+evtName] || function(){}; + node["on"+evtName] = function(){ + fp.apply(node, arguments); + oldHandler.apply(node, arguments); + } + return true; + } + + // BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/) + function dj_load_init(e){ + // allow multiple calls, only first one will take effect + // A bug in khtml calls events callbacks for document for event which isnt supported + // for example a created contextmenu event calls DOMContentLoaded, workaround + var type = (e && e.type) ? e.type.toLowerCase() : "load"; + if(arguments.callee.initialized || (type!="domcontentloaded" && type!="load")){ return; } + arguments.callee.initialized = true; + if(typeof(_timer) != 'undefined'){ + clearInterval(_timer); + delete _timer; + } + + var initFunc = function(){ + //perform initialization + if(dojo.render.html.ie){ + dojo.hostenv.makeWidgets(); + } + }; + + if(dojo.hostenv.inFlightCount == 0){ + initFunc(); + dojo.hostenv.modulesLoaded(); + }else{ + //This else case should be xdomain loading. + //Make sure this is the first thing in the load listener array. + //Part of the dojo.addOnLoad guarantee is that when the listeners are notified, + //It means the DOM (or page) has loaded and that widgets have been parsed. + dojo.hostenv.modulesLoadedListeners.unshift(initFunc); + } + } + + // START DOMContentLoaded + // Mozilla and Opera 9 expose the event we could use + if(document.addEventListener){ + if(dojo.render.html.opera || (dojo.render.html.moz && !djConfig.delayMozLoadingFix)){ + document.addEventListener("DOMContentLoaded", dj_load_init, null); + } + + // mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already. + // also used for Mozilla because of trac #1640 + window.addEventListener("load", dj_load_init, null); + } + + // for Internet Explorer. readyState will not be achieved on init call, but dojo doesn't need it + // however, we'll include it because we don't know if there are other functions added that might. + // Note that this has changed because the build process strips all comments--including conditional + // ones. + if(dojo.render.html.ie && dojo.render.os.win){ + document.attachEvent("onreadystatechange", function(e){ + if(document.readyState == "complete"){ + dj_load_init(); + } + }); + } + + if (/(WebKit|khtml)/i.test(navigator.userAgent)) { // sniff + var _timer = setInterval(function() { + if (/loaded|complete/.test(document.readyState)) { + dj_load_init(); // call the onload handler + } + }, 10); + } + // END DOMContentLoaded + + // IE WebControl hosted in an application can fire "beforeunload" and "unload" + // events when control visibility changes, causing Dojo to unload too soon. The + // following code fixes the problem + // Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155 + if(dojo.render.html.ie){ + dj_addNodeEvtHdlr(window, "beforeunload", function(){ + dojo.hostenv._unloading = true; + window.setTimeout(function() { + dojo.hostenv._unloading = false; + }, 0); + }); + } + + dj_addNodeEvtHdlr(window, "unload", function(){ + dojo.hostenv.unloaded(); + if((!dojo.render.html.ie)||(dojo.render.html.ie && dojo.hostenv._unloading)){ + 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 bug) + var parser = new dojo.xml.Parse(); + if(sids.length > 0){ + for(var x=0; x"); + } catch (e) { + var script = document.createElement("script"); + script.src = spath; + document.getElementsByTagName("head")[0].appendChild(script); + } + } + } +})(); + +dojo.provide("dojo.string.common"); + +dojo.string.trim = function(/* string */str, /* integer? */wh){ + // summary + // Trim whitespace from str. If wh > 0, trim from start, if wh < 0, trim from end, else both + 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, ""); // string +} + +dojo.string.trimStart = function(/* string */str) { + // summary + // Trim whitespace at the beginning of 'str' + return dojo.string.trim(str, 1); // string +} + +dojo.string.trimEnd = function(/* string */str) { + // summary + // Trim whitespace at the end of 'str' + return dojo.string.trim(str, -1); +} + +dojo.string.repeat = function(/* string */str, /* integer */count, /* string? */separator) { + // summary + // Return 'str' repeated 'count' times, optionally placing 'separator' between each rep + var out = ""; + for(var i = 0; i < count; i++) { + out += str; + if(separator && i < count - 1) { + out += separator; + } + } + return out; // string +} + +dojo.string.pad = function(/* string */str, /* integer */len/*=2*/, /* string */ c/*='0'*/, /* integer */dir/*=1*/) { + // summary + // 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 + 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; // string +} + +dojo.string.padLeft = function(/* string */str, /* integer */len, /* string */c) { + // summary + // same as dojo.string.pad(str, len, c, 1) + return dojo.string.pad(str, len, c, 1); // string +} + +dojo.string.padRight = function(/* string */str, /* integer */len, /* string */c) { + // summary + // same as dojo.string.pad(str, len, c, -1) + return dojo.string.pad(str, len, c, -1); // string +} + +dojo.provide("dojo.string"); + +dojo.provide("dojo.lang.common"); + +dojo.lang.inherits = function(/*Function*/subclass, /*Function*/superclass){ + // summary: Set up inheritance between two classes. + if(!dojo.lang.isFunction(superclass)){ + 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; + // DEPRECATED: super is a reserved word, use 'superclass' + subclass['super'] = superclass.prototype; +} + +dojo.lang._mixin = function(/*Object*/ obj, /*Object*/ props){ + // summary: + // Adds all properties and methods of props to obj. This addition is + // "prototype extension safe", so that instances of objects will not + // pass along prototype defaults. + var tobj = {}; + for(var x in props){ + // the "tobj" condition avoid copying properties in "props" + // inherited from Object.prototype. For example, if obj has a custom + // toString() method, don't overwrite it with the toString() method + // that props inherited from Object.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 + && (typeof(props["toString"]) == "function") + && (props["toString"] != obj["toString"]) + && (props["toString"] != tobj["toString"])) + { + obj.toString = props.toString; + } + return obj; // Object +} + +dojo.lang.mixin = function(/*Object*/obj, /*Object...*/props){ + // summary: Adds all properties and methods of props to obj. + for(var i=1, l=arguments.length; i -1; // 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(/*anything*/ 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)); // Boolean +} + +dojo.lang.isArray = function(/*anything*/ it){ + // summary: Return true if it is an Array. + return (it && it instanceof Array || typeof it == "array"); // Boolean +} + +dojo.lang.isArrayLike = function(/*anything*/ 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; // Boolean +} + +dojo.lang.isFunction = function(/*anything*/ it){ + // summary: Return true if it is a Function. + return (it instanceof Function || typeof it == "function"); // Boolean +}; + +(function(){ + // webkit treats NodeList as a function, which is bad + if((dojo.render.html.capable)&&(dojo.render.html["safari"])){ + dojo.lang.isFunction = function(/*anything*/ it){ + if((typeof(it) == "function") && (it == "[object NodeList]")) { return false; } + return (it instanceof Function || typeof it == "function"); // Boolean + } + } +})(); + +dojo.lang.isString = function(/*anything*/ it){ + // summary: Return true if it is a String. + return (typeof it == "string" || it instanceof String); +} + +dojo.lang.isAlien = function(/*anything*/ it){ + // summary: Return true if it is not a built-in function. False if not. + if(!it){ return false; } + return !dojo.lang.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean +} + +dojo.lang.isBoolean = function(/*anything*/ it){ + // summary: Return true if it is a Boolean. + return (it instanceof Boolean || typeof it == "boolean"); // 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(/*anything*/ it){ + // summary: Return true if it is a number. + // description: + // 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"); // Boolean +} + +/* + * FIXME: Should isUndefined go away since it is error prone? + */ +dojo.lang.isUndefined = function(/*anything*/ it){ + // summary: Return true if it is not defined. + // description: + // 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 ((typeof(it) == "undefined")&&(it == undefined)); // Boolean +} + +// end Crockford functions + +dojo.provide("dojo.lang.extras"); + + +dojo.lang.setTimeout = function(/*Function*/func, /*int*/delay /*, ...*/){ + // summary: + // Sets a timeout in milliseconds to execute a function in a given + // context with optional arguments. + // usage: + // dojo.lang.setTimeout(Object context, function func, number delay[, arg1[, ...]]); + // dojo.lang.setTimeout(function func, number delay[, arg1[, ...]]); + + 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); // int +} + +dojo.lang.clearTimeout = function(/*int*/timer){ + // summary: clears timer by number from the execution queue + + // FIXME: + // why do we have this function? It's not portable outside of browser + // environments and it's a stupid wrapper on something that browsers + // provide anyway. + dojo.global().clearTimeout(timer); +} + +dojo.lang.getNameInObj = function(/*Object*/ns, /*unknown*/item){ + // summary: + // looks for a value in the object ns with a value matching item and + // returns the property name + // ns: if null, dj_global is used + // item: value to return a name for + if(!ns){ ns = dj_global; } + + for(var x in ns){ + if(ns[x] === item){ + return new String(x); // String + } + } + return null; // null +} + +dojo.lang.shallowCopy = function(/*Object*/obj, /*Boolean?*/deep){ + // summary: + // copies object obj one level deep, or full depth if deep is true + var i, ret; + + if(obj === null){ /*obj: null*/ return null; } // null + + if(dojo.lang.isObject(obj)){ + // obj: Object + 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)){ + // obj: Array + ret = []; + for(i=0; i 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 + * 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(/*String*/ url, /*String*/ mimetype, /*String*/ transport, /*String or Boolean*/ changeUrl){ +// summary: +// Constructs a Request object that is used by dojo.io.bind(). +// description: +// dojo.io.bind() will create one of these for you if +// you call dojo.io.bind() with an plain object containing the bind parameters. +// This method can either take the arguments specified, or an Object containing all of the parameters that you +// want to use to create the dojo.io.Request (similar to how dojo.io.bind() is called. +// The named parameters to this constructor represent the minimum set of parameters need + 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(/*String*/type, /*Object*/data, /*Object*/transportImplementation, /*Object*/kwArgs){ + // summary: + // Called on successful completion of a bind. + // type: String + // A string with value "load" + // data: Object + // The object representing the result of the bind. The actual structure + // of the data object will depend on the mimetype that was given to bind + // in the bind arguments. + // transportImplementation: Object + // The object that implements a particular transport. Structure is depedent + // on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the + // XMLHttpRequest object from the browser. + // kwArgs: Object + // Object that contains the request parameters that were given to the + // bind call. Useful for storing and retrieving state from when bind + // was called. + }, + error: function(/*String*/type, /*Object*/error, /*Object*/transportImplementation, /*Object*/kwArgs){ + // summary: + // Called when there is an error with a bind. + // type: String + // A string with value "error" + // error: Object + // The error object. Should be a dojo.io.Error object, but not guaranteed. + // transportImplementation: Object + // The object that implements a particular transport. Structure is depedent + // on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the + // XMLHttpRequest object from the browser. + // kwArgs: Object + // Object that contains the request parameters that were given to the + // bind call. Useful for storing and retrieving state from when bind + // was called. + }, + timeout: function(/*String*/type, /*Object*/empty, /*Object*/transportImplementation, /*Object*/kwArgs){ + // summary: + // Called when there is an error with a bind. Only implemented in certain transports at this time. + // type: String + // A string with value "timeout" + // empty: Object + // Should be null. Just a spacer argument so that load, error, timeout and handle have the + // same signatures. + // transportImplementation: Object + // The object that implements a particular transport. Structure is depedent + // on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the + // XMLHttpRequest object from the browser. May be null for the timeout case for + // some transports. + // kwArgs: Object + // Object that contains the request parameters that were given to the + // bind call. Useful for storing and retrieving state from when bind + // was called. + }, + handle: function(/*String*/type, /*Object*/data, /*Object*/transportImplementation, /*Object*/kwArgs){ + // summary: + // The handle method can be defined instead of defining separate load, error and timeout + // callbacks. + // type: String + // A string with the type of callback: "load", "error", or "timeout". + // data: Object + // See the above callbacks for what this parameter could be. + // transportImplementation: Object + // The object that implements a particular transport. Structure is depedent + // on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the + // XMLHttpRequest object from the browser. + // kwArgs: Object + // Object that contains the request parameters that were given to the + // bind call. Useful for storing and retrieving state from when bind + // was called. + }, + + //FIXME: change IframeIO.js to use timeouts? + // 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(/*Object*/ kwArgs){ + // summary: + // Creates a dojo.io.Request from a simple object (kwArgs object). + + // 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 0){ + dojo.io.bind(dojo.io._bindQueue.shift()); + }else{ + dojo.io._queueBindInFlight = false; + } + } +} +dojo.io._bindQueue = []; +dojo.io._queueBindInFlight = false; + +dojo.io.argsFromMap = function(/*Object*/map, /*String?*/encoding, /*String?*/last){ + // summary: + // Converts name/values pairs in the map object to an URL-encoded string + // with format of name1=value1&name2=value2... + // map: Object + // Object that has the contains the names and values. + // encoding: String? + // String to specify how to encode the name and value. If the encoding string + // contains "utf" (case-insensitive), then encodeURIComponent is used. Otherwise + // dojo.string.encodeAscii is used. + // last: String? + // The last parameter in the list. Helps with final string formatting? + 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("&"); //String +} + +dojo.io.setIFrameSrc = function(/*DOMNode*/ iframe, /*String*/ src, /*Boolean*/ replace){ + //summary: + // Sets the URL that is loaded in an IFrame. The replace parameter indicates whether + // location.replace() should be used when changing the location of the iframe. + 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; x1; }); + // // returns false + // dojo.lang.every([1, 2, 3, 4], function(item){ return item>0; }); + // // returns true + return this._everyOrSome(true, arr, callback, thisObject); // Boolean + }, + + some: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){ + // summary: + // determines whether or not any item in the array satisfies the + // condition implemented by callback. thisObject may be used to + // scope the call to callback. The function signature is derived + // from the JavaScript 1.6 Array.some() function. More + // information on this can be found here: + // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some + // examples: + // dojo.lang.some([1, 2, 3, 4], function(item){ return item>1; }); + // // returns true + // dojo.lang.some([1, 2, 3, 4], function(item){ return item<1; }); + // // returns false + return this._everyOrSome(false, arr, callback, thisObject); // Boolean + }, + + filter: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){ + // summary: + // returns a new Array with those items from arr that match the + // condition implemented by callback.thisObject may be used to + // scope the call to callback. The function signature is derived + // from the JavaScript 1.6 Array.filter() function, although + // special accomidation is made in our implementation for strings. + // More information on the JS 1.6 API can be found here: + // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter + // examples: + // dojo.lang.some([1, 2, 3, 4], function(item){ return item>1; }); + // // returns [2, 3, 4] + var isString = dojo.lang.isString(arr); + if(isString){ /*arr: String*/arr = arr.split(""); } + var outArr; + if(Array.filter){ + outArr = Array.filter(arr, callback, thisObject); + }else{ + if(!thisObject){ + if(arguments.length >= 3){ dojo.raise("thisObject doesn't exist!"); } + thisObject = dj_global; + } + + 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(""); // String + } else { + return outArr; // Array + } + }, + + unnest: function(/* ... */){ + // summary: + // Creates a 1-D array out of all the arguments passed, + // unravelling any array-like objects in the process + // usage: + // unnest(1, 2, 3) ==> [1, 2, 3] + // unnest(1, [2, [3], [[[4]]]]) ==> [1, 2, 3, 4] + + 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; // Array + }, + + toArray: function(/*Object*/arrayLike, /*Number*/startOffset){ + // summary: + // Converts an array-like object (i.e. arguments, DOMCollection) + // to an array. Returns a new Array object. + var array = []; + for(var i = startOffset||0; i < arrayLike.length; i++){ + array.push(arrayLike[i]); + } + return array; // Array + } +}); + +dojo.provide("dojo.lang.func"); + +dojo.lang.hitch = function(/*Object*/thisObject, /*Function|String*/method){ + // summary: + // Returns a function that will only ever execute in the a given scope + // (thisObject). This allows for easy use of object member functions + // in callbacks and other places in which the "this" keyword may + // otherwise not reference the expected scope. Note that the order of + // arguments may be reversed in a future version. + // thisObject: the scope to run the method in + // method: + // a function to be "bound" to thisObject or the name of the method in + // thisObject to be used as the basis for the binding + // usage: + // dojo.lang.hitch(foo, "bar")(); // runs foo.bar() in the scope of foo + // dojo.lang.hitch(foo, myFunction); // returns a function that runs myFunction in the scope of foo + + // FIXME: + // should this be extended to "fixate" arguments in a manner similar + // to dojo.lang.curry, but without the default execution of curry()? + var fcn = (dojo.lang.isString(method) ? thisObject[method] : method) || function(){}; + return function(){ + return fcn.apply(thisObject, arguments); // Function + }; +} + +dojo.lang.anonCtr = 0; +dojo.lang.anon = {}; + +dojo.lang.nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj, /*Boolean*/searchForNames){ + // summary: + // Creates a reference to anonFuncPtr in thisObj with a completely + // unique name. The new name is returned as a String. If + // searchForNames is true, an effort will be made to locate an + // existing reference to anonFuncPtr in thisObj, and if one is found, + // the existing name will be returned instead. The default is for + // searchForNames to be false. + var nso = (thisObj|| 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; // String +} + +dojo.lang.forward = function(funcName){ + // summary: + // Returns a function that forwards a method call to + // this.funcName(...). Unlike dojo.lang.hitch(), the "this" scope is + // not fixed on a single object. Ported from MochiKit. + return function(){ + return this[funcName].apply(this, arguments); + }; // Function +} + +dojo.lang.curry = function(thisObj, func /* args ... */){ + // summary: + // similar to the curry() method found in many functional programming + // environments, this function returns an "argument accumulator" + // function, bound to a particular scope, and "primed" with a variable + // number of arguments. The curry method is unique in that it returns + // a function that may return other "partial" function which can be + // called repeatedly. New functions are returned until the arity of + // the original function is reached, at which point the underlying + // function (func) is called in the scope thisObj with all of the + // accumulated arguments (plus any extras) in positional order. + // examples: + // assuming a function defined like this: + // var foo = { + // bar: function(arg1, arg2, arg3){ + // dojo.debug.apply(dojo, arguments); + // } + // }; + // + // dojo.lang.curry() can be used most simply in this way: + // + // tmp = dojo.lang.curry(foo, foo.bar, "arg one", "thinger"); + // tmp("blah", "this is superfluous"); + // // debugs: "arg one thinger blah this is superfluous" + // tmp("blah"); + // // debugs: "arg one thinger blah" + // tmp(); + // // returns a function exactly like tmp that expects one argument + // + // other intermittent functions could be created until the 3 + // positional arguments are filled: + // + // tmp = dojo.lang.curry(foo, foo.bar, "arg one"); + // tmp2 = tmp("arg two"); + // tmp2("blah blah"); + // // debugs: "arg one arg two blah blah" + // tmp2("oy"); + // // debugs: "arg one arg two oy" + // + // curry() can also be used to call the function if enough arguments + // are passed in the initial invocation: + // + // dojo.lang.curry(foo, foo.bar, "one", "two", "three", "four"); + // // debugs: "one two three four" + // dojo.lang.curry(foo, foo.bar, "one", "two", "three"); + // // debugs: "one two three" + + + // FIXME: the order of func and thisObj should be changed!!! + var outerArgs = []; + thisObj = thisObj||dj_global; + if(dojo.lang.isString(func)){ + func = thisObj[func]; + } + for(var x=2; x"' +// Optionally skips escapes for single quotes + + str = str.replace(/&/gm, "&").replace(//gm, ">").replace(/"/gm, """); + if(!noSingleQuotes){ str = str.replace(/'/gm, "'"); } + return str; // string +} + +dojo.string.escapeSql = function(/*string*/str){ +//summary: +// Adds escape sequences for single quotes in SQL expressions + + return str.replace(/'/gm, "''"); //string +} + +dojo.string.escapeRegExp = function(/*string*/str){ +//summary: +// Adds escape sequences for special characters in regular expressions + + return str.replace(/\\/gm, "\\\\").replace(/([\f\b\n\t\r[\^$|?*+(){}])/gm, "\\$1"); // string +} + +//FIXME: should this one also escape backslash? +dojo.string.escapeJavaScript = function(/*string*/str){ +//summary: +// Adds escape sequences for single and double quotes as well +// as non-visible characters in JavaScript string literal expressions + + return str.replace(/(["'\f\b\n\t\r])/gm, "\\$1"); // string +} + +//FIXME: looks a lot like escapeJavaScript, just adds quotes? deprecate one? +dojo.string.escapeString = function(/*string*/str){ +//summary: +// Adds escape sequences for non-visual characters, double quote and backslash +// and surrounds with double quotes to form a valid string literal. + return ('"' + str.replace(/(["\\])/g, '\\$1') + '"' + ).replace(/[\f]/g, "\\f" + ).replace(/[\b]/g, "\\b" + ).replace(/[\n]/g, "\\n" + ).replace(/[\t]/g, "\\t" + ).replace(/[\r]/g, "\\r"); // string +} + +// TODO: make an HTML version +dojo.string.summary = function(/*string*/str, /*number*/len){ +// summary: +// Truncates 'str' after 'len' characters and appends periods as necessary so that it ends with "..." + + if(!len || str.length <= len){ + return str; // string + } + + return str.substring(0, len).replace(/\.+$/, "") + "..."; // string +} + +dojo.string.endsWith = function(/*string*/str, /*string*/end, /*boolean*/ignoreCase){ +// summary: +// Returns true if 'str' ends with 'end' + + if(ignoreCase){ + str = str.toLowerCase(); + end = end.toLowerCase(); + } + if((str.length - end.length) < 0){ + return false; // boolean + } + return str.lastIndexOf(end) == str.length - end.length; // boolean +} + +dojo.string.endsWithAny = function(/*string*/str /* , ... */){ +// summary: +// Returns true if 'str' ends with any of the arguments[2 -> n] + + for(var i = 1; i < arguments.length; i++) { + if(dojo.string.endsWith(str, arguments[i])) { + return true; // boolean + } + } + return false; // boolean +} + +dojo.string.startsWith = function(/*string*/str, /*string*/start, /*boolean*/ignoreCase){ +// summary: +// Returns true if 'str' starts with 'start' + + if(ignoreCase) { + str = str.toLowerCase(); + start = start.toLowerCase(); + } + return str.indexOf(start) == 0; // boolean +} + +dojo.string.startsWithAny = function(/*string*/str /* , ... */){ +// summary: +// Returns true if 'str' starts with any of the arguments[2 -> n] + + for(var i = 1; i < arguments.length; i++) { + if(dojo.string.startsWith(str, arguments[i])) { + return true; // boolean + } + } + return false; // boolean +} + +dojo.string.has = function(/*string*/str /* , ... */) { +// summary: +// Returns true if 'str' contains any of the arguments 2 -> n + + for(var i = 1; i < arguments.length; i++) { + if(str.indexOf(arguments[i]) > -1){ + return true; // boolean + } + } + return false; // boolean +} + +dojo.string.normalizeNewlines = function(/*string*/text, /*string? (\n or \r)*/newlineChar){ +// summary: +// Changes occurences of CR and LF in text to CRLF, or if newlineChar is provided as '\n' or '\r', +// substitutes newlineChar for occurrences of CR/LF and CRLF + + 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").replace(/\r([^\n])/g, "\r\n$1"); + } + return text; // string +} + +dojo.string.splitEscaped = function(/*string*/str, /*string of length=1*/charac){ +// summary: +// Splits 'str' into an array separated by 'charac', but skips characters escaped with a backslash + + 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; // array +} + +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 = { + // summary + // aliases for various common XML namespaces + 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(/* object */wh){ + // summary: + // checks to see if wh is actually a node. + if(typeof Element == "function") { + try { + return wh instanceof Element; // boolean + } catch(e) {} + } else { + // best-guess + return wh && !isNaN(wh.nodeType); // boolean + } +} + +dojo.dom.getUniqueId = function(){ + // summary: + // returns a unique string for use with any DOM element + var _document = dojo.doc(); + do { + var id = "dj_unique_" + (++arguments.callee._idIncrement); + }while(_document.getElementById(id)); + return id; // string +} +dojo.dom.getUniqueId._idIncrement = 0; + +dojo.dom.firstElement = dojo.dom.getFirstChildElement = function(/* Element */parentNode, /* string? */tagName){ + // summary: + // returns the first child element matching 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; // Element +} + +dojo.dom.lastElement = dojo.dom.getLastChildElement = function(/* Element */parentNode, /* string? */tagName){ + // summary: + // returns the last child element matching 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; // Element +} + +dojo.dom.nextElement = dojo.dom.getNextSiblingElement = function(/* Node */node, /* string? */tagName){ + // summary: + // returns the next sibling element matching 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; // Element +} + +dojo.dom.prevElement = dojo.dom.getPreviousSiblingElement = function(/* Node */node, /* string? */tagName){ + // summary: + // returns the previous sibling element matching 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; // Element +} + +// 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(/*Element*/srcNode, /*Element*/destNode, /*boolean?*/trim){ + // summary: + // Moves children from srcNode to destNode and returns the count of + // children moved; will trim off text nodes if trim == true + 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; // number +} + +dojo.dom.copyChildren = function(/*Element*/srcNode, /*Element*/destNode, /*boolean?*/trim){ + // summary: + // Copies children from srcNde to destNode and returns the count of + // children copied; will trim off text nodes if trim == true + var clonedNode = srcNode.cloneNode(true); + return this.moveChildren(clonedNode, destNode, trim); // number +} + +dojo.dom.replaceChildren = function(/*Element*/node, /*Node*/newChild){ + // summary: + // Removes all children of node and appends newChild. All the existing + // children will be destroyed. + // FIXME: what if newChild is an array-like object? + var nodes = []; + if(dojo.render.html.ie){ + for(var i=0;i 0){ + return ancestors[0]; // Node + } + + node = node.parentNode; + } + if(returnFirstHit){ return null; } + return ancestors; // array +} + +dojo.dom.getAncestorsByTag = function(/*Node*/node, /*String*/tag, /*boolean?*/returnFirstHit){ + // summary: + // returns all ancestors matching tag (as tagName), will only return + // first one if returnFirstHit + tag = tag.toLowerCase(); + return dojo.dom.getAncestors(node, function(el){ + return ((el.tagName)&&(el.tagName.toLowerCase() == tag)); + }, returnFirstHit); // Node || array +} + +dojo.dom.getFirstAncestorByTag = function(/*Node*/node, /*string*/tag){ + // summary: + // Returns first ancestor of node with tag tagName + return dojo.dom.getAncestorsByTag(node, tag, true); // Node +} + +dojo.dom.isDescendantOf = function(/* Node */node, /* Node */ancestor, /* boolean? */guaranteeDescendant){ + // summary + // Returns boolean if node is a descendant of ancestor + // guaranteeDescendant allows us to be a "true" isDescendantOf function + if(guaranteeDescendant && node) { node = node.parentNode; } + while(node) { + if(node == ancestor){ + return true; // boolean + } + node = node.parentNode; + } + return false; // boolean +} + +dojo.dom.innerXML = function(/*Node*/node){ + // summary: + // Implementation of MS's innerXML function. + if(node.innerXML){ + return node.innerXML; // string + }else if (node.xml){ + return node.xml; // string + }else if(typeof XMLSerializer != "undefined"){ + return (new XMLSerializer()).serializeToString(node); // string + } +} + +dojo.dom.createDocument = function(){ + // summary: + // cross-browser implementation of creating an XML document object. + var doc = null; + var _document = dojo.doc(); + + if(!dj_undef("ActiveXObject")){ + var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ]; + for(var i = 0; i1) { + var _document = dojo.doc(); + dojo.dom.replaceChildren(node, _document.createTextNode(text)); + return text; // string + } else { + if(node.textContent != undefined){ //FF 1.5 + return node.textContent; // string + } + 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; // string + } +} + +dojo.dom.hasParent = function(/*Node*/node){ + // summary: + // returns whether or not node is a child of another node. + return Boolean(node && node.parentNode && dojo.dom.isNode(node.parentNode)); // boolean +} + +/** + * Examples: + * + * myFooNode = + * 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 */node /* ... */){ + // summary: + // determines if node has any of the provided tag names and returns + // the tag name that matches, empty string otherwise. + if(node && node.tagName) { + for(var i=1; i"); + } +}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."); +} + +dojo.undo.browser = { + initialHref: (!dj_undef("window")) ? window.location.href : "", + initialHash: (!dj_undef("window")) ? window.location.hash : "", + + moveForward: false, + historyStack: [], + forwardStack: [], + historyIframe: null, + bookmarkAnchor: null, + locationTimer: null, + + /** + * + */ + setInitialState: function(/*Object*/args){ + //summary: Sets the state object and back callback for the very first page that is loaded. + //description: It is recommended that you call this method as part of an event listener that is registered via + //dojo.addOnLoad(). + //args: Object + // See the addToHistory() function for the list of valid args properties. + this.initialState = this._createState(this.initialHref, args, 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: function(args){ + //summary: adds a state object (args) to the history list. You must set + //djConfig.preventBackButtonFix = false to use dojo.undo.browser. + + //args: Object + // args can have the following properties: + // 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 + // }); + // + // BROWSER 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. + + //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 hash = null; + var url = 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"]){ + hash = "#"+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime()); + + //If the current hash matches the new one, just replace the history object with + //this new one. It doesn't make sense to track different state objects for the same + //logical URL. This matches the browser behavior of only putting in one history + //item no matter how many times you click on the same #hash link, at least in Firefox + //and Safari, and there is no reliable way in those browsers to know if a #hash link + //has been clicked on multiple times. So making this the standard behavior in all browsers + //so that dojo.undo.browser's behavior is the same in all browsers. + if(this.historyStack.length == 0 && this.initialState.urlHash == hash){ + this.initialState = this._createState(url, args, hash); + return; + }else if(this.historyStack.length > 0 && this.historyStack[this.historyStack.length - 1].urlHash == hash){ + this.historyStack[this.historyStack.length - 1] = this._createState(url, args, hash); + return; + } + + this.changingUrl = true; + setTimeout("window.location.href = '"+hash+"'; dojo.undo.browser.changingUrl = false;", 1); + this.bookmarkAnchor.href = hash; + + if(dojo.render.html.ie){ + url = this._loadIframeHistory(); + + 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; + } + + 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); + } + } + }else{ + url = this._loadIframeHistory(); + } + + this.historyStack.push(this._createState(url, args, hash)); + }, + + checkLocation: function(){ + //summary: private method. Do not call this directly. + 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){ + //summary: private method. Do not call this directly. + 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(){ + //summary: private method. Do not call this directly. + + //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(){ + //summary: private method. Do not call this directly. + + 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); + }, + + _createState: function(url, args, hash){ + //summary: private method. Do not call this directly. + + return {"url": url, "kwArgs": args, "urlHash": hash}; //Object + }, + + _getUrlQuery: function(url){ + //summary: private method. Do not call this directly. + var segments = url.split("?"); + if (segments.length < 2){ + return null; //null + } + else{ + return segments[1]; //String + } + }, + + _loadIframeHistory: function(){ + //summary: private method. Do not call this directly. + var url = dojo.hostenv.getBaseScriptUri()+"iframe_history.html?"+(new Date()).getTime(); + this.moveForward = true; + dojo.io.setIFrameSrc(this.historyIframe, url, false); + return url; //String + } +} + +dojo.provide("dojo.io.BrowserIO"); + + +if(!dj_undef("window")) { + +dojo.io.checkChildrenForFile = function(/*DOMNode*/node){ + //summary: Checks any child nodes of node for an input type="file" element. + 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; //boolean +} + +dojo.io.formHasFile = function(/*DOMNode*/formNode){ + //summary: Just calls dojo.io.checkChildrenForFile(). + return dojo.io.checkChildrenForFile(formNode); //boolean +} + +dojo.io.updateNode = function(/*DOMNode*/node, /*String or Object*/urlOrArgs){ + //summary: Updates a DOMnode with the result of a dojo.io.bind() call. + //node: DOMNode + //urlOrArgs: String or Object + // Either a String that has an URL, or an object containing dojo.io.bind() + // arguments. + 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){ + dojo.dom.destroyNode(node.firstChild); + } + node.innerHTML = d; + }; + dojo.io.bind(args); +} + +dojo.io.formFilter = function(/*DOMNode*/node) { + //summary: Returns true if the node is an input element that is enabled, has + //a name, and whose type is one of the following values: ["file", "submit", "image", "reset", "button"] + var type = (node.type||"").toLowerCase(); + return !node.disabled && node.name + && !dojo.lang.inArray(["file", "submit", "image", "reset", "button"], type); //boolean +} + +// TODO: Move to htmlUtils +dojo.io.encodeForm = function(/*DOMNode*/formNode, /*String?*/encoding, /*Function?*/formFilter){ + //summary: Converts the names and values of form elements into an URL-encoded + //string (name=value&name=value...). + //formNode: DOMNode + //encoding: String? + // The encoding to use for the values. Specify a string that starts with + // "utf" (for instance, "utf8"), to use encodeURIComponent() as the encoding + // function. Otherwise, dojo.string.encodeAscii will be used. + //formFilter: Function? + // A function used to filter out form elements. The element node will be passed + // to the formFilter function, and a boolean result is expected (true indicating + // indicating that the element should have its name/value included in the output). + // If no formFilter is specified, then dojo.io.formFilter() will be used. + 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("&") + "&"; //String +} + +dojo.io.FormBind = function(/*DOMNode or Object*/args) { + //summary: constructor for a dojo.io.FormBind object. See the Dojo Book for + //some information on usage: http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book23 + //args: DOMNode or Object + // args can either be the DOMNode for a form element, or an object containing + // dojo.io.bind() arguments, one of which should be formNode with the value of + // a form element DOMNode. + 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(/*DOMNode or Object*/args) { + //summary: Internal function called by the dojo.io.FormBind() constructor + //do not call this method directly. + 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(/*DOMNode*/form) { + //summary: Function used to verify that the form is OK to submit. + //Override this function if you want specific form validation done. + return true; //boolean + }, + + submit: function(/*Event*/e) { + //summary: internal function that is connected as a listener to the + //form's onsubmit event. + e.preventDefault(); + if(this.onSubmit(this.form)) { + dojo.io.bind(dojo.lang.mixin(this.bindArgs, { + formFilter: dojo.lang.hitch(this, "formFilter") + })); + } + }, + + click: function(/*Event*/e) { + //summary: internal method that is connected as a listener to the + //form's elements whose click event can submit a form. + var node = e.currentTarget; + if(node.disabled) { return; } + this.clickedButton = node; + }, + + formFilter: function(/*DOMNode*/node) { + //summary: internal function used to know which form element values to include + // in the dojo.io.bind() request. + 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; //boolean + }, + + // in case you don't have dojo.event.* pulled in + connect: function(/*Object*/srcObj, /*Function*/srcFcn, /*Function*/targetFcn) { + //summary: internal function used to connect event listeners to form elements + //that trigger events. Used in case dojo.event is not loaded. + 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(){ + //summary: The object that implements the dojo.io.bind transport for XMLHttpRequest. + 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" || kwArgs.mimetype == "application/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(){ + //summary: internal method used to trigger a timer to watch all inflight + //XMLHttpRequests. + 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(){ + //summary: internal method that checks each inflight XMLHttpRequest to see + //if it has completed or if the timeout situation applies. + 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--){ + try{ + 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); + } + } + }catch(e){ + try{ + var errObj = new dojo.io.Error("XMLHttpTransport.watchInFlight Error: " + e); + tif.req[(typeof tif.req.error == "function") ? "error" : "handle"]("error", errObj, tif.http, tif.req); + }catch(e2){ + dojo.debug("XMLHttpTransport error callback failed: " + e2); + } + } + } + } + + 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(/*dojo.io.Request*/kwArgs){ + //summary: Tells dojo.io.bind() if this is a good transport to + //use for the particular type of request. This type of transport cannot + //handle forms that have an input type="file" element. + + // 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", "application/json"], (kwArgs["mimetype"].toLowerCase()||"")) + && !( kwArgs["formNode"] && dojo.io.formHasFile(kwArgs["formNode"]) ); //boolean + } + + this.multipartBoundary = "45309FFF-BD65-4d50-99C9-36986896A96F"; // unique guid as a boundary value for multipart posts + + this.bind = function(/*dojo.io.Request*/kwArgs){ + //summary: function that sends the request to the server. + + //This function will attach an abort() function to the kwArgs dojo.io.Request object, + //so if you need to abort the request, you can call that method on the request object. + //The following are acceptable properties in kwArgs (in addition to the + //normal dojo.io.Request object properties). + //url: String: URL the server URL to use for the request. + //method: String: the HTTP method to use (GET, POST, etc...). + //mimetype: Specifies what format the result data should be given to the load/handle callback. Valid values are: + // text/javascript, text/json, application/json, application/xml, text/xml. Any other mimetype will give back a text + // string. + //transport: String: specify "XMLHTTPTransport" to force the use of this XMLHttpRequest transport. + //headers: Object: The object property names and values will be sent as HTTP request header + // names and values. + //sendTransport: boolean: If true, then dojo.transport=xmlhttp will be added to the request. + //encoding: String: The type of encoding to use when dealing with the content kwArgs property. + //content: Object: The content object is converted into a name=value&name=value string, by + // using dojo.io.argsFromMap(). The encoding kwArgs property is passed to dojo.io.argsFromMap() + // for use in encoding the names and values. The resulting string is added to the request. + //formNode: DOMNode: a form element node. This should not normally be used. Use new dojo.io.FormBind() instead. + // If formNode is used, then the names and values of the form elements will be converted + // to a name=value&name=value string and added to the request. The encoding kwArgs property is used + // to encode the names and values. + //postContent: String: Raw name=value&name=value string to be included as part of the request. + //back or backButton: Function: A function to be called if the back button is pressed. If this kwArgs property + // is used, then back button support via dojo.undo.browser will be used. See notes for dojo.undo.browser on usage. + // You need to set djConfig.preventBackButtonFix = false to enable back button support. + //changeUrl: boolean or String: Used as part of back button support. See notes for dojo.undo.browser on usage. + //user: String: The user name. Used in conjuction with password. Passed to XMLHttpRequest.open(). + //password: String: The user's password. Used in conjuction with user. Passed to XMLHttpRequest.open(). + //file: Object or Array of Objects: an object simulating a file to be uploaded. file objects should have the following properties: + // name or fileName: the name of the file + // contentType: the MIME content type for the file. + // content: the actual content of the file. + //multipart: boolean: indicates whether this should be a multipart mime request. If kwArgs.file exists, then this + // property is set to true automatically. + //sync: boolean: if true, then a synchronous XMLHttpRequest call is done, + // if false (the default), then an asynchronous call is used. + //preventCache: boolean: If true, then a cache busting parameter is added to the request URL. + // default value is false. + //useCache: boolean: If true, then XMLHttpTransport will keep an internal cache of the server + // response and use that response if a similar request is done again. + // A similar request is one that has the same URL, query string and HTTP method value. + // default is false. + 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! + if (!kwArgs.user) { + http.open("POST", url, async); + }else{ + http.open("POST", url, async, kwArgs.user, kwArgs.password); + } + 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(); + } + if (!kwArgs.user) { + http.open(kwArgs.method.toUpperCase(), tmpUrl, async); + }else{ + http.open(kwArgs.method.toUpperCase(), tmpUrl, async, kwArgs.user, kwArgs.password); + } + 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(/*String*/name, /*String*/value, + /*Number?*/days, /*String?*/path, + /*String?*/domain, /*boolean?*/secure){ + //summary: sets a cookie. + 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(/*String*/name){ + //summary: Gets a cookie with the given 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; //String +} + +dojo.io.cookie.get = dojo.io.cookie.getCookie; + +dojo.io.cookie.deleteCookie = function(/*String*/name){ + //summary: Deletes a cookie with the given name. + dojo.io.cookie.setCookie(name, "-", 0); +} + +dojo.io.cookie.setObjectCookie = function( /*String*/name, /*Object*/obj, + /*Number?*/days, /*String?*/path, + /*String?*/domain, /*boolean?*/secure, + /*boolean?*/clearCurrent){ + //summary: Takes an object, serializes it to a cookie value, and either + //sets a cookie with the serialized value. + //description: If clearCurrent is true, then any current cookie value + //for this object will be replaced with the the new serialized object value. + //If clearCurrent is false, then the existing cookie value will be modified + //with any changes from the new object value. + //Objects must be simple name/value pairs where the value is either a string + //or a number. Any other value will be ignored. + 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(obj[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(/*String*/name){ + //summary: Gets an object value for the given cookie name. The complement of + //dojo.io.cookie.setObjectCookie(). + 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(){ + //summary: Tests the browser to see if cookies are enabled. + 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; //boolean +} + +// 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.common"); + + +// 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(/*...*/){ + // summary: + // dojo.event.connect is the glue that holds most Dojo-based + // applications together. Most combinations of arguments are + // supported, with the connect() method attempting to disambiguate + // the implied types of positional parameters. The following will + // all work: + // dojo.event.connect("globalFunctionName1", "globalFunctionName2"); + // dojo.event.connect(functionReference1, functionReference2); + // dojo.event.connect("globalFunctionName1", functionReference2); + // dojo.event.connect(functionReference1, "globalFunctionName2"); + // dojo.event.connect(scope1, "functionName1", "globalFunctionName2"); + // dojo.event.connect("globalFunctionName1", scope2, "functionName2"); + // dojo.event.connect(scope1, "functionName1", scope2, "functionName2"); + // dojo.event.connect("after", scope1, "functionName1", scope2, "functionName2"); + // dojo.event.connect("before", scope1, "functionName1", scope2, "functionName2"); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // aroundFunctionReference); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName"); + // dojo.event.connect("before-around", scope1, "functionName1", + // scope2, "functionName2", + // aroundFunctionReference); + // dojo.event.connect("after-around", scope1, "functionName1", + // scope2, "functionName2", + // aroundFunctionReference); + // dojo.event.connect("after-around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName"); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName", true, 30); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName", null, null, 10); + // adviceType: + // Optional. String. One of "before", "after", "around", + // "before-around", or "after-around". FIXME + // srcObj: + // the scope in which to locate/execute the named srcFunc. Along + // with srcFunc, this creates a way to dereference the function to + // call. So if the function in question is "foo.bar", the + // srcObj/srcFunc pair would be foo and "bar", where "bar" is a + // string and foo is an object reference. + // srcFunc: + // the name of the function to connect to. When it is executed, + // the listener being registered with this call will be called. + // The adviceType defines the call order between the source and + // the target functions. + // adviceObj: + // the scope in which to locate/execute the named adviceFunc. + // adviceFunc: + // the name of the function being conected to srcObj.srcFunc + // aroundObj: + // the scope in which to locate/execute the named aroundFunc. + // aroundFunc: + // the name of, or a reference to, the function that will be used + // to mediate the advice call. Around advice requires a special + // unary function that will be passed a "MethodInvocation" object. + // These objects have several important properties, namely: + // - args + // a mutable array of arguments to be passed into the + // wrapped function + // - proceed + // a function that "continues" the invocation. The result + // of this function is the return of the wrapped function. + // You can then manipulate this return before passing it + // back out (or take further action based on it). + // once: + // boolean that determines whether or not this connect() will + // create a new connection if an identical connect() has already + // been made. Defaults to "false". + // delay: + // an optional delay (in ms), as an integer, for dispatch of a + // listener after the source has been fired. + // rate: + // an optional rate throttling parameter (integer, in ms). When + // specified, this particular connection will not fire more than + // once in the interval specified by the rate + // adviceMsg: + // boolean. Should the listener have all the parameters passed in + // as a single argument? + + /* + ao.adviceType = args[0]; + 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]; + */ + if(arguments.length == 1){ + var ao = arguments[0]; + }else{ + var ao = interpolateArgs(arguments, true); + } + if(dojo.lang.isString(ao.srcFunc) && (ao.srcFunc.toLowerCase() == "onkey") ){ + if(dojo.render.html.ie){ + ao.srcFunc = "onkeydown"; + this.connect(ao); + } + ao.srcFunc = "onkeypress"; + } + + + 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); + + // advanced users might want to fsck w/ the join point manually + return mjp; // a MethodJoinPoint object + } + + this.log = function(/*object or funcName*/ a1, /*funcName*/ a2){ + // summary: + // a function that will wrap and log all calls to the specified + // a1.a2() function. If only a1 is passed, it'll be used as a + // function or function name on the global context. Logging will + // be sent to dojo.debug + // a1: + // if a2 is passed, this should be an object. If not, it can be a + // function or function name. + // a2: + // a function name + 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= 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(/*Object*/obj, /*String*/funcName){ + this.object = obj||dj_global; + this.methodname = funcName; + this.methodfunc = this.object[funcName]; + this.squelch = false; + // this.before = []; + // this.after = []; + // this.around = []; +} + +dojo.event.MethodJoinPoint.getForMethod = function(/*Object*/obj, /*String*/funcName){ + // summary: + // "static" class function for returning a MethodJoinPoint from a + // scoped function. If one doesn't exist, one is created. + // obj: + // the scope to search for the function in + // funcName: + // the name of the function to return a MethodJoinPoint for + if(!obj){ obj = dj_global; } + if(!obj[funcName]){ + // supply a do-nothing method implementation + obj[funcName] = function(){}; + if(!obj[funcName]){ + // e.g. cannot add to inbuilt objects in IE6 + dojo.raise("Cannot set do-nothing method on that object "+funcName); + } + }else if((!dojo.lang.isFunction(obj[funcName]))&&(!dojo.lang.isAlien(obj[funcName]))){ + // FIXME: should we throw an exception here instead? + return null; + } + // we hide our joinpoint instance in obj[funcName + '$joinpoint'] + var jpname = funcName + "$joinpoint"; + var jpfuncname = funcName + "$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, funcName]); + } + } + var origArity = obj[funcName].length; + obj[jpfuncname] = obj[funcName]; + // joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, funcName); + joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, jpfuncname); + obj[funcName] = 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; x0)){ + // pass a cloned array, if this event disconnects this event forEach on this.before wont work + dojo.lang.forEach(this.before.concat(new Array()), unRollSquelch); + } + + var result; + try{ + if((this["around"])&&(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); + } + }catch(e){ + if(!this.squelch){ + dojo.debug(e,"when calling",this.methodname,"on",this.object,"with arguments",args); + dojo.raise(e); + } + } + + if((this["after"])&&(this.after.length>0)){ + // see comment on this.before above + dojo.lang.forEach(this.after.concat(new Array()), unRollSquelch); + } + + return (this.methodfunc) ? result : null; + }, + + getArr: function(/*String*/kind){ + // summary: return a list of listeners of the past "kind" + // kind: + // can be one of: "before", "after", "around", "before-around", or + // "after-around" + var type = "after"; + // FIXME: we should be able to do this through props or Array.in() + if((typeof kind == "string")&&(kind.indexOf("before")!=-1)){ + type = "before"; + }else if(kind=="around"){ + type = "around"; + } + if(!this[type]){ this[type] = []; } + return this[type]; // Array + }, + + kwAddAdvice: function(/*Object*/args){ + // summary: + // adds advice to the joinpoint with arguments in a map + // args: + // An object that can have the following properties: + // - adviceType + // - adviceObj + // - adviceFunc + // - aroundObj + // - aroundFunc + // - once + // - delay + // - rate + // - adviceMsg + 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, + adviceType, precedence, + once, delay, rate, asMessage){ + // summary: + // add advice to this joinpoint using positional parameters + // thisAdviceObj: + // the scope in which to locate/execute the named adviceFunc. + // thisAdviceFunc: + // the name of the function being conected + // thisAroundObj: + // the scope in which to locate/execute the named aroundFunc. + // thisAroundFunc: + // the name of the function that will be used to mediate the + // advice call. + // adviceType: + // Optional. String. One of "before", "after", "around", + // "before-around", or "after-around". FIXME + // once: + // boolean that determines whether or not this advice will create + // a new connection if an identical advice set has already been + // provided. Defaults to "false". + // delay: + // an optional delay (in ms), as an integer, for dispatch of a + // listener after the source has been fired. + // rate: + // an optional rate throttling parameter (integer, in ms). When + // specified, this particular connection will not fire more than + // once in the interval specified by the rate + // adviceMsg: + // boolean. Should the listener have all the parameters passed in + // as a single argument? + var arr = this.getArr(adviceType); + if(!arr){ + dojo.raise("bad this: " + this); + } + + var ao = [thisAdviceObj, thisAdvice, thisAroundObj, thisAround, delay, rate, asMessage]; + + if(once){ + if(this.hasAdvice(thisAdviceObj, thisAdvice, adviceType, arr) >= 0){ + return; + } + } + + if(precedence == "first"){ + arr.unshift(ao); + }else{ + arr.push(ao); + } + }, + + hasAdvice: function(thisAdviceObj, thisAdvice, adviceType, arr){ + // summary: + // returns the array index of the first existing connection + // betweened the passed advice and this joinpoint. Will be -1 if + // none exists. + // thisAdviceObj: + // the scope in which to locate/execute the named adviceFunc. + // thisAdviceFunc: + // the name of the function being conected + // adviceType: + // Optional. String. One of "before", "after", "around", + // "before-around", or "after-around". FIXME + // arr: + // Optional. The list of advices to search. Will be found via + // adviceType if not passed + if(!arr){ arr = this.getArr(adviceType); } + var ind = -1; + for(var x=0; x=0; i=i-1){ + var el = na[i]; + try{ + if(el && el["__clobberAttrs__"]){ + for(var j=0; j= 65 && unifiedCharCode <= 90 && evt.shiftKey == false){ + unifiedCharCode += 32; + } + if(unifiedCharCode >= 1 && unifiedCharCode <= 26 && evt.ctrlKey){ + unifiedCharCode += 96; // 001-032 = ctrl+[a-z] + } + evt.key = String.fromCharCode(unifiedCharCode); + } + } + } else if(evt["type"] == "keypress"){ + if(dojo.render.html.opera){ + if(evt.which == 0){ + evt.key = evt.keyCode; + }else if(evt.which > 0){ + switch(evt.which){ + case evt.KEY_SHIFT: + case evt.KEY_CTRL: + case evt.KEY_ALT: + case evt.KEY_CAPS_LOCK: + case evt.KEY_NUM_LOCK: + case evt.KEY_SCROLL_LOCK: + break; + case evt.KEY_PAUSE: + case evt.KEY_TAB: + case evt.KEY_BACKSPACE: + case evt.KEY_ENTER: + case evt.KEY_ESCAPE: + evt.key = evt.which; + break; + default: + var unifiedCharCode = evt.which; + if((evt.ctrlKey || evt.altKey || evt.metaKey) && (evt.which >= 65 && evt.which <= 90 && evt.shiftKey == false)){ + unifiedCharCode += 32; + } + evt.key = String.fromCharCode(unifiedCharCode); + } + } + }else if(dojo.render.html.ie){ // catch some IE keys that are hard to get in keyDown + // key combinations were handled in onKeyDown + if(!evt.ctrlKey && !evt.altKey && evt.keyCode >= evt.KEY_SPACE){ + evt.key = String.fromCharCode(evt.keyCode); + } + }else if(dojo.render.html.safari){ + switch(evt.keyCode){ + case 25: evt.key = evt.KEY_TAB; evt.shift = true;break; + case 63232: evt.key = evt.KEY_UP_ARROW; break; + case 63233: evt.key = evt.KEY_DOWN_ARROW; break; + case 63234: evt.key = evt.KEY_LEFT_ARROW; break; + case 63235: evt.key = evt.KEY_RIGHT_ARROW; break; + case 63236: evt.key = evt.KEY_F1; break; + case 63237: evt.key = evt.KEY_F2; break; + case 63238: evt.key = evt.KEY_F3; break; + case 63239: evt.key = evt.KEY_F4; break; + case 63240: evt.key = evt.KEY_F5; break; + case 63241: evt.key = evt.KEY_F6; break; + case 63242: evt.key = evt.KEY_F7; break; + case 63243: evt.key = evt.KEY_F8; break; + case 63244: evt.key = evt.KEY_F9; break; + case 63245: evt.key = evt.KEY_F10; break; + case 63246: evt.key = evt.KEY_F11; break; + case 63247: evt.key = evt.KEY_F12; break; + case 63250: evt.key = evt.KEY_PAUSE; break; + case 63272: evt.key = evt.KEY_DELETE; break; + case 63273: evt.key = evt.KEY_HOME; break; + case 63275: evt.key = evt.KEY_END; break; + case 63276: evt.key = evt.KEY_PAGE_UP; break; + case 63277: evt.key = evt.KEY_PAGE_DOWN; break; + case 63302: evt.key = evt.KEY_INSERT; break; + case 63248://prtscr + case 63249://scrolllock + case 63289://numlock + break; + default: + evt.key = evt.charCode >= evt.KEY_SPACE ? String.fromCharCode(evt.charCode) : evt.keyCode; + } + }else{ + evt.key = evt.charCode > 0 ? String.fromCharCode(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; // Event + } + + this.stopEvent = function(/*Event*/evt){ + // summary: + // prevents propigation and clobbers the default action of the + // passed event + // evt: Optional for IE. The native event object. + if(window.event){ + evt.cancelBubble = true; + evt.returnValue = false; + }else{ + evt.preventDefault(); + evt.stopPropagation(); + } + } +} + +dojo.provide("dojo.event.*"); + +dojo.provide("dojo.gfx.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.gfx.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.gfx.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.gfx.color.Color){ + // why does this create a new instance if we were passed one? + 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.gfx.color.Color.fromArray = function(arr) { + return new dojo.gfx.color.Color(arr[0], arr[1], arr[2], arr[3]); +} + +dojo.extend(dojo.gfx.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.gfx.color.rgb2hex(this.toRgb()); + }, + toCss: function() { + return "rgb(" + this.toRgb().join() + ")"; + }, + toString: function() { + return this.toHex(); // decent default? + }, + blend: function(color, weight){ + var rgb = null; + if(dojo.lang.isArray(color)){ + rgb = color; + }else if(color instanceof dojo.gfx.color.Color){ + rgb = color.toRgb(); + }else{ + rgb = new dojo.gfx.color.Color(color).toRgb(); + } + return dojo.gfx.color.blend(this.toRgb(), rgb, weight); + } +}); + +dojo.gfx.color.named = { + white: [255,255,255], + black: [0,0,0], + red: [255,0,0], + green: [0,255,0], + lime: [0,255,0], + blue: [0,0,255], + navy: [0,0,128], + gray: [128,128,128], + silver: [192,192,192] +}; + +dojo.gfx.color.blend = function(a, b, weight){ + // summary: + // blend colors a and b (both as RGB array or hex strings) with weight + // from -1 to +1, 0 being a 50/50 blend + if(typeof a == "string"){ + return dojo.gfx.color.blendHex(a, b, weight); + } + if(!weight){ + weight = 0; + } + weight = Math.min(Math.max(-1, weight), 1); + + // alex: this interface blows. + // map -1 to 1 to the range 0 to 1 + weight = ((weight + 1)/2); + + var c = []; + + // var stop = (1000*weight); + for(var x = 0; x < 3; x++){ + c[x] = parseInt( b[x] + ( (a[x] - b[x]) * weight) ); + } + return c; +} + +// very convenient blend that takes and returns hex values +// (will get called automatically by blend when blend gets strings) +dojo.gfx.color.blendHex = function(a, b, weight) { + return dojo.gfx.color.rgb2hex(dojo.gfx.color.blend(dojo.gfx.color.hex2rgb(a), dojo.gfx.color.hex2rgb(b), weight)); +} + +// get RGB array from css-style color declarations +dojo.gfx.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.gfx.color.hex2rgb(color); + if(colors) { + return colors; + } else { + // named color (how many do we support?) + return dojo.gfx.color.named[color] || [255, 255, 255]; + } + } +} + +dojo.gfx.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.gfx.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.lfx.Animation"); + + +/* + Animation package based on Dan Pupius' work: http://pupius.co.uk/js/Toolkit.Drawing.js +*/ +dojo.lfx.Line = function(/*int*/ start, /*int*/ end){ + // summary: dojo.lfx.Line is the object used to generate values + // from a start value to an end value + this.start = start; + this.end = end; + if(dojo.lang.isArray(start)){ + /* start: Array + end: Array + pId: a */ + 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; // Array + } + }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; // Decimal + } + } +} + +dojo.lfx.easeDefault = function(/*Decimal?*/ n){ + // summary: Returns the point for point n on a sin wave. + if(dojo.render.html.khtml){ + // the cool kids are obviously not using konqueror... + // found a very wierd bug in floats constants, 1.5 evals as 1 + // seems somebody mixed up ints and floats in 3.5.4 ?? + // FIXME: investigate more and post a KDE bug (Fredrik) + return (parseFloat("0.5")+((Math.sin( (n+parseFloat("1.5")) * Math.PI))/2)); + }else{ + return (0.5+((Math.sin( (n+1.5) * Math.PI))/2)); + } +} + +dojo.lfx.easeIn = function(/*Decimal?*/ 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(/*Decimal?*/ 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(/*Decimal?*/ 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(){ + // summary: dojo.lfx.IAnimation is an interface that implements + // commonly used functions of animation objects +} +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(/*Event*/ evt, /*Object*/ scope, /*Function*/ newFunc){ + // summary: Convenience function. Quickly connect to an event + // of this object and save the old functions connected to it. + // evt: The name of the event to connect to. + // scope: the scope in which to run newFunc. + // newFunc: the function to run when evt is fired. + if(!newFunc){ + /* scope: Function + newFunc: null + pId: f */ + 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; // dojo.lfx.IAnimation + }, + + fire: function(/*Event*/ evt, /*Array*/ args){ + // summary: Convenience function. Fire event "evt" and pass it + // the arguments specified in "args". + // evt: The event to fire. + // args: The arguments to pass to the event. + if(this[evt]){ + this[evt].apply(this, (args||[])); + } + return this; // dojo.lfx.IAnimation + }, + + repeat: function(/*int*/ count){ + // summary: Set the repeat count of this object. + // count: How many times to repeat the animation. + this.repeatCount = count; + return this; // dojo.lfx.IAnimation + }, + + // private properties + _active: false, + _paused: false +}); + +dojo.lfx.Animation = function( /*Object*/ handlers, + /*int*/ duration, + /*dojo.lfx.Line*/ curve, + /*function*/ easing, + /*int*/ repeatCount, + /*int*/ rate){ + // summary + // a generic animation object that fires callbacks into it's handlers + // object at various states + // handlers: { 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)){ + /* curve: Array + pId: a */ + 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(/*int?*/ delay, /*bool?*/ gotoStart){ + // summary: Start the animation. + // delay: How many milliseconds to delay before starting. + // gotoStart: If true, starts the animation from the beginning; otherwise, + // starts it from its current position. + if(gotoStart){ + clearTimeout(this._timer); + this._active = false; + this._paused = false; + this._percent = 0; + }else if(this._active && !this._paused){ + return this; // dojo.lfx.Animation + } + + this.fire("handler", ["beforeBegin"]); + this.fire("beforeBegin"); + + if(delay > 0){ + setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay); + return this; // dojo.lfx.Animation + } + + 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; // dojo.lfx.Animation + }, + + pause: function(){ + // summary: Pauses a running animation. + clearTimeout(this._timer); + if(!this._active){ return this; /*dojo.lfx.Animation*/} + this._paused = true; + var value = this.curve.getValue(this._percent / 100); + this.fire("handler", ["pause", value]); + this.fire("onPause", [value]); + return this; // dojo.lfx.Animation + }, + + gotoPercent: function(/*Decimal*/ pct, /*bool?*/ andPlay){ + // summary: Sets the progress of the animation. + // pct: A percentage in decimal notation (between and including 0.0 and 1.0). + // andPlay: If true, play the animation after setting the progress. + clearTimeout(this._timer); + this._active = true; + this._paused = true; + this._percent = pct; + if(andPlay){ this.play(); } + return this; // dojo.lfx.Animation + }, + + stop: function(/*bool?*/ gotoEnd){ + // summary: Stops a running animation. + // gotoEnd: If true, the animation will end. + 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; // dojo.lfx.Animation + }, + + status: function(){ + // summary: Returns a string representation of the status of + // the animation. + if(this._active){ + return this._paused ? "paused" : "playing"; // String + }else{ + return "stopped"; // String + } + 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.Animation + } +}); + +dojo.lfx.Combine = function(/*dojo.lfx.IAnimation...*/ animations){ + // summary: An animation object to play animations passed to it at the same time. + 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]))){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + 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(/*int?*/ delay, /*bool?*/ gotoStart){ + // summary: Start the animations. + // delay: How many milliseconds to delay before starting. + // gotoStart: If true, starts the animations from the beginning; otherwise, + // starts them from their current position. + if( !this._anims.length ){ return this; /*dojo.lfx.Combine*/} + + this.fire("beforeBegin"); + + if(delay > 0){ + setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay); + return this; // dojo.lfx.Combine + } + + if(gotoStart || this._anims[0].percent == 0){ + this.fire("onBegin"); + } + this.fire("onPlay"); + this._animsCall("play", null, gotoStart); + return this; // dojo.lfx.Combine + }, + + pause: function(){ + // summary: Pauses the running animations. + this.fire("onPause"); + this._animsCall("pause"); + return this; // dojo.lfx.Combine + }, + + stop: function(/*bool?*/ gotoEnd){ + // summary: Stops the running animations. + // gotoEnd: If true, the animations will end. + this.fire("onStop"); + this._animsCall("stop", gotoEnd); + return this; // dojo.lfx.Combine + }, + + // private methods + _onAnimsEnded: function(){ + this._animsEnded++; + if(this._animsEnded >= this._anims.length){ + this.fire("onEnd"); + } + return this; // dojo.lfx.Combine + }, + + _animsCall: function(/*String*/ 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.Combine + } +}); + +dojo.lfx.Chain = function(/*dojo.lfx.IAnimation...*/ animations) { + // summary: An animation object to play animations passed to it + // one after another. + 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]))){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + 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(/*int?*/ delay, /*bool?*/ gotoStart){ + // summary: Start the animation sequence. + // delay: How many milliseconds to delay before starting. + // gotoStart: If true, starts the sequence from the beginning; otherwise, + // starts it from its current position. + if( !this._anims.length ) { return this; /*dojo.lfx.Chain*/} + 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; // dojo.lfx.Chain + } + + 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; // dojo.lfx.Chain + }, + + pause: function(){ + // summary: Pauses the running animation sequence. + if( this._anims[this._currAnim] ) { + this._anims[this._currAnim].pause(); + this.fire("onPause", [this._currAnim]); + } + return this; // dojo.lfx.Chain + }, + + playPause: function(){ + // summary: If the animation sequence is playing, pause it; otherwise, + // play it. + 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; // dojo.lfx.Chain + }, + + stop: function(){ + // summary: Stops the running animations. + var currAnim = this._anims[this._currAnim]; + if(currAnim){ + currAnim.stop(); + this.fire("onStop", [this._currAnim]); + } + return currAnim; // dojo.lfx.IAnimation + }, + + // 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.Chain + } +}); + +dojo.lfx.combine = function(/*dojo.lfx.IAnimation...*/ animations){ + // summary: Convenience function. Returns a dojo.lfx.Combine created + // using the animations passed in. + var anims = arguments; + if(dojo.lang.isArray(arguments[0])){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + anims = arguments[0]; + } + if(anims.length == 1){ return anims[0]; } + return new dojo.lfx.Combine(anims); // dojo.lfx.Combine +} + +dojo.lfx.chain = function(/*dojo.lfx.IAnimation...*/ animations){ + // summary: Convenience function. Returns a dojo.lfx.Chain created + // using the animations passed in. + var anims = arguments; + if(dojo.lang.isArray(arguments[0])){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + anims = arguments[0]; + } + if(anims.length == 1){ return anims[0]; } + return new dojo.lfx.Chain(anims); // dojo.lfx.Combine +} + +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(/* DOMEvent */evt){ + // summary + // Returns the target of an event + 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; // HTMLElement +} + +dojo.html.getViewport = function(){ + // summary + // Returns the dimensions of the viewable area of a browser window + 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 }; // object +} + +dojo.html.getScroll = function(){ + // summary + // Returns the scroll position of the document + 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. + }; // object +} + +dojo.html.getParentByType = function(/* HTMLElement */node, /* string */type) { + // summary + // Returns the first ancestor of node with tagName 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; // HTMLElement +} + +dojo.html.getAttribute = function(/* HTMLElement */node, /* string */attr){ + // summary + // Returns the value of attribute attr from node. + 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; // string + } + + // try returning the attributes value, if we couldn't get it as a string + if(v && v.value){ + return v.value; // string + } + + // 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; // string + }else if(node.getAttribute(ta)){ + return node.getAttribute(ta); // string + }else if(node.getAttribute(ta.toLowerCase())){ + return node.getAttribute(ta.toLowerCase()); // string + } + return null; // string +} + +dojo.html.hasAttribute = function(/* HTMLElement */node, /* string */attr){ + // summary + // Determines whether or not the specified node carries a value for the attribute in question. + return dojo.html.getAttribute(dojo.byId(node), attr) ? true : false; // boolean +} + +dojo.html.getCursorPosition = function(/* DOMEvent */e){ + // summary + // 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} + // NOTE: for events delivered via dojo.event.connect() and/or dojoAttachEvent (for widgets), + // you can just access evt.pageX and evt.pageY, rather than calling this function. + 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; // object +} + +dojo.html.isTag = function(/* HTMLElement */node) { + // summary + // Like dojo.dom.isTag, except case-insensitive + node = dojo.byId(node); + if(node && node.tagName) { + for (var i=1; i, + //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(/* HTMLDocument */doc, /* string */tag){ + // summary + // Creates an element in the HTML document, here for ActiveX activation workaround. + return doc.createElement(tag); // HTMLElement + } +} + +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.uri.Uri"); + +dojo.uri = new function() { + this.dojoUri = function (/*dojo.uri.Uri||String*/uri) { + // summary: returns a Uri object resolved relative to the dojo root + return new dojo.uri.Uri(dojo.hostenv.getBaseScriptUri(), uri); + } + + this.moduleUri = function(/*String*/module, /*dojo.uri.Uri||String*/uri){ + // summary: returns a Uri object relative to a module + // description: Examples: dojo.uri.moduleUri("dojo","Editor"), or dojo.uri.moduleUri("acme","someWidget") + var loc = dojo.hostenv.getModuleSymbols(module).join('/'); + //var loc = dojo.hostenv.getModulePrefix(module); + if(!loc){return null;} + if(loc.lastIndexOf("/") != loc.length-1){loc += "/";} + return new dojo.uri.Uri(dojo.hostenv.getBaseScriptUri()+loc,uri); + } + + this.Uri = function (/*dojo.uri.Uri||String...*/) { + // summary: Constructor to create an object representing a URI. + // description: + // Each argument is evaluated in order relative to the next until + // a canonical uri is produced. To get an absolute Uri relative + // to the current document use + // new dojo.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.html.style"); + +dojo.html.getClass = function(/* HTMLElement */node){ + // summary + // 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; + 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, ""); // string +} + +dojo.html.getClasses = function(/* HTMLElement */node) { + // summary + // Returns an array of CSS classes currently assigned directly to the node in question. + // Returns an empty array if no classes are found; + var c = dojo.html.getClass(node); + return (c == "") ? [] : c.split(/\s+/g); // array +} + +dojo.html.hasClass = function(/* HTMLElement */node, /* string */classname){ + // summary + // 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. + return (new RegExp('(^|\\s+)'+classname+'(\\s+|$)')).test(dojo.html.getClass(node)) // boolean +} + +dojo.html.prependClass = function(/* HTMLElement */node, /* string */classStr){ + // summary + // 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. + classStr += " " + dojo.html.getClass(node); + return dojo.html.setClass(node, classStr); // boolean +} + +dojo.html.addClass = function(/* HTMLElement */node, /* string */classStr){ + // summary + // Adds the specified class to the end of the class list on the + // passed &node;. Returns &true; or &false; indicating success or failure. + if (dojo.html.hasClass(node, classStr)) { + return false; + } + classStr = (dojo.html.getClass(node) + " " + classStr).replace(/^\s+|\s+$/g,""); + return dojo.html.setClass(node, classStr); // boolean +} + +dojo.html.setClass = function(/* HTMLElement */node, /* string */classStr){ + // summary + // 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. + 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; +} + +dojo.html.removeClass = function(/* HTMLElement */node, /* string */classStr, /* boolean? */allowPartialMatches){ + // summary + // Removes the className from the node;. Returns true or false indicating success or failure. + 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); + }catch(e){ + dojo.debug("dojo.html.removeClass() failed", e); + } + return true; // boolean +} + +dojo.html.replaceClass = function(/* HTMLElement */node, /* string */newClass, /* string */oldClass) { + // summary + // Replaces 'oldClass' and adds 'newClass' to node + 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 +} + + +dojo.html.getElementsByClass = function( + /* string */classStr, + /* HTMLElement? */parent, + /* string? */nodeType, + /* integer? */classMatchType, + /* boolean? */useNonXpath +){ + // summary + // Returns an array of nodes for the given classStr, children of a + // parent, and optionally of a certain nodeType + // FIXME: temporarily set to false because of several dojo tickets related + // to the xpath version not working consistently in firefox. + useNonXpath = false; + 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; // NodeList + }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; // NodeList + } +} +dojo.html.getElementsByClassName = dojo.html.getElementsByClass; + +dojo.html.toCamelCase = function(/* string */selector){ + // summary + // Translates a CSS selector string to a camel-cased one. + 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; // string +} + +dojo.html.toSelectorCase = function(/* string */selector){ + // summary + // Translates a camel cased string to a selector cased one. + return selector.replace(/([A-Z])/g, "-$1" ).toLowerCase(); // string +} + +dojo.html.getComputedStyle = function(/* HTMLElement */node, /* string */cssSelector, /* integer? */inValue){ + // summary + // Returns the computed style of cssSelector on node. + 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 && dojo.html.isDescendantOf(node, node.ownerDocument)){ // W3, gecko, KHTML + try{ + // mozilla segfaults when margin-* and node is removed from doc + // FIXME: need to figure out a if there is quicker workaround + var cs = document.defaultView.getComputedStyle(node, ""); + if(cs){ + return cs.getPropertyValue(cssSelector); // integer + } + }catch(e){ // reports are that Safari can throw an exception above + if(node.style.getPropertyValue){ // W3 + return node.style.getPropertyValue(cssSelector); // integer + } else { + return inValue; // integer + } + } + } else if(node.currentStyle){ // IE + return node.currentStyle[property]; // integer + } + + if(node.style.getPropertyValue){ // W3 + return node.style.getPropertyValue(cssSelector); // integer + }else{ + return inValue; // integer + } +} + +dojo.html.getStyleProperty = function(/* HTMLElement */node, /* string */cssSelector){ + // summary + // Returns the value of the passed style + node = dojo.byId(node); + return (node && node.style ? node.style[dojo.html.toCamelCase(cssSelector)] : undefined); // string +} + +dojo.html.getStyle = function(/* HTMLElement */node, /* string */cssSelector){ + // summary + // Returns the computed value of the passed style + var value = dojo.html.getStyleProperty(node, cssSelector); + return (value ? value : dojo.html.getComputedStyle(node, cssSelector)); // string || integer +} + +dojo.html.setStyle = function(/* HTMLElement */node, /* string */cssSelector, /* string */value){ + // summary + // Set the value of passed style on node + node = dojo.byId(node); + if(node && node.style){ + var camelCased = dojo.html.toCamelCase(cssSelector); + node.style[camelCased] = value; + } +} + +dojo.html.setStyleText = function (/* HTMLElement */target, /* string */text) { + // summary + // Try to set the entire cssText property of the passed target; equiv of setting style attribute. + try { + target.style.cssText = text; + } catch (e) { + target.setAttribute("style", text); + } +} + +dojo.html.copyStyle = function(/* HTMLElement */target, /* HTMLElement */source){ + // summary + // 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(/* HTMLElement */node, /* string */cssSelector, /* boolean? */autoIsZero){ + // summary + // Get the value of passed selector, with the specific units used + var s = dojo.html.getComputedStyle(node, cssSelector); + if((!s)||((s == 'auto')&&(autoIsZero))){ + return { value: 0, units: 'px' }; // object + } + // 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() }; // object +} +dojo.html.getUnitValue.bad = { value: NaN, units: '' }; + +dojo.html.getPixelValue = function(/* HTMLElement */node, /* string */cssSelector, /* boolean? */autoIsZero){ + // summary + // Get the value of passed selector in pixels. + 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; // integer + } + // 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; // integer + } + return result.value; // integer +} + +dojo.html.setPositivePixelValue = function(/* HTMLElement */node, /* string */selector, /* integer */value){ + // summary + // Attempt to set the value of selector on node as a positive pixel value. + if(isNaN(value)){return false;} + node.style[selector] = Math.max(0, value) + 'px'; + return true; // boolean +} + +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(/* string */selector, /* string */declaration, /* integer? */index) { + // summary + // Attempt to insert declaration as selector on the internal stylesheet; if index try to set it there. + 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; // integer + } // 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; // integer + } // fail + } + + if (dojo.html.styleSheet.insertRule) { // W3 + var rule = selector + " { " + declaration + " }"; + return dojo.html.styleSheet.insertRule(rule, index); // integer + } else if (dojo.html.styleSheet.addRule) { // IE + return dojo.html.styleSheet.addRule(selector, declaration, index); // integer + } else { + return null; // integer + } // fail +} + +dojo.html.removeCssRule = function(/* integer? */index){ + // summary + // Attempt to remove the rule at index. + if(!dojo.html.styleSheet){ + dojo.debug("no stylesheet defined for removing rules"); + return false; + } + if(dojo.render.html.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; // boolean +} + +dojo.html._insertedCssFiles = []; // cache container needed because IE reformats cssText when added to DOM +dojo.html.insertCssFile = function(/* string */URI, /* HTMLDocument? */doc, /* boolean? */checkDuplicates, /* boolean */fail_ok){ + // summary + // calls css by XmlHTTP and inserts it into DOM as + if(!URI){ return; } + if(!doc){ doc = document; } + var cssStr = dojo.hostenv.getText(URI, false, fail_ok); + if(cssStr===null){ return; } + 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, doc); + 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; // HTMLStyleElement +} + +dojo.html.insertCssText = function(/* string */cssStr, /* HTMLDocument? */doc, /* string? */URI){ + // summary + // Attempt to insert CSS rules into the document through inserting a style element + // DomNode Style = insertCssText(String ".dojoMenu {color: green;}"[, DomDoc document, dojo.uri.Uri Url ]) + if(!cssStr){ + return; // HTMLStyleElement + } + 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; // HTMLStyleElement + }else{ + head.appendChild(style); + } + if(style.styleSheet){// IE + var setFunc = function(){ + try{ + style.styleSheet.cssText = cssStr; + }catch(e){ dojo.debug(e); } + }; + if(style.styleSheet.disabled){ + setTimeout(setFunc, 10); + }else{ + setFunc(); + } + }else{ // w3c + var cssText = doc.createTextNode(cssStr); + style.appendChild(cssText); + } + return style; // HTMLStyleElement +} + +dojo.html.fixPathsInCssText = function(/* string */cssStr, /* string */URI){ + // summary + // usage: cssText comes from dojoroot/src/widget/templates/Foobar.css + // it has .dojoFoo { background-image: url(images/bar.png);} then uri should point to dojoroot/src/widget/templates/ + if(!cssStr || !URI){ return; } + var match, str = "", url = "", urlChrs = "[\\t\\s\\w\\(\\)\\/\\.\\\\'\"-:#=&?~]+"; + var regex = new RegExp('url\\(\\s*('+urlChrs+')\\s*\\)'); + var regexProtocol = /(file|https?|ftps?):\/\//; + regexTrim = new RegExp("^[\\s]*(['\"]?)("+urlChrs+")\\1[\\s]*?$"); + if(dojo.render.html.ie55 || dojo.render.html.ie60){ + var regexIe = new RegExp("AlphaImageLoader\\((.*)src\=['\"]("+urlChrs+")['\"]"); + // TODO: need to decide how to handle relative paths and AlphaImageLoader see #1441 + // current implementation breaks on build with intern_strings + while(match = regexIe.exec(cssStr)){ + url = match[2].replace(regexTrim, "$2"); + if(!regexProtocol.exec(url)){ + url = (new dojo.uri.Uri(URI, url).toString()); + } + str += cssStr.substring(0, match.index) + "AlphaImageLoader(" + match[1] + "src='" + url + "'"; + cssStr = cssStr.substr(match.index + match[0].length); + } + cssStr = str + cssStr; + str = ""; + } + + 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; // string +} + +dojo.html.setActiveStyleSheet = function(/* string */title){ + // summary + // Activate style sheet with specified 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(){ + // summary + // return the title of the currently active stylesheet + 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"); // string + } + } + return null; // string +} + +dojo.html.getPreferredStyleSheet = function(){ + // summary + // Return the preferred stylesheet title (i.e. link without alt attribute) + 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"); // string + } + } + return null; // string +} + +dojo.html.applyBrowserClass = function(/* HTMLElement */node){ + // summary + // Applies pre-set class names based on browser & version to the passed node. + // Modified version of Morris' CSS hack. + var drh=dojo.render.html; + var classes = { + dj_ie: drh.ie, + dj_ie55: drh.ie55, + dj_ie6: drh.ie60, + dj_ie7: drh.ie70, + dj_iequirks: drh.ie && drh.quirks, + dj_opera: drh.opera, + dj_opera8: drh.opera && (Math.floor(dojo.render.version)==8), + dj_opera9: drh.opera && (Math.floor(dojo.render.version)==9), + dj_khtml: drh.khtml, + dj_safari: drh.safari, + dj_gecko: drh.mozilla + }; // no dojo unsupported browsers + for(var p in classes){ + if(classes[p]){ + dojo.html.addClass(node, p); + } + } +}; + +dojo.provide("dojo.html.display"); + +dojo.html._toggle = function(node, tester, setter){ + node = dojo.byId(node); + setter(node, !tester(node)); + return tester(node); +} + +dojo.html.show = function(/* HTMLElement */node){ + // summary + // Show the passed element by reverting display property set by dojo.html.hide + 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 + } +} + +dojo.html.hide = function(/* HTMLElement */node){ + // summary + // Hide the passed element by setting display:none + 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'); +} + +dojo.html.setShowing = function(/* HTMLElement */node, /* boolean? */showing){ + // summary + // Calls show() if showing is true, hide() otherwise + dojo.html[(showing ? 'show' : 'hide')](node); +} + +dojo.html.isShowing = function(/* HTMLElement */node){ + // summary + // Returns whether the element is displayed or not. + // FIXME: returns true if node is bad, isHidden would be easier to make correct + return (dojo.html.getStyleProperty(node, 'display') != 'none'); // boolean +} + +dojo.html.toggleShowing = function(/* HTMLElement */node){ + // summary + // Call setShowing() on node with the complement of isShowing(), then return the new value of isShowing() + return dojo.html._toggle(node, dojo.html.isShowing, dojo.html.setShowing); // boolean +} + +// Simple mapping of tag names to display values +// FIXME: simplistic +dojo.html.displayMap = { tr: '', td: '', th: '', img: 'inline', span: 'inline', input: 'inline', button: 'inline' }; + +dojo.html.suggestDisplayByTagName = function(/* HTMLElement */node){ + // summary + // Suggest a value for the display property that will show 'node' based on it's tag + node = dojo.byId(node); + if(node && node.tagName){ + var tag = node.tagName.toLowerCase(); + return (tag in dojo.html.displayMap ? dojo.html.displayMap[tag] : 'block'); // string + } +} + +dojo.html.setDisplay = function(/* HTMLElement */node, /* string */display){ + // summary + // 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.setStyle(node, 'display', ((display instanceof String || typeof display == "string") ? display : (display ? dojo.html.suggestDisplayByTagName(node) : 'none'))); +} + +dojo.html.isDisplayed = function(/* HTMLElement */node){ + // summary + // 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 + return (dojo.html.getComputedStyle(node, 'display') != 'none'); // boolean +} + +dojo.html.toggleDisplay = function(/* HTMLElement */node){ + // summary + // Call setDisplay() on node with the complement of isDisplayed(), then + // return the new value of isDisplayed() + return dojo.html._toggle(node, dojo.html.isDisplayed, dojo.html.setDisplay); // boolean +} + +dojo.html.setVisibility = function(/* HTMLElement */node, /* string */visibility){ + // summary + // 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.setStyle(node, 'visibility', ((visibility instanceof String || typeof visibility == "string") ? visibility : (visibility ? 'visible' : 'hidden'))); +} + +dojo.html.isVisible = function(/* HTMLElement */node){ + // summary + // Returns 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 + return (dojo.html.getComputedStyle(node, 'visibility') != 'hidden'); // boolean +} + +dojo.html.toggleVisibility = function(node){ + // summary + // Call setVisibility() on node with the complement of isVisible(), then return the new value of isVisible() + return dojo.html._toggle(node, dojo.html.isVisible, dojo.html.setVisibility); // boolean +} + +dojo.html.setOpacity = function(/* HTMLElement */node, /* float */opacity, /* boolean? */dontFixOpacity){ + // summary + // Sets the opacity of node in a cross-browser way. + // float between 0.0 (transparent) and 1.0 (opaque) + 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= 0.999999 ? 1.0 : Number(opac); // float +} + +dojo.provide("dojo.html.color"); + + +dojo.html.getBackgroundColor = function(/* HTMLElement */node){ + // summary + // returns the background color of the passed node as a 32-bit color (RGBA) + 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.gfx.color.extractRGB(color); + } + return color; // array +} + +dojo.provide("dojo.html.layout"); + + +dojo.html.sumAncestorProperties = function(/* HTMLElement */node, /* string */prop){ + // summary + // Returns the sum of the passed property on all ancestors of node. + 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; // integer +} + +dojo.html.setStyleAttributes = function(/* HTMLElement */node, /* string */attributes) { + // summary + // allows a dev to pass a string similar to what you'd pass in style="", and apply it to a node. + node = dojo.byId(node); + var splittedAttribs=attributes.replace(/(;)?\s*$/, "").split(";"); + for(var i=0; i0){ + 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;inativeBoxType;--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; // object +} + +dojo.html.isPositionAbsolute = function(/* HTMLElement */node){ + // summary + // Returns true if the element is absolutely positioned. + return (dojo.html.getComputedStyle(node, 'position') == 'absolute'); // boolean +} + +dojo.html._sumPixelValues = function(/* HTMLElement */node, selectors, autoIsZero){ + var total = 0; + for(var x=0; x 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, boxtype); + 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; // object +} + +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.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, + /*Object[]*/ propertyMap, + /*int*/ duration, + /*function*/ easing, + /*Object*/ handlers){ + // summary: Returns an animation that will transition the properties of "nodes" + // depending how they are defined in "propertyMap". + // nodes: An array of DOMNodes or one DOMNode. + // propertyMap: { property: String, start: Decimal?, end: Decimal?, units: String? } + // An array of objects defining properties to change. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // handlers: { handler: Function?, onstart: Function?, onstop: Function?, onanimate: Function? } + 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){ + try{ + if(s == "opacity"){ + dojo.html.setOpacity(n, style[s]); + }else{ + n.style[s] = style[s]; + } + }catch(e){ dojo.debug(e); } + } + } + + 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.gfx.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.gfx.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.Animation +} + +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(/*DOMNode[]*/ nodes, + /*Object*/values, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary:Returns an animation that will fade the "nodes" from the start to end values passed. + // nodes: An array of DOMNodes or one DOMNode. + // values: { start: Decimal?, end: Decimal? } + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.Animation +} + +dojo.lfx.html.fadeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current opacity to fully opaque. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + return dojo.lfx.html.fade(nodes, { end: 1 }, duration, easing, callback); // dojo.lfx.Animation +} + +dojo.lfx.html.fadeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current opacity to fully transparent. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + return dojo.lfx.html.fade(nodes, { end: 0 }, duration, easing, callback); // dojo.lfx.Animation +} + +dojo.lfx.html.fadeShow = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from transparent to opaque and shows + // "nodes" at the end if it is hidden. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.Animation +} + +dojo.lfx.html.fadeHide = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current opacity to opaque and hides + // "nodes" at the end. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.Animation +} + +dojo.lfx.html.wipeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will show and wipe in "nodes". + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + + dojo.lang.forEach(nodes, function(node){ + var oprop = { }; // old properties of node (before we mucked w/them) + + // get node height, either it's natural height or it's height specified via style or class attributes + // (for FF, the node has to be (temporarily) rendered to measure height) + // TODO: should this offscreen code be part of dojo.html, so that getBorderBox() works on hidden nodes? + var origTop, origLeft, origPosition; + with(node.style){ + origTop=top; origLeft=left; origPosition=position; + top="-9999px"; left="-9999px"; position="absolute"; + display=""; + } + var height = dojo.html.getBorderBox(node).height; + with(node.style){ + top=origTop; left=origLeft; position=origPosition; + display="none"; + } + + var anim = dojo.lfx.propertyAnimation(node, + { "height": { + start: 1, // 0 causes IE to display the whole panel + end: function(){ return height; } + } + }, + duration, + easing); + + anim.connect("beforeBegin", function(){ + oprop.overflow = node.style.overflow; + oprop.height = node.style.height; + with(node.style){ + overflow = "hidden"; + height = "1px"; // 0 causes IE to display the whole panel + } + dojo.html.show(node); + }); + + anim.connect("onEnd", function(){ + with(node.style){ + overflow = oprop.overflow; + height = oprop.height; + } + if(callback){ callback(node, anim); } + }); + anims.push(anim); + }); + + return dojo.lfx.combine(anims); // dojo.lfx.Combine +} + +dojo.lfx.html.wipeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will wipe out and hide "nodes". + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + + dojo.lang.forEach(nodes, function(node){ + var oprop = { }; // old properties of node (before we mucked w/them) + var anim = dojo.lfx.propertyAnimation(node, + { "height": { + start: function(){ return dojo.html.getContentBox(node).height; }, + end: 1 // 0 causes IE to display the whole panel + } + }, + duration, + easing, + { + "beforeBegin": function(){ + oprop.overflow = node.style.overflow; + oprop.height = node.style.height; + with(node.style){ + overflow = "hidden"; + } + dojo.html.show(node); + }, + + "onEnd": function(){ + dojo.html.hide(node); + with(node.style){ + overflow = oprop.overflow; + height = oprop.height; + } + if(callback){ callback(node, anim); } + } + } + ); + anims.push(anim); + }); + + return dojo.lfx.combine(anims); // dojo.lfx.Combine +} + +dojo.lfx.html.slideTo = function(/*DOMNode*/ nodes, + /*Object*/ coords, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will slide "nodes" from its current position to + // the position defined in "coords". + // nodes: An array of DOMNodes or one DOMNode. + // coords: { top: Decimal?, left: Decimal? } + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + var compute = dojo.html.getComputedStyle; + + if(dojo.lang.isArray(coords)){ + /* coords: Array + pId: a */ + 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.Combine +} + +dojo.lfx.html.slideBy = function(/*DOMNode*/ nodes, /*Object*/ coords, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will slide "nodes" from its current position + // to its current position plus the numbers defined in "coords". + // nodes: An array of DOMNodes or one DOMNode. + // coords: { top: Decimal?, left: Decimal? } + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + var compute = dojo.html.getComputedStyle; + + if(dojo.lang.isArray(coords)){ + /* coords: Array + pId: a */ + 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.Combine +} + +dojo.lfx.html.explode = function(/*DOMNode*/ start, + /*DOMNode*/ endNode, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will + // start: + // endNode: + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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); + if(endNode.explodeClassName){ outline.className = endNode.explodeClassName; } + with(outline.style){ + position = "absolute"; + display = "none"; + // border = "1px solid black"; + var backgroundStyle = h.getStyle(start, "background-color"); + backgroundColor = backgroundStyle ? backgroundStyle.toLowerCase() : "transparent"; + backgroundColor = (backgroundColor == "transparent") ? "rgb(221, 221, 221)" : backgroundColor; + } + dojo.body().appendChild(outline); + + with(endNode.style){ + visibility = "hidden"; + display = "block"; + } + var endCoords = h.toCoordinateObject(endNode, true); + with(endNode.style){ + display = "none"; + visibility = "visible"; + } + + var props = { opacity: { start: 0.5, 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.Animation +} + +dojo.lfx.html.implode = function(/*DOMNode*/ startNode, + /*DOMNode*/ end, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will + // startNode: + // end: + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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); + if (startNode.explodeClassName) { outline.className = startNode.explodeClassName; } + 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.5 } }; + 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.Animation +} + +dojo.lfx.html.highlight = function(/*DOMNode[]*/ nodes, + /*dojo.gfx.color.Color*/ startColor, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will set the background color + // of "nodes" to startColor and transition it to "nodes" + // original color. + // startColor: Color to transition from. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.gfx.color.Color(startColor); + var endRgb = new dojo.gfx.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.Combine +} + +dojo.lfx.html.unhighlight = function(/*DOMNode[]*/ nodes, + /*dojo.gfx.color.Color*/ endColor, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will transition "nodes" background color + // from its current color to "endColor". + // endColor: Color to transition to. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + + dojo.lang.forEach(nodes, function(node){ + var color = new dojo.gfx.color.Color(dojo.html.getBackgroundColor(node)); + var rgb = new dojo.gfx.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.lfx.Combine +} + +dojo.lang.mixin(dojo.lfx, dojo.lfx.html); + +dojo.provide("dojo.lfx.*"); diff --git a/source/web/scripts/ajax/dojo/src/AdapterRegistry.js b/source/web/scripts/ajax/dojo/src/AdapterRegistry.js new file mode 100644 index 0000000000..742b182134 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/AdapterRegistry.js @@ -0,0 +1,88 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.AdapterRegistry"); +dojo.require("dojo.lang.func"); + +dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){ + // summary: + // A registry to make contextual calling/searching easier. + // description: + // Objects of this class keep list of arrays in the form [name, check, + // wrap, directReturn] that are used to determine what the contextual + // result of a set of checked arguments is. All check/wrap functions + // in this registry should be of the same arity. + this.pairs = []; + this.returnWrappers = returnWrappers || false; +} + +dojo.lang.extend(dojo.AdapterRegistry, { + register: function(name, check, /*Function*/ wrap, directReturn, override){ + // summary: + // register a check function to determine if the wrap function or + // object gets selected + // name: String + // a way to identify this matcher. + // check: Function + // a function that arguments are passed to from the adapter's + // match() function. The check function should return true if the + // given arguments are appropriate for the wrap function. + // directReturn: Boolean? + // If directReturn is true, the value passed in for wrap will be + // returned instead of being called. Alternately, the + // AdapterRegistry can be set globally to "return not call" using + // the returnWrappers property. Either way, this behavior allows + // the registry to act as a "search" function instead of a + // function interception library. + // override: Boolean? + // If override is given and true, the check function will be given + // highest priority. Otherwise, it will be the lowest priority + // adapter. + + var type = (override) ? "unshift" : "push"; + this.pairs[type]([name, check, wrap, directReturn]); + }, + + match: function(/* ... */){ + // summary: + // Find an adapter for the given arguments. If no suitable adapter + // is found, throws an exception. match() accepts any number of + // arguments, all of which are passed to all matching functions + // from the registered pairs. + for(var i = 0; i < this.pairs.length; i++){ + var pair = this.pairs[i]; + if(pair[1].apply(this, arguments)){ + if((pair[3])||(this.returnWrappers)){ + return pair[2]; + }else{ + return pair[2].apply(this, arguments); + } + } + } + throw new Error("No match found"); + // dojo.raise("No match found"); + }, + + unregister: function(name){ + // summary: Remove a named adapter from the registry + + // FIXME: this is kind of a dumb way to handle this. On a large + // registry this will be slow-ish and we can use the name as a lookup + // should we choose to trade memory for speed. + for(var i = 0; i < this.pairs.length; i++){ + var pair = this.pairs[i]; + if(pair[0] == name){ + this.pairs.splice(i, 1); + return true; + } + } + return false; + } +}); diff --git a/source/web/scripts/ajax/dojo/src/Deferred.js b/source/web/scripts/ajax/dojo/src/Deferred.js new file mode 100644 index 0000000000..882ecfffa0 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/Deferred.js @@ -0,0 +1,313 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.Deferred"); +dojo.require("dojo.lang.func"); + +dojo.Deferred = function(/*Function?*/ canceller){ + /* + NOTE: this namespace and documentation are imported wholesale + from MochiKit + + Encapsulates a sequence of callbacks in response to a value that + may not yet be available. This is modeled after the Deferred class + from Twisted . + + Why do we want this? JavaScript has no threads, and even if it did, + threads are hard. Deferreds are a way of abstracting non-blocking + events, such as the final response to an XMLHttpRequest. + + The sequence of callbacks is internally represented as a list + of 2-tuples containing the callback/errback pair. For example, + the following call sequence:: + + var d = new Deferred(); + d.addCallback(myCallback); + d.addErrback(myErrback); + d.addBoth(myBoth); + d.addCallbacks(myCallback, myErrback); + + is translated into a Deferred with the following internal + representation:: + + [ + [myCallback, null], + [null, myErrback], + [myBoth, myBoth], + [myCallback, myErrback] + ] + + The Deferred also keeps track of its current status (fired). + Its status may be one of three things: + + -1: no value yet (initial condition) + 0: success + 1: error + + A Deferred will be in the error state if one of the following + three conditions are met: + + 1. The result given to callback or errback is "instanceof" Error + 2. The previous callback or errback raised an exception while + executing + 3. The previous callback or errback returned a value "instanceof" + Error + + Otherwise, the Deferred will be in the success state. The state of + the Deferred determines the next element in the callback sequence to + run. + + When a callback or errback occurs with the example deferred chain, + something equivalent to the following will happen (imagine that + exceptions are caught and returned):: + + // d.callback(result) or d.errback(result) + if(!(result instanceof Error)){ + result = myCallback(result); + } + if(result instanceof Error){ + result = myErrback(result); + } + result = myBoth(result); + if(result instanceof Error){ + result = myErrback(result); + }else{ + result = myCallback(result); + } + + The result is then stored away in case another step is added to the + callback sequence. Since the Deferred already has a value available, + any new callbacks added will be called immediately. + + There are two other "advanced" details about this implementation that + are useful: + + Callbacks are allowed to return Deferred instances themselves, so you + can build complicated sequences of events with ease. + + The creator of the Deferred may specify a canceller. The canceller + is a function that will be called if Deferred.cancel is called before + the Deferred fires. You can use this to implement clean aborting of + an XMLHttpRequest, etc. Note that cancel will fire the deferred with + a CancelledError (unless your canceller returns another kind of + error), so the errbacks should be prepared to handle that error for + cancellable Deferreds. + + */ + + this.chain = []; + this.id = this._nextId(); + this.fired = -1; + this.paused = 0; + this.results = [null, null]; + this.canceller = canceller; + this.silentlyCancelled = false; +}; + +dojo.lang.extend(dojo.Deferred, { + getFunctionFromArgs: function(){ + var a = arguments; + if((a[0])&&(!a[1])){ + if(dojo.lang.isFunction(a[0])){ + return a[0]; + }else if(dojo.lang.isString(a[0])){ + return dj_global[a[0]]; + } + }else if((a[0])&&(a[1])){ + return dojo.lang.hitch(a[0], a[1]); + } + return null; + }, + + makeCalled: function() { + var deferred = new dojo.Deferred(); + deferred.callback(); + return deferred; + }, + + repr: function(){ + var state; + if(this.fired == -1){ + state = 'unfired'; + }else if(this.fired == 0){ + state = 'success'; + } else { + state = 'error'; + } + return 'Deferred(' + this.id + ', ' + state + ')'; + }, + + toString: dojo.lang.forward("repr"), + + _nextId: (function(){ + var n = 1; + return function(){ return n++; }; + })(), + + cancel: function(){ + // summary: Cancels a Deferred that has not yet received a value, or is + // waiting on another Deferred as its value. + // description: + // If a canceller is defined, the canceller is called. If the + // canceller did not return an error, or there was no canceller, + // then the errback chain is started with CancelledError. + if(this.fired == -1){ + if (this.canceller){ + this.canceller(this); + }else{ + this.silentlyCancelled = true; + } + if(this.fired == -1){ + this.errback(new Error(this.repr())); + } + }else if( (this.fired == 0)&& + (this.results[0] instanceof dojo.Deferred)){ + this.results[0].cancel(); + } + }, + + + _pause: function(){ + // summary: Used internally to signal that it's waiting on another Deferred + this.paused++; + }, + + _unpause: function(){ + // summary: Used internally to signal that it's no longer waiting on + // another Deferred. + this.paused--; + if ((this.paused == 0) && (this.fired >= 0)) { + this._fire(); + } + }, + + _continue: function(res){ + // summary: Used internally when a dependent deferred fires. + this._resback(res); + this._unpause(); + }, + + _resback: function(res){ + // The primitive that means either callback or errback + this.fired = ((res instanceof Error) ? 1 : 0); + this.results[this.fired] = res; + this._fire(); + }, + + _check: function(){ + if(this.fired != -1){ + if(!this.silentlyCancelled){ + dojo.raise("already called!"); + } + this.silentlyCancelled = false; + return; + } + }, + + callback: function(res){ + // summary: Begin the callback sequence with a non-error value. + + /* + callback or errback should only be called once on a given + Deferred. + */ + this._check(); + this._resback(res); + }, + + errback: function(res){ + // summary: Begin the callback sequence with an error result. + this._check(); + if(!(res instanceof Error)){ + res = new Error(res); + } + this._resback(res); + }, + + addBoth: function(cb, cbfn){ + /* summary + Add the same function as both a callback and an errback as the + next element on the callback sequence. This is useful for code + that you want to guarantee to run, e.g. a finalizer. + */ + var enclosed = this.getFunctionFromArgs(cb, cbfn); + if(arguments.length > 2){ + enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2); + } + return this.addCallbacks(enclosed, enclosed); + }, + + addCallback: function(cb, cbfn){ + // summary: Add a single callback to the end of the callback sequence. + var enclosed = this.getFunctionFromArgs(cb, cbfn); + if(arguments.length > 2){ + enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2); + } + return this.addCallbacks(enclosed, null); + }, + + addErrback: function(cb, cbfn){ + // summary: Add a single callback to the end of the callback sequence. + var enclosed = this.getFunctionFromArgs(cb, cbfn); + if(arguments.length > 2){ + enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2); + } + return this.addCallbacks(null, enclosed); + return this.addCallbacks(null, cbfn); + }, + + addCallbacks: function (cb, eb) { + // summary: Add separate callback and errback to the end of the callback + // sequence. + this.chain.push([cb, eb]) + if (this.fired >= 0) { + this._fire(); + } + return this; + }, + + _fire: function(){ + // summary: Used internally to exhaust the callback sequence when a result + // is available. + var chain = this.chain; + var fired = this.fired; + var res = this.results[fired]; + var self = this; + var cb = null; + while (chain.length > 0 && this.paused == 0) { + // Array + var pair = chain.shift(); + var f = pair[fired]; + if (f == null) { + continue; + } + try { + res = f(res); + fired = ((res instanceof Error) ? 1 : 0); + if(res instanceof dojo.Deferred) { + cb = function(res){ + self._continue(res); + } + this._pause(); + } + }catch(err){ + fired = 1; + res = err; + } + } + this.fired = fired; + this.results[fired] = res; + if((cb)&&(this.paused)){ + // this is for "tail recursion" in case the dependent + // deferred is already fired + res.addBoth(cb); + } + } +}); diff --git a/source/web/scripts/ajax/dojo/src/DeferredList.js b/source/web/scripts/ajax/dojo/src/DeferredList.js new file mode 100644 index 0000000000..0364ad8116 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/DeferredList.js @@ -0,0 +1,88 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.require("dojo.Deferred"); + +dojo.provide("dojo.DeferredList"); + + +dojo.DeferredList = function (list, /*bool?*/ fireOnOneCallback, /*bool?*/ fireOnOneErrback, /*bool?*/ consumeErrors, /*Function?*/ canceller) { + this.list = list; + this.resultList = new Array(this.list.length); + + // Deferred init + this.chain = []; + this.id = this._nextId(); + this.fired = -1; + this.paused = 0; + this.results = [null, null]; + this.canceller = canceller; + this.silentlyCancelled = false; + + if (this.list.length === 0 && !fireOnOneCallback) { + this.callback(this.resultList); + } + + this.finishedCount = 0; + this.fireOnOneCallback = fireOnOneCallback; + this.fireOnOneErrback = fireOnOneErrback; + this.consumeErrors = consumeErrors; + + var index = 0; + + var _this = this; + + dojo.lang.forEach(this.list, function(d) { + var _index = index; + //dojo.debug("add cb/errb index "+_index); + d.addCallback(function(r) { _this._cbDeferred(_index, true, r) }); + d.addErrback(function(r) { _this._cbDeferred(_index, false, r) }); + index++; + }); + +}; + + +dojo.inherits(dojo.DeferredList, dojo.Deferred); + +dojo.lang.extend(dojo.DeferredList, { + + _cbDeferred: function (index, succeeded, result) { + //dojo.debug("Fire "+index+" succ "+succeeded+" res "+result); + this.resultList[index] = [succeeded, result]; + this.finishedCount += 1; + if (this.fired !== 0) { + if (succeeded && this.fireOnOneCallback) { + this.callback([index, result]); + } else if (!succeeded && this.fireOnOneErrback) { + this.errback(result); + } else if (this.finishedCount == this.list.length) { + this.callback(this.resultList); + } + } + if (!succeeded && this.consumeErrors) { + result = null; + } + return result; + }, + + gatherResults: function (deferredList) { + var d = new dojo.DeferredList(deferredList, false, true, false); + d.addCallback(function (results) { + var ret = []; + for (var i = 0; i < results.length; i++) { + ret.push(results[i][1]); + } + return ret; + }); + return d; + } +}); + diff --git a/source/web/scripts/ajax/dojo/src/a11y.js b/source/web/scripts/ajax/dojo/src/a11y.js new file mode 100644 index 0000000000..2b417ae1ae --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/a11y.js @@ -0,0 +1,103 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.a11y"); + +dojo.require("dojo.uri.*"); +dojo.require("dojo.html.common"); + +dojo.a11y = { + // imgPath: String path to the test image for determining if images are displayed or not + // doAccessibleCheck: Boolean if true will perform check for need to create accessible widgets + // accessible: Boolean uninitialized when null (accessible check has not been performed) + // if true generate accessible widgets + imgPath:dojo.uri.dojoUri("src/widget/templates/images"), + doAccessibleCheck: true, + accessible: null, + + checkAccessible: function(){ + // summary: + // perform check for accessibility if accessibility checking is turned + // on and the accessibility test has not been performed yet + if(this.accessible === null){ + this.accessible = false; //default + if(this.doAccessibleCheck == true){ + this.accessible = this.testAccessible(); + } + } + return this.accessible; /* Boolean */ + }, + + testAccessible: function(){ + // summary: + // Always perform the accessibility check to determine if high + // contrast mode is on or display of images are turned off. Currently only checks + // in IE and Mozilla. + this.accessible = false; //default + if (dojo.render.html.ie || dojo.render.html.mozilla){ + var div = document.createElement("div"); + //div.style.color="rgb(153,204,204)"; + div.style.backgroundImage = "url(\"" + this.imgPath + "/tab_close.gif\")"; + // must add to hierarchy before can view currentStyle below + dojo.body().appendChild(div); + // in FF and IE the value for the current background style of the added div + // will be "none" in high contrast mode + // in FF the return value will be url(invalid-url:) when running over http + var bkImg = null; + if (window.getComputedStyle ) { + var cStyle = getComputedStyle(div, ""); + bkImg = cStyle.getPropertyValue("background-image"); + }else{ + bkImg = div.currentStyle.backgroundImage; + } + var bUseImgElem = false; + if (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" )) { + this.accessible = true; + } + /* + if(this.accessible == false && document.images){ + // test if images are off in IE + var testImg = new Image(); + if(testImg.fileSize) { + testImg.src = this.imgPath + "/tab_close.gif"; + if(testImg.fileSize < 0){ + this.accessible = true; + } + } + }*/ + dojo.body().removeChild(div); + } + return this.accessible; /* Boolean */ + }, + + setCheckAccessible: function(/* Boolean */ bTest){ + // summary: + // Set whether or not to check for accessibility mode. Default value + // of module is true - perform check for accessibility modes. + // bTest: Boolean - true to check; false to turn off checking + this.doAccessibleCheck = bTest; + }, + + setAccessibleMode: function(){ + // summary: + // perform the accessibility check and sets the correct mode to load + // a11y widgets. Only runs if test for accessiiblity has not been performed yet. + // Call testAccessible() to force the test. + if (this.accessible === null){ + if (this.checkAccessible()){ + dojo.render.html.prefixes.unshift("a11y"); + } + } + return this.accessible; /* Boolean */ + } +}; + +//dojo.hostenv.modulesLoadedListeners.unshift(function() { dojo.a11y.setAccessibleMode(); }); +//dojo.event.connect("before", dojo.hostenv, "makeWidgets", dojo.a11y, "setAccessibleMode"); diff --git a/source/web/scripts/ajax/dojo/src/animation.js b/source/web/scripts/ajax/dojo/src/animation.js new file mode 100644 index 0000000000..d877b8f3fb --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/animation.js @@ -0,0 +1,14 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.animation"); +dojo.require("dojo.animation.Animation"); + +dojo.deprecated("dojo.animation is slated for removal in 0.5; use dojo.lfx instead.", "0.5"); diff --git a/source/web/scripts/ajax/dojo/src/animation/Animation.js b/source/web/scripts/ajax/dojo/src/animation/Animation.js new file mode 100644 index 0000000000..0d704e5603 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/animation/Animation.js @@ -0,0 +1,245 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.animation.Animation"); +dojo.require("dojo.animation.AnimationEvent"); + +dojo.require("dojo.lang.func"); +dojo.require("dojo.math"); +dojo.require("dojo.math.curves"); + +dojo.deprecated("dojo.animation.Animation is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5"); + +/* +Animation package based off of Dan Pupius' work on Animations: +http://pupius.co.uk/js/Toolkit.Drawing.js +*/ + +dojo.animation.Animation = function(/*dojo.math.curves.* */ curve, /*int*/ duration, /*Decimal?*/ accel, /*int?*/ repeatCount, /*int?*/ rate) { + // summary: Animation object iterates a set of numbers over a curve for a given amount of time, calling 'onAnimate' at each step. + // curve: Curve to animate over. + // duration: Duration of the animation, in milliseconds. + // accel: Either an integer or curve representing amount of acceleration. (?) Default is linear acceleration. + // repeatCount: Number of times to repeat the animation. Default is 0. + // rate: Time between animation steps, in milliseconds. Default is 25. + // description: Calls the following events: "onBegin", "onAnimate", "onEnd", "onPlay", "onPause", "onStop" + // If the animation implements a "handler" function, that will be called before each event is called. + + if(dojo.lang.isArray(curve)) { + // curve: Array + // id: i + curve = new dojo.math.curves.Line(curve[0], curve[1]); + } + this.curve = curve; + this.duration = duration; + this.repeatCount = repeatCount || 0; + this.rate = rate || 25; + if(accel) { + // accel: Decimal + // id: j + if(dojo.lang.isFunction(accel.getValue)) { + // accel: dojo.math.curves.CatmullRom + // id: k + this.accel = accel; + } else { + var i = 0.35*accel+0.5; // 0.15 <= i <= 0.85 + this.accel = new dojo.math.curves.CatmullRom([[0], [i], [1]], 0.45); + } + } +} + +dojo.lang.extend(dojo.animation.Animation, { + // public properties + curve: null, + duration: 0, + repeatCount: 0, + accel: null, + + // events + onBegin: null, + onAnimate: null, + onEnd: null, + onPlay: null, + onPause: null, + onStop: null, + handler: null, + + // "private" properties + _animSequence: null, + _startTime: null, + _endTime: null, + _lastFrame: null, + _timer: null, + _percent: 0, + _active: false, + _paused: false, + _startRepeatCount: 0, + + // public methods + play: function(/*Boolean?*/ gotoStart) { + // summary: Play the animation. + // goToStart: If true, will restart the animation from the beginning. + // Otherwise, starts from current play counter. + // description: Sends an "onPlay" event to any observers. + // Also sends an "onBegin" event if starting from the beginning. + if( gotoStart ) { + clearTimeout(this._timer); + this._active = false; + this._paused = false; + this._percent = 0; + } else if( this._active && !this._paused ) { + return; + } + + this._startTime = new Date().valueOf(); + if( this._paused ) { + this._startTime -= (this.duration * this._percent / 100); + } + this._endTime = this._startTime + this.duration; + this._lastFrame = this._startTime; + + var e = new dojo.animation.AnimationEvent(this, null, this.curve.getValue(this._percent), + this._startTime, this._startTime, this._endTime, this.duration, this._percent, 0); + + this._active = true; + this._paused = false; + + if( this._percent == 0 ) { + if(!this._startRepeatCount) { + this._startRepeatCount = this.repeatCount; + } + e.type = "begin"; + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onBegin == "function") { this.onBegin(e); } + } + + e.type = "play"; + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onPlay == "function") { this.onPlay(e); } + + if(this._animSequence) { this._animSequence._setCurrent(this); } + + this._cycle(); + }, + + pause: function() { + // summary: Temporarily stop the animation, leaving the play counter at the current location. + // Resume later with sequence.play() + // description: Sends an "onPause" AnimationEvent to any observers. + clearTimeout(this._timer); + if( !this._active ) { return; } + this._paused = true; + var e = new dojo.animation.AnimationEvent(this, "pause", this.curve.getValue(this._percent), + this._startTime, new Date().valueOf(), this._endTime, this.duration, this._percent, 0); + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onPause == "function") { this.onPause(e); } + }, + + playPause: function() { + // summary: Toggle between play and paused states. + if( !this._active || this._paused ) { + this.play(); + } else { + this.pause(); + } + }, + + gotoPercent: function(/*int*/ pct, /*Boolean*/ andPlay) { + // summary: Set the play counter at a certain point in the animation. + // pct: Point to set the play counter to, expressed as a percentage (0 to 100). + // andPlay: If true, will start the animation at the counter automatically. + clearTimeout(this._timer); + this._active = true; + this._paused = true; + this._percent = pct; + if( andPlay ) { this.play(); } + }, + + stop: function(/*Boolean?*/ gotoEnd) { + // summary: Stop the animation. + // gotoEnd: If true, will advance play counter to the end before sending the event. + // description: Sends an "onStop" AnimationEvent to any observers. + clearTimeout(this._timer); + var step = this._percent / 100; + if( gotoEnd ) { + step = 1; + } + var e = new dojo.animation.AnimationEvent(this, "stop", this.curve.getValue(step), + this._startTime, new Date().valueOf(), this._endTime, this.duration, this._percent); + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onStop == "function") { this.onStop(e); } + this._active = false; + this._paused = false; + }, + + status: function() { + // summary: Return the status of the animation. + // description: Returns one of "playing", "paused" or "stopped". + if( this._active ) { + return this._paused ? "paused" : "playing"; /* String */ + } else { + return "stopped"; /* String */ + } + }, + + // "private" methods + _cycle: function() { + // summary: Perform once 'cycle' or step of the animation. + clearTimeout(this._timer); + if( this._active ) { + var curr = new Date().valueOf(); + var step = (curr - this._startTime) / (this._endTime - this._startTime); + var fps = 1000 / (curr - this._lastFrame); + this._lastFrame = curr; + + if( step >= 1 ) { + step = 1; + this._percent = 100; + } else { + this._percent = step * 100; + } + + // Perform accelleration + if(this.accel && this.accel.getValue) { + step = this.accel.getValue(step); + } + + var e = new dojo.animation.AnimationEvent(this, "animate", this.curve.getValue(step), + this._startTime, curr, this._endTime, this.duration, this._percent, Math.round(fps)); + + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onAnimate == "function") { this.onAnimate(e); } + + if( step < 1 ) { + this._timer = setTimeout(dojo.lang.hitch(this, "_cycle"), this.rate); + } else { + e.type = "end"; + this._active = false; + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onEnd == "function") { this.onEnd(e); } + + if( this.repeatCount > 0 ) { + this.repeatCount--; + this.play(true); + } else if( this.repeatCount == -1 ) { + this.play(true); + } else { + if(this._startRepeatCount) { + this.repeatCount = this._startRepeatCount; + this._startRepeatCount = 0; + } + if( this._animSequence ) { + this._animSequence._playNext(); + } + } + } + } + } +}); diff --git a/source/web/scripts/ajax/dojo/src/animation/AnimationEvent.js b/source/web/scripts/ajax/dojo/src/animation/AnimationEvent.js new file mode 100644 index 0000000000..bc14d02a1b --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/animation/AnimationEvent.js @@ -0,0 +1,64 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.animation.AnimationEvent"); +dojo.require("dojo.lang.common"); + +dojo.deprecated("dojo.animation.AnimationEvent is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5"); + +dojo.animation.AnimationEvent = function( + /*dojo.animation.Animation*/ animation, + /*String*/type, + /*int[] */ coords, + /*int*/ startTime, + /*int*/ currentTime, + /*int*/ endTime, + /*int*/ duration, + /*int*/ percent, + /*int?*/ fps) { + // summary: Event sent at various points during an Animation. + // animation: Animation throwing the event. + // type: One of: "animate", "begin", "end", "play", "pause" or "stop". + // coords: Current coordinates of the animation. + // startTime: Time the animation was started, as milliseconds. + // currentTime: Time the event was thrown, as milliseconds. + // endTime: Time the animation is expected to complete, as milliseconds. + // duration: Duration of the animation, in milliseconds. + // percent: Percent of the animation that has completed, between 0 and 100. + // fps: Frames currently shown per second. (Only sent for "animate" event). + // description: The AnimationEvent has public properties of the same name as + // all constructor arguments, plus "x", "y" and "z". + + this.type = type; // "animate", "begin", "end", "play", "pause", "stop" + this.animation = animation; + + this.coords = coords; + this.x = coords[0]; + this.y = coords[1]; + this.z = coords[2]; + + this.startTime = startTime; + this.currentTime = currentTime; + this.endTime = endTime; + + this.duration = duration; + this.percent = percent; + this.fps = fps; +}; +dojo.extend(dojo.animation.AnimationEvent, { + coordsAsInts: function() { + // summary: Coerce the coordinates into integers. + var cints = new Array(this.coords.length); + for(var i = 0; i < this.coords.length; i++) { + cints[i] = Math.round(this.coords[i]); + } + return cints; + } +}); diff --git a/source/web/scripts/ajax/dojo/src/animation/AnimationSequence.js b/source/web/scripts/ajax/dojo/src/animation/AnimationSequence.js new file mode 100644 index 0000000000..4c1392423b --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/animation/AnimationSequence.js @@ -0,0 +1,162 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.animation.AnimationSequence"); +dojo.require("dojo.animation.AnimationEvent"); +dojo.require("dojo.animation.Animation"); + +dojo.deprecated("dojo.animation.AnimationSequence is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5"); + +dojo.animation.AnimationSequence = function(/*int?*/ repeatCount){ + // summary: Sequence of Animations, played one after the other. + // repeatCount: Number of times to repeat the entire sequence. Default is 0 (play once only). + // description: Calls the following events: "onBegin", "onEnd", "onNext" + // If the animation implements a "handler" function, that will be called before each event is called. + this._anims = []; + this.repeatCount = repeatCount || 0; +} + +dojo.lang.extend(dojo.animation.AnimationSequence, { + repeatCount: 0, + + _anims: [], + _currAnim: -1, + + onBegin: null, + onEnd: null, + onNext: null, + handler: null, + + add: function() { + // summary: Add one or more Animations to the sequence. + // description: args: Animations (dojo.animation.Animation) to add to the sequence. + for(var i = 0; i < arguments.length; i++) { + this._anims.push(arguments[i]); + arguments[i]._animSequence = this; + } + }, + + remove: function(/*dojo.animation.Animation*/ anim) { + // summary: Remove one particular animation from the sequence. + // amim: Animation to remove. + for(var i = 0; i < this._anims.length; i++) { + if( this._anims[i] == anim ) { + this._anims[i]._animSequence = null; + this._anims.splice(i, 1); + break; + } + } + }, + + removeAll: function() { + // summary: Remove all animations from the sequence. + for(var i = 0; i < this._anims.length; i++) { + this._anims[i]._animSequence = null; + } + this._anims = []; + this._currAnim = -1; + }, + + clear: function() { + // summary: Remove all animations from the sequence. + this.removeAll(); + }, + + play: function(/*Boolean?*/ gotoStart) { + // summary: Play the animation sequence. + // gotoStart: If true, will start at the beginning of the first sequence. + // Otherwise, starts at the current play counter of the current animation. + // description: Sends an "onBegin" event to any observers. + if( this._anims.length == 0 ) { return; } + if( gotoStart || !this._anims[this._currAnim] ) { + this._currAnim = 0; + } + if( this._anims[this._currAnim] ) { + if( this._currAnim == 0 ) { + var e = {type: "begin", animation: this._anims[this._currAnim]}; + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onBegin == "function") { this.onBegin(e); } + } + this._anims[this._currAnim].play(gotoStart); + } + }, + + pause: function() { + // summary: temporarily stop the current animation. Resume later with sequence.play() + if( this._anims[this._currAnim] ) { + this._anims[this._currAnim].pause(); + } + }, + + playPause: function() { + // summary: Toggle between play and paused states. + if( this._anims.length == 0 ) { return; } + if( this._currAnim == -1 ) { this._currAnim = 0; } + if( this._anims[this._currAnim] ) { + this._anims[this._currAnim].playPause(); + } + }, + + stop: function() { + // summary: Stop the current animation. + if( this._anims[this._currAnim] ) { + this._anims[this._currAnim].stop(); + } + }, + + status: function() { + // summary: Return the status of the current animation. + // description: Returns one of "playing", "paused" or "stopped". + if( this._anims[this._currAnim] ) { + return this._anims[this._currAnim].status(); + } else { + return "stopped"; + } + }, + + _setCurrent: function(/*dojo.animation.Animation*/ anim) { + // summary: Set the current animation. + // anim: Animation to make current, must have already been added to the sequence. + for(var i = 0; i < this._anims.length; i++) { + if( this._anims[i] == anim ) { + this._currAnim = i; + break; + } + } + }, + + _playNext: function() { + // summary: Play the next animation in the sequence. + // description: Sends an "onNext" event to any observers. + // Also sends "onEnd" if the last animation is finished. + if( this._currAnim == -1 || this._anims.length == 0 ) { return; } + this._currAnim++; + if( this._anims[this._currAnim] ) { + var e = {type: "next", animation: this._anims[this._currAnim]}; + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onNext == "function") { this.onNext(e); } + this._anims[this._currAnim].play(true); + } else { + var e = {type: "end", animation: this._anims[this._anims.length-1]}; + if(typeof this.handler == "function") { this.handler(e); } + if(typeof this.onEnd == "function") { this.onEnd(e); } + if(this.repeatCount > 0) { + this._currAnim = 0; + this.repeatCount--; + this._anims[this._currAnim].play(true); + } else if(this.repeatCount == -1) { + this._currAnim = 0; + this._anims[this._currAnim].play(true); + } else { + this._currAnim = -1; + } + } + } +}); diff --git a/source/web/scripts/ajax/dojo/src/animation/Timer.js b/source/web/scripts/ajax/dojo/src/animation/Timer.js new file mode 100644 index 0000000000..bf83ccbb4a --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/animation/Timer.js @@ -0,0 +1,16 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.animation.Timer"); +dojo.require("dojo.lang.timing.Timer"); + +dojo.deprecated("dojo.animation.Timer is now dojo.lang.timing.Timer", "0.5"); + +dojo.animation.Timer = dojo.lang.timing.Timer; diff --git a/source/web/scripts/ajax/dojo/src/animation/__package__.js b/source/web/scripts/ajax/dojo/src/animation/__package__.js new file mode 100644 index 0000000000..1ceb877f8e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/animation/__package__.js @@ -0,0 +1,20 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: [ + "dojo.animation.AnimationEvent", + "dojo.animation.Animation", + "dojo.animation.AnimationSequence" + ] +}); +dojo.provide("dojo.animation.*"); + +dojo.deprecated("dojo.Animation.* is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5"); diff --git a/source/web/scripts/ajax/dojo/src/behavior.js b/source/web/scripts/ajax/dojo/src/behavior.js new file mode 100644 index 0000000000..26995d6732 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/behavior.js @@ -0,0 +1,248 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.behavior"); +dojo.require("dojo.event.*"); + +dojo.require("dojo.experimental"); +dojo.experimental("dojo.behavior"); + +dojo.behavior = new function(){ + function arrIn(obj, name){ + if(!obj[name]){ obj[name] = []; } + return obj[name]; + } + + function forIn(obj, scope, func){ + var tmpObj = {}; + for(var x in obj){ + if(typeof tmpObj[x] == "undefined"){ + if(!func){ + scope(obj[x], x); + }else{ + func.call(scope, obj[x], x); + } + } + } + } + + // FIXME: need a better test so we don't exclude nightly Safari's! + this.behaviors = {}; + this.add = function(behaviorObj){ + /* behavior objects are specified in the following format: + * + * { + * "#id": { + * "found": function(element){ + * // ... + * }, + * + * "onblah": {targetObj: foo, targetFunc: "bar"}, + * + * "onblarg": "/foo/bar/baz/blarg", + * + * "onevent": function(evt){ + * }, + * + * "onotherevent: function(evt){ + * // ... + * } + * }, + * + * "#id2": { + * // ... + * }, + * + * "#id3": function(element){ + * // ... + * }, + * + * // publish the match on a topic + * "#id4": "/found/topic/name", + * + * // match all direct descendants + * "#id4 > *": function(element){ + * // ... + * }, + * + * // match the first child node that's an element + * "#id4 > @firstElement": { ... }, + * + * // match the last child node that's an element + * "#id4 > @lastElement": { ... }, + * + * // all elements of type tagname + * "tagname": { + * // ... + * }, + * + * // maps to roughly: + * // dojo.lang.forEach(body.getElementsByTagName("tagname1"), function(node){ + * // dojo.lang.forEach(node.getElementsByTagName("tagname2"), function(node2){ + * // dojo.lang.forEach(node2.getElementsByTagName("tagname3", function(node3){ + * // // apply rules + * // }); + * // }); + * // }); + * "tagname1 tagname2 tagname3": { + * // ... + * }, + * + * ".classname": { + * // ... + * }, + * + * "tagname.classname": { + * // ... + * }, + * } + * + * The "found" method is a generalized handler that's called as soon + * as the node matches the selector. Rules for values that follow also + * apply to the "found" key. + * + * The "on*" handlers are attached with dojo.event.connect(). If the + * value is not a function but is rather an object, it's assumed to be + * the "other half" of a dojo.event.kwConnect() argument object. It + * may contain any/all properties of such a connection modifier save + * for the sourceObj and sourceFunc properties which are filled in by + * the system automatically. If a string is instead encountered, the + * node publishes the specified event on the topic contained in the + * string value. + * + * If the value corresponding to the ID key is a function and not a + * list, it's treated as though it was the value of "found". + * + */ + + var tmpObj = {}; + forIn(behaviorObj, this, function(behavior, name){ + var tBehavior = arrIn(this.behaviors, name); + if((dojo.lang.isString(behavior))||(dojo.lang.isFunction(behavior))){ + behavior = { found: behavior }; + } + forIn(behavior, function(rule, ruleName){ + arrIn(tBehavior, ruleName).push(rule); + }); + }); + } + + this.apply = function(){ + dojo.profile.start("dojo.behavior.apply"); + var r = dojo.render.html; + // note, we apply one way for fast queries and one way for slow + // iteration. So be it. + var safariGoodEnough = (!r.safari); + if(r.safari){ + // Anything over release #420 should work the fast way + var uas = r.UA.split("AppleWebKit/")[1]; + if(parseInt(uas.match(/[0-9.]{3,}/)) >= 420){ + safariGoodEnough = true; + } + } + if((dj_undef("behaviorFastParse", djConfig) ? (safariGoodEnough) : djConfig["behaviorFastParse"])){ + this.applyFast(); + }else{ + this.applySlow(); + } + dojo.profile.end("dojo.behavior.apply"); + } + + this.matchCache = {}; + + this.elementsById = function(id, handleRemoved){ + var removed = []; + var added = []; + arrIn(this.matchCache, id); + if(handleRemoved){ + var nodes = this.matchCache[id]; + for(var x=0; x"); + } catch (e) { + var script = document.createElement("script"); + script.src = spath; + document.getElementsByTagName("head")[0].appendChild(script); + } + } + } +})(); diff --git a/source/web/scripts/ajax/dojo/src/browser_debug.js b/source/web/scripts/ajax/dojo/src/browser_debug.js new file mode 100644 index 0000000000..b1b563d018 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/browser_debug.js @@ -0,0 +1,176 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.hostenv.loadedUris.push("../src/bootstrap1.js"); +dojo.hostenv.loadedUris.push("../src/loader.js"); +dojo.hostenv.loadedUris.push("../src/hostenv_browser.js"); +dojo.hostenv.loadedUris.push("../src/bootstrap2.js"); +dojo.hostenv._loadedUrisListStart = dojo.hostenv.loadedUris.length; + +function removeComments(contents){ + contents = new String((!contents) ? "" : contents); + // clobber all comments + // FIXME broken if // or /* inside quotes or regexp + contents = contents.replace( /^(.*?)\/\/(.*)$/mg , "$1"); + contents = contents.replace( /(\n)/mg , "__DOJONEWLINE"); + contents = contents.replace( /\/\*(.*?)\*\//g , ""); + return contents.replace( /__DOJONEWLINE/mg , "\n"); +} + +dojo.hostenv.getRequiresAndProvides = function(contents){ + // FIXME: should probably memoize this! + if(!contents){ return []; } + + + // check to see if we need to load anything else first. Ugg. + var deps = []; + var tmp; + RegExp.lastIndex = 0; + var testExp = /dojo.(hostenv.loadModule|hostenv.require|require|requireIf|kwCompoundRequire|hostenv.conditionalLoadModule|hostenv.startPackage|provide)\([\w\W]*?\)/mg; + while((tmp = testExp.exec(contents)) != null){ + deps.push(tmp[0]); + } + return deps; +} + +dojo.hostenv.getDelayRequiresAndProvides = function(contents){ + // FIXME: should probably memoize this! + if(!contents){ return []; } + + // check to see if we need to load anything else first. Ugg. + var deps = []; + var tmp; + RegExp.lastIndex = 0; + var testExp = /dojo.(requireAfterIf)\([\w\W]*?\)/mg; + while((tmp = testExp.exec(contents)) != null){ + deps.push(tmp[0]); + } + return deps; +} + +/* +dojo.getNonExistantDescendants = function(objpath){ + var ret = []; + // fast path for no periods + if(typeof objpath != "string"){ return dj_global; } + if(objpath.indexOf('.') == -1){ + if(dj_undef(objpath, dj_global)){ + ret.push[objpath]; + } + return ret; + } + + var syms = objpath.split(/\./); + var obj = dj_global; + for(var i=0;i=0; x--){ + dojo.clobberLastObject(removals[x]); + } + var depList = []; + var seen = dojo.hostenv._writtenIncludes; + for(var x=0; x"); + } + document.write(""); + dojo.hostenv._loadedUrisListStart = 0; + if (!willCallAgain) { + // turn off debugAtAllCosts, so that dojo.require() calls inside of ContentPane hrefs + // work correctly + dj_eval = old_dj_eval; + dojo.hostenv.loadUri = dojo.hostenv.oldLoadUri; + } +} diff --git a/source/web/scripts/ajax/dojo/src/cal/iCalendar.js b/source/web/scripts/ajax/dojo/src/cal/iCalendar.js new file mode 100644 index 0000000000..0da52f9d17 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/cal/iCalendar.js @@ -0,0 +1,815 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.cal.iCalendar"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.cal.textDirectory"); +dojo.require("dojo.date.common"); +dojo.require("dojo.date.serialize"); + + +dojo.cal.iCalendar.fromText = function (/* string */text) { + // summary + // Parse text of an iCalendar and return an array of iCalendar objects + + var properties = dojo.cal.textDirectory.tokenise(text); + var calendars = []; + + //dojo.debug("Parsing iCal String"); + for (var i = 0, begun = false; i < properties.length; i++) { + var prop = properties[i]; + if (!begun) { + if (prop.name == 'BEGIN' && prop.value == 'VCALENDAR') { + begun = true; + var calbody = []; + } + } else if (prop.name == 'END' && prop.value == 'VCALENDAR') { + calendars.push(new dojo.cal.iCalendar.VCalendar(calbody)); + begun = false; + } else { + calbody.push(prop); + } + } + return /* array */calendars; +} + + +dojo.cal.iCalendar.Component = function (/* string */ body ) { + // summary + // A component is the basic container of all this stuff. + + if (!this.name) { + this.name = "COMPONENT" + } + + this.properties = []; + this.components = []; + + if (body) { + for (var i = 0, context = ''; i < body.length; i++) { + if (context == '') { + if (body[i].name == 'BEGIN') { + context = body[i].value; + var childprops = []; + } else { + this.addProperty(new dojo.cal.iCalendar.Property(body[i])); + } + } else if (body[i].name == 'END' && body[i].value == context) { + if (context=="VEVENT") { + this.addComponent(new dojo.cal.iCalendar.VEvent(childprops)); + } else if (context=="VTIMEZONE") { + this.addComponent(new dojo.cal.iCalendar.VTimeZone(childprops)); + } else if (context=="VTODO") { + this.addComponent(new dojo.cal.iCalendar.VTodo(childprops)); + } else if (context=="VJOURNAL") { + this.addComponent(new dojo.cal.iCalendar.VJournal(childprops)); + } else if (context=="VFREEBUSY") { + this.addComponent(new dojo.cal.iCalendar.VFreeBusy(childprops)); + } else if (context=="STANDARD") { + this.addComponent(new dojo.cal.iCalendar.Standard(childprops)); + } else if (context=="DAYLIGHT") { + this.addComponent(new dojo.cal.iCalendar.Daylight(childprops)); + } else if (context=="VALARM") { + this.addComponent(new dojo.cal.iCalendar.VAlarm(childprops)); + }else { + dojo.unimplemented("dojo.cal.iCalendar." + context); + } + context = ''; + } else { + childprops.push(body[i]); + } + } + + if (this._ValidProperties) { + this.postCreate(); + } + } +} + +dojo.extend(dojo.cal.iCalendar.Component, { + + addProperty: function (prop) { + // summary + // push a new property onto a component. + this.properties.push(prop); + this[prop.name.toLowerCase()] = prop; + }, + + addComponent: function (prop) { + // summary + // add a component to this components list of children. + this.components.push(prop); + }, + + postCreate: function() { + for (var x=0; x 0) { + return events; + } + + return null; + } +}); + +/* + * STANDARD + */ + +var StandardProperties = [ + _P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true), + _P("comment"), _P("rdate"), _P("rrule"), _P("tzname") +]; + + +dojo.cal.iCalendar.Standard = function (/* string */ body) { + // summary + // STANDARD Component + + this.name = "STANDARD"; + this._ValidProperties = StandardProperties; + dojo.cal.iCalendar.Component.call(this, body); +} + +dojo.inherits(dojo.cal.iCalendar.Standard, dojo.cal.iCalendar.Component); + +/* + * DAYLIGHT + */ + +var DaylightProperties = [ + _P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true), + _P("comment"), _P("rdate"), _P("rrule"), _P("tzname") +]; + +dojo.cal.iCalendar.Daylight = function (/* string */ body) { + // summary + // Daylight Component + this.name = "DAYLIGHT"; + this._ValidProperties = DaylightProperties; + dojo.cal.iCalendar.Component.call(this, body); +} + +dojo.inherits(dojo.cal.iCalendar.Daylight, dojo.cal.iCalendar.Component); + +/* + * VEVENT + */ + +var VEventProperties = [ + // these can occur once only + _P("class", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1), + _P("geo", 1), _P("last-mod", 1), _P("location", 1), _P("organizer", 1), + _P("priority", 1), _P("dtstamp", 1), _P("seq", 1), _P("status", 1), + _P("summary", 1), _P("transp", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1), + // these two are exclusive + [_P("dtend", 1), _P("duration", 1)], + // these can occur many times over + _P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"), + _P("exdate"), _P("exrule"), _P("rstatus"), _P("related"), _P("resources"), + _P("rdate"), _P("rrule") +]; + +dojo.cal.iCalendar.VEvent = function (/* string */ body) { + // summary + // VEVENT Component + this._ValidProperties = VEventProperties; + this.name = "VEVENT"; + dojo.cal.iCalendar.Component.call(this, body); + this.recurring = false; + this.startDate = dojo.date.fromIso8601(this.dtstart.value); +} + +dojo.inherits(dojo.cal.iCalendar.VEvent, dojo.cal.iCalendar.Component); + +dojo.extend(dojo.cal.iCalendar.VEvent, { + getDates: function(until) { + var dtstart = this.getDate(); + + var recurranceSet = []; + var weekdays=["su","mo","tu","we","th","fr","sa"]; + var order = { + "daily": 1, "weekly": 2, "monthly": 3, "yearly": 4, + "byday": 1, "bymonthday": 1, "byweekno": 2, "bymonth": 3, "byyearday": 4}; + + // expand rrules into the recurrance + for (var x=0; x interval) { + interval = rrule.interval; + } + + var set = []; + var freqInt = order[freq]; + + if (rrule.until) { + var tmpUntil = dojo.date.fromIso8601(rrule.until); + } else { + var tmpUntil = until + } + + if (tmpUntil > until) { + tmpUntil = until + } + + + if (dtstart 1) { + var regex = "([+-]?)([0-9]{1,3})"; + for (var z=1; x 0) { + var regex = "([+-]?)([0-9]{1,3})"; + for (var z=0; z 0) { + var regex = "([+-]?)([0-9]{0,1}?)([A-Za-z]{1,2})"; + for (var z=0; z 0){ + arr = this.name.split('.'); + this.group = arr[0]; + this.name = arr[1]; + } + + // don't do any parsing, leave to implementation + this.value = right; +} + + +dojo.cal.textDirectory.tokenise = function(/*String*/text){ +// summary: parses text into an array of properties. + + // normlize to one property per line and parse + var nText = dojo.string.normalizeNewlines(text,"\n"). + replace(/\n[ \t]/g, ''). + replace(/\x00/g, ''); + + var lines = nText.split("\n"); + var properties = []; + + for(var i = 0; i < lines.length; i++){ + if(dojo.string.trim(lines[i]) == ''){ continue; } + var prop = new dojo.cal.textDirectory.Property(lines[i]); + properties.push(prop); + } + return properties; // Array +} diff --git a/source/web/scripts/ajax/dojo/src/charting/Axis.js b/source/web/scripts/ajax/dojo/src/charting/Axis.js new file mode 100644 index 0000000000..fcd3bc6c51 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/Axis.js @@ -0,0 +1,146 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.Axis"); +dojo.require("dojo.lang.common"); + +dojo.charting.Axis = function(/* string? */label, /* string? */scale, /* array? */labels){ + var id = "dojo-charting-axis-"+dojo.charting.Axis.count++; + this.getId=function(){ return id; }; + this.setId=function(key){ id = key; }; + this.scale = scale || "linear"; // linear || log + this.label = label || ""; + this.showLabel = true; // show axis label. + this.showLabels = true; // show interval ticks. + this.showLines = false; // if you want lines over the range of the plot area + this.showTicks = false; // if you want tick marks on the axis. + this.range = { upper : 0, lower : 0 }; // range of individual axis. + this.origin = "min"; // this can be any number, "min" or "max". min/max is translated on init. + + this.labels = labels || []; + this._labels = []; // what we really use to draw things. + this.nodes={ main: null, axis: null, label: null, labels: null, lines: null, ticks: null }; +}; +dojo.charting.Axis.count = 0; + +dojo.extend(dojo.charting.Axis, { + // TODO: implement log scaling. + getCoord: function( + /* float */val, + /* dojo.charting.PlotArea */plotArea, + /* dojo.charting.Plot */plot + ){ + // summary + // returns the coordinate of val based on this axis range, plot area and plot. + val = parseFloat(val, 10); + var area = plotArea.getArea(); + if(plot.axisX == this){ + var offset = 0 - this.range.lower; + var min = this.range.lower + offset; // FIXME: check this. + var max = this.range.upper + offset; + val += offset; + return (val*((area.right-area.left)/max))+area.left; // float + } else { + var max = this.range.upper; + var min = this.range.lower; + var offset = 0; + if(min<0){ + offset += Math.abs(min); + } + max += offset; min += offset; val += offset; + var pmin = area.bottom; + var pmax = area.top; + return (((pmin-pmax)/(max-min))*(max-val))+pmax; + } + }, + initializeOrigin: function(drawAgainst, plane){ + // figure out the origin value. + if(isNaN(this.origin)){ + if(this.origin.toLowerCase() == "max"){ + this.origin = drawAgainst.range[(plane=="y")?"upper":"lower"]; + } + else if (this.origin.toLowerCase() == "min"){ + this.origin = drawAgainst.range[(plane=="y")?"lower":"upper"]; + } + else { this.origin=0; } + } + }, + initializeLabels: function(){ + // Translate the labels if needed. + if(this.labels.length == 0){ + this.showLabels = false; + this.showLines = false; + this.showTicks = false; + } else { + if(this.labels[0].label && this.labels[0].value != null){ + for(var i=0; i0){ + var s=a.pop(); + this._labels.push({ label: s, value: this.range.upper }); + } + // do the rest. + if(a.length>0){ + var range = this.range.upper - this.range.lower; + var step = range / (this.labels.length-1); + for(var i=1; i<=a.length; i++){ + this._labels.push({ + label: a[i-1], + value: this.range.lower+(step*i) + }); + } + } + } + } + }, + initialize: function(plotArea, plot, drawAgainst, plane){ + // summary + // Initialize the passed axis descriptor. Note that this should always + // be the result of plotArea.getAxes, and not the axis directly! + this.destroy(); + this.initializeOrigin(drawAgainst, plane); + this.initializeLabels(); + var node = this.render(plotArea, plot, drawAgainst, plane); + return node; + }, + destroy: function(){ + for(var p in this.nodes){ + while(this.nodes[p] && this.nodes[p].childNodes.length > 0){ + this.nodes[p].removeChild(this.nodes[p].childNodes[0]); + } + if(this.nodes[p] && this.nodes[p].parentNode){ + this.nodes[p].parentNode.removeChild(this.nodes[p]); + } + this.nodes[p] = null; + } + } +}); + +dojo.requireIf(dojo.render.svg.capable, "dojo.charting.svg.Axis"); +dojo.requireIf(dojo.render.vml.capable, "dojo.charting.vml.Axis"); diff --git a/source/web/scripts/ajax/dojo/src/charting/Chart.js b/source/web/scripts/ajax/dojo/src/charting/Chart.js new file mode 100644 index 0000000000..13502e50dd --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/Chart.js @@ -0,0 +1,85 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.Chart"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.charting.PlotArea"); + +dojo.charting.Chart = function( + /* HTMLElement? */node, + /* string? */title, + /* string? */description +){ + // summary + // Create the basic Chart object. + this.node = node || null; + this.title = title || "Chart"; // pure string. + this.description = description || ""; // HTML is allowed. + this.plotAreas = []; +}; + +dojo.extend(dojo.charting.Chart, { + // methods + addPlotArea: function(/* object */obj, /* bool? */doRender){ + // summary + // Add a PlotArea to this chart; object should be in the + // form of: { plotArea, (x, y) or (top, left) } + if(obj.x!=null && obj.left==null){ obj.left = obj.x; } + if(obj.y!=null && obj.top==null){ obj.top = obj.y; } + this.plotAreas.push(obj); + if(doRender){ this.render(); } + }, + + // events + onInitialize:function(chart){ }, + onRender:function(chart){ }, + onDestroy:function(chart){ }, + + // standard build methods + initialize: function(){ + // summary + // Initialize the Chart by rendering it. + if(!this.node){ + dojo.raise("dojo.charting.Chart.initialize: there must be a root node defined for the Chart."); + } + this.destroy(); + this.render(); + this.onInitialize(this); + }, + render:function(){ + // summary + // Render the chart in its entirety. + if(this.node.style.position != "absolute"){ + this.node.style.position = "relative"; + } + for(var i=0; i 0){ + this.node.removeChild(this.node.childNodes[0]); + } + } +}); diff --git a/source/web/scripts/ajax/dojo/src/charting/Plot.js b/source/web/scripts/ajax/dojo/src/charting/Plot.js new file mode 100644 index 0000000000..0560eee05e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/Plot.js @@ -0,0 +1,103 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.Plot"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.charting.Axis"); +dojo.require("dojo.charting.Series"); + +dojo.charting.RenderPlotSeries = { Singly:"single", Grouped:"grouped" }; + +dojo.charting.Plot = function( + /* dojo.charting.Axis? */xaxis, + /* dojo.charting.Axis? */yaxis, + /* dojo.charting.Series[]? */series +){ + // summary + // Creates a new instance of a Plot (X/Y Axis + n Series). + var id = "dojo-charting-plot-"+dojo.charting.Plot.count++; + this.getId=function(){ return id; }; + this.setId=function(key){ id = key; }; + this.axisX = null; + this.axisY = null; + this.series = []; + this.dataNode = null; + + // for bar charts, pie charts and stacked charts, change to Grouped. + this.renderType = dojo.charting.RenderPlotSeries.Singly; + if(xaxis){ + this.setAxis(xaxis,"x"); + } + if(yaxis){ + this.setAxis(yaxis,"y"); + } + if(series){ + for(var i=0; i 0){ + node.removeChild(node.childNodes[0]); + } + this.dataNode=null; + } +}); diff --git a/source/web/scripts/ajax/dojo/src/charting/PlotArea.js b/source/web/scripts/ajax/dojo/src/charting/PlotArea.js new file mode 100644 index 0000000000..6e64791a5b --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/PlotArea.js @@ -0,0 +1,195 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.PlotArea"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.gfx.color"); +dojo.require("dojo.gfx.color.hsl"); +dojo.require("dojo.charting.Plot"); + +dojo.charting.PlotArea = function(){ + // summary + // Creates a new PlotArea for drawing onto a Chart. + var id="dojo-charting-plotarea-"+dojo.charting.PlotArea.count++; + this.getId=function(){ return id; }; + this.setId=function(key){ id = key; }; + this.areaType = "standard"; // standard || radar + this.plots = []; // plots that will be drawn on this area + + this.size={ width:600, height:400 }; + this.padding={ top:10, right:10, bottom:20, left:20 }; + + // drawing node references. + this.nodes = { + main:null, + area:null, + background: null, + axes: null, + plots: null + }; + + // this is preset for a limited color range (green to purple), + // anticipating a max of 32 series on this plot area. + // if you need more flexibility, override these numbers. + this._color = { h: 140, s: 120, l: 120, step: 27 }; +}; +dojo.charting.PlotArea.count = 0; + +dojo.extend(dojo.charting.PlotArea, { + nextColor: function(){ + // summary + // Advances the internal HSV cursor and returns the next generated color. + var rgb=dojo.gfx.color.hsl2rgb(this._color.h, this._color.s, this._color.l); + this._color.h = (this._color.h + this._color.step)%360; + while(this._color.h < 140){ + this._color.h += this._color.step; + } + return dojo.gfx.color.rgb2hex(rgb[0], rgb[1], rgb[2]); // string + }, + getArea:function(){ + // summary + // Return an object describing the coordinates of the available area to plot on. + return { + left: this.padding.left, + right: this.size.width - this.padding.right, + top: this.padding.top, + bottom: this.size.height - this.padding.bottom, + toString:function(){ + var a=[ this.top, this.right, this.bottom, this.left ]; + return "["+a.join()+"]"; + } + }; // object + }, + getAxes: function(){ + // summary + // get the unique axes for this plot area. + var axes={}; + for(var i=0; i 0){ + node.removeChild(node.childNodes[0]); + } + this.nodes[p]=null; + } + } +}); + +dojo.requireIf(dojo.render.svg.capable, "dojo.charting.svg.PlotArea"); +dojo.requireIf(dojo.render.vml.capable, "dojo.charting.vml.PlotArea"); diff --git a/source/web/scripts/ajax/dojo/src/charting/Plotters.js b/source/web/scripts/ajax/dojo/src/charting/Plotters.js new file mode 100644 index 0000000000..3c91d67197 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/Plotters.js @@ -0,0 +1,19 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.Plotters"); + +/* + * Plotters is the placeholder; what will happen is that the proper renderer types + * will be mixed into this object (as opposed to creating a new one). + */ + +dojo.requireIf(dojo.render.svg.capable, "dojo.charting.svg.Plotters"); +dojo.requireIf(dojo.render.vml.capable, "dojo.charting.vml.Plotters"); diff --git a/source/web/scripts/ajax/dojo/src/charting/README.txt b/source/web/scripts/ajax/dojo/src/charting/README.txt new file mode 100644 index 0000000000..28a1c71b24 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/README.txt @@ -0,0 +1,46 @@ +Dojo Charting Engine +========================================================================= +The Dojo Charting Engine is a (fairly) complex object structure, designed +to provide as much flexibility as possible in terms of chart construction. +To this end, the engine details the following structure: + +Chart +---PlotArea[] +------Plot[] +---------Axis (axisX) +---------Axis (axisY) +---------Series[] + + +A Chart object is the main entity; it is the entire graphic. A Chart may +have any number of PlotArea objects, which are the basic canvas against +which data is plotted. A PlotArea may have any number of Plot objects, +which is a container representing up to 2 axes and any number of series +to be plotted against those axes; a Series represents a binding against +two fields from a data source (initial rev, this data source is always of +type dojo.collections.Store but this will probably change once dojo.data +is in production). + +The point of this structure is to allow for as much flexibility as possible +in terms of what kinds of charts can be represented by the engine. The +current plan is to accomodate up to analytical financial charts, which tend +to have 3 plot areas and any number of different types of axes on each one. + +The main exception to this is the pie chart, which will have it's own +custom codebase. Also, 3D charts are not accounted for at this time, +although the only thing that will probably need to be altered to make +that work would be Plot and Series (to accomodate the additional Z axis). + +Finally, a Plot will render its series[] through the use of Plotters, which +are custom methods to render specific types of charts. +------------------------------------------------------------------------- +In terms of widgets, the basic concept is that there is a central, super- +flexible Chart widget (Chart, oddly enough), and then any number of preset +chart type widgets, that are basically built to serve a simple, easy +purpose. For instance, if someone just needs to plot a series of lines, +they would be better off using the LineChart widget; but if someone needed +to plot a combo chart, that has 2 Y Axes (one linear, one log) against the +same X Axis, using lines and areas, then they will want to use a Chart widget. +Note also that unlike other widgets, the Charting engine *can* be called +directly from script *without* the need for the actual widget engine to be +loaded; the Chart widgets are thin wrappers around the charting engine. \ No newline at end of file diff --git a/source/web/scripts/ajax/dojo/src/charting/Series.js b/source/web/scripts/ajax/dojo/src/charting/Series.js new file mode 100644 index 0000000000..f5174f96c3 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/Series.js @@ -0,0 +1,215 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.Series"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.charting.Plotters"); + +dojo.charting.Series = function(/* object? */kwArgs){ + // summary + // Create an instance of data series for plotting. + var args = kwArgs || { length:1 }; + this.dataSource = args.dataSource || null; + this.bindings = { }; + this.color = args.color; + this.label = args.label; + + if(args.bindings){ + for(var p in args.bindings){ + this.addBinding(p, args.bindings[p]); + } + } +}; + +dojo.extend(dojo.charting.Series, { + bind:function(/* dojo.collections.Store */src, /* object */bindings){ + // summary + // Bind this series to src, with bindings. + this.dataSource = src; + this.bindings = bindings; + }, + addBinding:function(/* string */name, /* string */binding){ + // summary + // Bind to field "binding" using "name". + this.bindings[name] = binding; + }, + evaluate:function(/* object? */kwArgs){ + // summary + // Evaluate all bindings and return an array of objects describing the bind. + var ret = []; + var a = this.dataSource.getData(); + var l = a.length; + var start = 0; + var end = l; + + /* Allow for ranges. Can be done in one of two ways: + * 1. { from, to } as 0-based indices + * 2. { length } as num of data points to get; a negative + * value will start from the end of the data set. + * No kwArg object means the full data set will be evaluated + * and returned. + */ + if(kwArgs){ + if(kwArgs.from){ + start = Math.max(kwArgs.from,0); + if(kwArgs.to){ + end = Math.min(kwArgs.to, end); + } + } + else if(kwArgs.length){ + if(kwArgs.length < 0){ + // length points from end + start = Math.max((end + length),0); + } else { + end = Math.min((start + length), end); + } + } + } + + for(var i=start; i b.x) return 1; + if(a.x < b.x) return -1; + return 0; + }); + } + return ret; // array + }, + + // trends + trends:{ + createRange: function(/* array */values, /* int */len){ + // summary + // Creates the data range used for all trends. + var idx = values.length-1; + var length = (len||values.length); + return { "index": idx, "length": length, "start":Math.max(idx-length,0) }; // object + }, + + mean: function(/* array */values, /* int */len){ + // summary + // Returns the mean or average over the set of values. + var range = this.createRange(values, len); + if(range.index<0){ return 0; } + var total = 0; + var count = 0; + for(var i=range.index; i>=range.start; i--){ + total += values[i].y; + count++; + } + total /= Math.max(count,1); + return total; // float + }, + + variance: function(/* array */values,/* int */len){ + // summary + // Returns the variance of the set of values. + var range = this.createRange(values,len); + if(range.index < 0){ return 0; } + var total = 0; + var square = 0; + var count = 0; + for(var i=range.index; i>=range.start; i--){ + total += values[i].y; + square += Math.pow(values[i].y, 2); + count++; + } + return (square/count)-Math.pow(total/count,2); // float + }, + + standardDeviation: function(/* array */values, /* int */len){ + // summary + // Returns the standard deviation of the set of values. + return Math.sqrt(this.getVariance(values, len)); // float + }, + + max: function(/* array */values, /* int */len){ + // summary + // Returns the max number in the set of values. + var range = this.createRange(values, len); + if(range.index < 0){ return 0; } + var max = Number.MIN_VALUE; + for (var i=range.index; i>=range.start; i--){ + max = Math.max(values[i].y,max); + } + return max; // float + }, + + min: function(/* array */values, /* int */len){ + // summary + // Returns the lowest number in the set of values. + var range=this.createRange(values, len); + if(range.index < 0){ return 0; } + var min = Number.MAX_VALUE; + for(var i=range.index; i>=range.start; i--){ + min = Math.min(values[i].y, min); + } + return min; // float + }, + + median: function(/* array */values, /* int */len){ + // summary + // Returns the median in the set of values (number closest to the middle of a sorted set). + var range = this.createRange(values, len); + if(range.index<0){ return 0; } + var a = []; + for (var i=range.index; i>=range.start; i--){ + var b=false; + for(var j=0; j 0){ + return a[Math.ceil(a.length / 2)]; // float + } + return 0; // float + }, + + mode: function(/* array */values, /* int */len){ + // summary + // Returns the mode in the set of values + var range=this.createRange(values, len); + if(range.index<0){ return 0; } + var o = {}; + var ret = 0 + var median = Number.MIN_VALUE; + for(var i=range.index; i>=range.start; i--){ + if (!o[values[i].y]){ + o[values[i].y] = 1; + } else { + o[values[i].y]++; + } + } + for(var p in o){ + if(median < o[p]){ + median = o[p]; + ret=p; + } + } + return ret; + } + } +}); diff --git a/source/web/scripts/ajax/dojo/src/charting/__package__.js b/source/web/scripts/ajax/dojo/src/charting/__package__.js new file mode 100644 index 0000000000..969c611bb7 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/__package__.js @@ -0,0 +1,11 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.*"); diff --git a/source/web/scripts/ajax/dojo/src/charting/svg/Axis.js b/source/web/scripts/ajax/dojo/src/charting/svg/Axis.js new file mode 100644 index 0000000000..e16b54328a --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/charting/svg/Axis.js @@ -0,0 +1,226 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.charting.svg.Axis"); +dojo.require("dojo.lang.common"); + +if(dojo.render.svg.capable){ + dojo.extend(dojo.charting.Axis, { + renderLines: function( + /* dojo.charting.PlotArea */plotArea, + /* dojo.charting.Plot */plot, + /* string */plane + ){ + // summary + // Renders any reference lines for this axis. + if(this.nodes.lines){ + while(this.nodes.lines.childNodes.length > 0){ + this.nodes.lines.removeChild(this.nodes.lines.childNodes[0]); + } + if(this.nodes.lines.parentNode){ + this.nodes.lines.parentNode.removeChild(this.nodes.lines); + this.nodes.lines = null; + } + } + + var area = plotArea.getArea(); + var g = this.nodes.lines = document.createElementNS(dojo.svg.xmlns.svg, "g"); + g.setAttribute("id", this.getId()+"-lines"); + for(var i=0; i 0){ + this.nodes.ticks.removeChild(this.nodes.ticks.childNodes[0]); + } + if(this.nodes.ticks.parentNode){ + this.nodes.ticks.parentNode.removeChild(this.nodes.ticks); + this.nodes.ticks = null; + } + } + + var g = this.nodes.ticks = document.createElementNS(dojo.svg.xmlns.svg, "g"); + g.setAttribute("id", this.getId()+"-ticks"); + for(var i=0; i 0){ + this.nodes.labels.removeChild(this.nodes.labels.childNodes[0]); + } + if(this.nodes.labels.parentNode){ + this.nodes.labels.parentNode.removeChild(this.nodes.labels); + this.nodes.labels = null; + } + } + var g = this.nodes.labels = document.createElementNS(dojo.svg.xmlns.svg, "g"); + g.setAttribute("id", this.getId()+"-labels"); + + for(var i=0; i 0){ + x = xOrigin; + } + + var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect"); + bar.setAttribute("fill", data[j][i].series.color); + bar.setAttribute("stroke-width", "0"); + bar.setAttribute("x", xA); + bar.setAttribute("y", y); + bar.setAttribute("width", w); + bar.setAttribute("height", barH); + bar.setAttribute("fill-opacity", "0.6"); + if(applyTo){ applyTo(bar, data[j][i].src); } + group.appendChild(bar); + } + } + return group; // SVGGElement + }, + Gantt: function( + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* object? */kwArgs, + /* function? */applyTo + ){ + // summary + // Plots a grouped set of Gantt bars + // Bindings: high/low + var area = plotarea.getArea(); + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + // precompile the data + var n = plot.series.length; // how many series + var data = []; + for(var i=0; i high){ + var t = high; + high = low; + low = t; + } + var x = plot.axisX.getCoord(low, plotarea, plot); + var w = plot.axisX.getCoord(high, plotarea, plot) - x; + var y = yStart + (barH*j); + + var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect"); + bar.setAttribute("fill", data[j][i].series.color); + bar.setAttribute("stroke-width", "0"); + bar.setAttribute("x", x); + bar.setAttribute("y", y); + bar.setAttribute("width", w); + bar.setAttribute("height", barH); + bar.setAttribute("fill-opacity", "0.6"); + if(applyTo){ applyTo(bar, data[j][i].src); } + group.appendChild(bar); + } + } + return group; // SVGGElement + }, + StackedArea: function( + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* object? */kwArgs, + /* function? */applyTo + ){ + // summary + // Plots a set of stacked areas. + // Bindings: x/y + var area = plotarea.getArea(); + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + // precompile the data + var n = plot.series.length; // how many series + var data = []; + var totals = []; + + // we're assuming that all series for this plot has the name x assignment for now. + for(var i=0; i=0; i--){ + var path = document.createElementNS(dojo.svg.xmlns.svg, "path"); + path.setAttribute("fill", data[i][0].series.color); + path.setAttribute("fill-opacity", "0.4"); + path.setAttribute("stroke", data[i][0].series.color); + path.setAttribute("stroke-width" , "1"); + path.setAttribute("stroke-opacity", "0.85"); + + var cmd = []; + var r=3; + for(var j=0; j=0; j--){ + var x = plot.axisX.getCoord(values[j].x, plotarea, plot); + var y = plot.axisY.getCoord(values[j].y, plotarea, plot); + cmd.push("L"); + cmd.push(x+","+y); + } + } + path.setAttribute("d", cmd.join(" ")+ " Z"); + group.appendChild(path); + } + return group; // SVGGElement + }, + StackedCurvedArea: function( + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* object? */kwArgs, + /* function? */applyTo + ){ + // summary + // Plots a set of stacked areas, using a tensioning factor to soften points. + // Bindings: x/y + var tension = 3; + var area = plotarea.getArea(); + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + // precompile the data + var n = plot.series.length; // how many series + var data = []; + var totals = []; + + // we're assuming that all series for this plot has the name x assignment for now. + for(var i=0; i=0; i--){ + var path = document.createElementNS(dojo.svg.xmlns.svg, "path"); + path.setAttribute("fill", data[i][0].series.color); + path.setAttribute("fill-opacity", "0.4"); + path.setAttribute("stroke", data[i][0].series.color); + path.setAttribute("stroke-width" , "1"); + path.setAttribute("stroke-opacity", "0.85"); + + var cmd = []; + var r=3; + for(var j=0; j0){ + dx = x - plot.axisX.getCoord(values[j-1].x, plotarea, plot); + dy = plot.axisY.getCoord(values[j-1].y, plotarea, plot); + } + + if(j==0){ cmd.push("M"); } + else { + cmd.push("C"); + var cx = x-(tension-1) * (dx/tension); + cmd.push(cx + "," + dy); + cx = x - (dx/tension); + cmd.push(cx + "," + y); + } + cmd.push(x+","+y); + + // points on the line + var c=document.createElementNS(dojo.svg.xmlns.svg, "circle"); + c.setAttribute("cx",x); + c.setAttribute("cy",y); + c.setAttribute("r","3"); + c.setAttribute("fill", values[j].series.color); + c.setAttribute("fill-opacity", "0.6"); + c.setAttribute("stroke-width", "1"); + c.setAttribute("stroke-opacity", "0.85"); + group.appendChild(c); + if(applyTo){ applyTo(c, data[i].src); } + } + + // now run the path backwards from the previous series. + if(i == 0){ + cmd.push("L"); + cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)); + cmd.push("L"); + cmd.push(plot.axisX.getCoord(data[0][0].x, plotarea, plot) + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)); + cmd.push("Z"); + } else { + var values = data[i-1]; + cmd.push("L"); + cmd.push(x + "," + Math.round(plot.axisY.getCoord(values[values.length-1].y, plotarea, plot))); + for(var j=values.length-2; j>=0; j--){ + var x = plot.axisX.getCoord(values[j].x, plotarea, plot); + var y = plot.axisY.getCoord(values[j].y, plotarea, plot); + var dx = x - plot.axisX.getCoord(values[j+1].x, plotarea, plot); + var dy = plot.axisY.getCoord(values[j+1].y, plotarea, plot); + + cmd.push("C"); + var cx = x-(tension-1) * (dx/tension); + cmd.push(cx + "," + dy); + cx = x - (dx/tension); + cmd.push(cx + "," + y); + cmd.push(x+","+y); + } + } + path.setAttribute("d", cmd.join(" ")+ " Z"); + group.appendChild(path); + } + return group; // SVGGElement + }, + + /********************************************************* + * Single plotters: one series at a time. + *********************************************************/ + DataBar: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots a set of bars in relation to y==0. + // Bindings: x/y + var area = plotarea.getArea(); + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + var n = data.length; + var w = (area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower); // the width of each group. + var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot); + + for(var i=0; i0){ + dx = x - plot.axisX.getCoord(data[i-1].x, plotarea, plot); + dy = plot.axisY.getCoord(data[i-1].y, plotarea, plot); + } + + if(i==0){ cmd.push("M"); } + else { + cmd.push("C"); + var cx = x-(tension-1) * (dx/tension); + cmd.push(cx + "," + dy); + cx = x - (dx/tension); + cmd.push(cx + "," + y); + } + cmd.push(x+","+y); + + // points on the line + var c=document.createElementNS(dojo.svg.xmlns.svg, "circle"); + c.setAttribute("cx",x); + c.setAttribute("cy",y); + c.setAttribute("r","3"); + c.setAttribute("fill", data[i].series.color); + c.setAttribute("fill-opacity", "0.6"); + c.setAttribute("stroke-width", "1"); + c.setAttribute("stroke-opacity", "0.85"); + line.appendChild(c); + if(applyTo){ applyTo(c, data[i].src); } + } + path.setAttribute("d", cmd.join(" ")); + return line; // SVGGElement + }, + Area: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as an area. + // Bindings: x/y + var area = plotarea.getArea(); + var line = document.createElementNS(dojo.svg.xmlns.svg, "g"); + var path = document.createElementNS(dojo.svg.xmlns.svg, "path"); + line.appendChild(path); + + path.setAttribute("fill", data[0].series.color); + path.setAttribute("fill-opacity", "0.4"); + path.setAttribute("stroke", data[0].series.color); + path.setAttribute("stroke-width" , "1"); + path.setAttribute("stroke-opacity", "0.85"); + if(data[0].series.label != null){ + path.setAttribute("title", data[0].series.label); + } + + var cmd=[]; + for(var i=0; i0){ + dx = x - plot.axisX.getCoord(data[i-1].x, plotarea, plot); + dy = plot.axisY.getCoord(data[i-1].y, plotarea, plot); + } + + if(i==0){ cmd.push("M"); } + else { + cmd.push("C"); + var cx = x-(tension-1) * (dx/tension); + cmd.push(cx + "," + dy); + cx = x - (dx/tension); + cmd.push(cx + "," + y); + } + cmd.push(x+","+y); + + // points on the line + var c=document.createElementNS(dojo.svg.xmlns.svg, "circle"); + c.setAttribute("cx",x); + c.setAttribute("cy",y); + c.setAttribute("r","3"); + c.setAttribute("fill", data[i].series.color); + c.setAttribute("fill-opacity", "0.6"); + c.setAttribute("stroke-width", "1"); + c.setAttribute("stroke-opacity", "0.85"); + line.appendChild(c); + if(applyTo){ applyTo(c, data[i].src); } + } + // finish it off + cmd.push("L"); + cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)); + cmd.push("L"); + cmd.push(plot.axisX.getCoord(data[0].x, plotarea, plot) + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)); + cmd.push("Z"); + path.setAttribute("d", cmd.join(" ")); + return line; // SVGGElement + }, + HighLow: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as a set of high/low bars. + // Bindings: x/high/low + var area = plotarea.getArea(); + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + var n = data.length; + var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4; + var w = part*2; + + for(var i=0; i high){ + var t = low; + low = high; + high = t; + } + + var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2); + var y = plot.axisY.getCoord(high, plotarea, plot); + var h = plot.axisY.getCoord(low, plotarea, plot)-y; + + // high + low + var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect"); + bar.setAttribute("fill", data[i].series.color); + bar.setAttribute("stroke-width", "0"); + bar.setAttribute("x", x); + bar.setAttribute("y", y); + bar.setAttribute("width", w); + bar.setAttribute("height", h); + bar.setAttribute("fill-opacity", "0.6"); + if(applyTo){ applyTo(bar, data[i].src); } + group.appendChild(bar); + } + return group; // SVGGElement + }, + HighLowClose: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as a set of high/low bars with a close indicator. + // Bindings: x/high/low/close + var area = plotarea.getArea(); + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + var n = data.length; + var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4; + var w = part*2; + + for(var i=0; i high){ + var t = low; + low = high; + high = t; + } + var c = data[i].close; + + var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2); + var y = plot.axisY.getCoord(high, plotarea, plot); + var h = plot.axisY.getCoord(low, plotarea, plot)-y; + var close = plot.axisY.getCoord(c, plotarea, plot); + + var g = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + // high + low + var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect"); + bar.setAttribute("fill", data[i].series.color); + bar.setAttribute("stroke-width", "0"); + bar.setAttribute("x", x); + bar.setAttribute("y", y); + bar.setAttribute("width", w); + bar.setAttribute("height", h); + bar.setAttribute("fill-opacity", "0.6"); + g.appendChild(bar); + + // close + var line=document.createElementNS(dojo.svg.xmlns.svg, "line"); + line.setAttribute("x1", x); + line.setAttribute("x2", x+w+(part*2)); + line.setAttribute("y1", close); + line.setAttribute("y2", close); + line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;"); + g.appendChild(line); + + if(applyTo){ applyTo(g, data[i].src); } + group.appendChild(g); + } + return group; // SVGGElement + }, + HighLowOpenClose: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as a set of high/low bars with open and close indicators. + // Bindings: x/high/low/open/close + var area = plotarea.getArea(); + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + var n = data.length; + var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4; + var w = part*2; + + for(var i=0; i high){ + var t = low; + low = high; + high = t; + } + var o = data[i].open; + var c = data[i].close; + + var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2); + var y = plot.axisY.getCoord(high, plotarea, plot); + var h = plot.axisY.getCoord(low, plotarea, plot)-y; + var open = plot.axisY.getCoord(o, plotarea, plot); + var close = plot.axisY.getCoord(c, plotarea, plot); + + var g = document.createElementNS(dojo.svg.xmlns.svg, "g"); + + // high + low + var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect"); + bar.setAttribute("fill", data[i].series.color); + bar.setAttribute("stroke-width", "0"); + bar.setAttribute("x", x); + bar.setAttribute("y", y); + bar.setAttribute("width", w); + bar.setAttribute("height", h); + bar.setAttribute("fill-opacity", "0.6"); + g.appendChild(bar); + + // open + var line=document.createElementNS(dojo.svg.xmlns.svg, "line"); + line.setAttribute("x1", x-(part*2)); + line.setAttribute("x2", x+w); + line.setAttribute("y1", open); + line.setAttribute("y2", open); + line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;"); + g.appendChild(line); + + // close + var line=document.createElementNS(dojo.svg.xmlns.svg, "line"); + line.setAttribute("x1", x); + line.setAttribute("x2", x+w+(part*2)); + line.setAttribute("y1", close); + line.setAttribute("y2", close); + line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;"); + g.appendChild(line); + + if(applyTo){ applyTo(g, data[i].src); } + group.appendChild(g); + } + return group; // SVGGElement + }, + Scatter: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as a set of points. + // Bindings: x/y + var r=7; + var group = document.createElementNS(dojo.svg.xmlns.svg, "g"); + for (var i=0; i 0){ + this.nodes.lines.removeChild(this.nodes.lines.childNodes[0]); + } + if(this.nodes.lines.parentNode){ + this.nodes.lines.parentNode.removeChild(this.nodes.lines); + this.nodes.lines = null; + } + } + + var area = plotArea.getArea(); + var g = this.nodes.lines = document.createElement("div"); + g.setAttribute("id", this.getId()+"-lines"); + for(var i=0; i 0){ + this.nodes.ticks.removeChild(this.nodes.ticks.childNodes[0]); + } + if(this.nodes.ticks.parentNode){ + this.nodes.ticks.parentNode.removeChild(this.nodes.ticks); + this.nodes.ticks = null; + } + } + + var g = this.nodes.ticks = document.createElement("div"); + g.setAttribute("id", this.getId()+"-ticks"); + for(var i=0; i 0){ + this.nodes.labels.removeChild(this.nodes.labels.childNodes[0]); + } + if(this.nodes.labels.parentNode){ + this.nodes.labels.parentNode.removeChild(this.nodes.labels); + this.nodes.labels = null; + } + } + var g = this.nodes.labels = document.createElement("div"); + g.setAttribute("id", this.getId()+"-labels"); + + for(var i=0; i 0){ + x = xOrigin; + } + + var bar=document.createElement("v:rect"); + bar.style.position="absolute"; + bar.style.top=y+1+"px"; + bar.style.left=xA+"px"; + bar.style.width=w+"px"; + bar.style.height=barH+"px"; + bar.setAttribute("fillColor", data[j][i].series.color); + bar.setAttribute("stroked", "false"); + bar.style.antialias="false"; + var fill=document.createElement("v:fill"); + fill.setAttribute("opacity", "0.6"); + bar.appendChild(fill); + if(applyTo){ applyTo(bar, data[j][i].src); } + group.appendChild(bar); + } + } + + // calculate the width of each bar. + var space = 4; + var n = plot.series.length; + var h = ((area.bottom-area.top)-(space*(n-1)))/n; + var xOrigin = plot.axisX.getCoord(0, plotarea, plot); + for(var i=0; i 0){ + xA = x; + x = xOrigin; + } + + } + return group; // HTMLDivElement + }, + Gantt: function( + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* object? */kwArgs, + /* function? */applyTo + ){ + // summary + // Plots a grouped set of Gantt bars + // Bindings: high/low + var area = plotarea.getArea(); + var group = dojo.charting.Plotters._group(plotarea); + + // precompile the data + var n = plot.series.length; // how many series + var data = []; + for(var i=0; i high){ + var t = high; + high = low; + low = t; + } + var x = plot.axisX.getCoord(low, plotarea, plot); + var w = plot.axisX.getCoord(high, plotarea, plot) - x; + var y = yStart + (barH*j); + + var bar=document.createElement("v:rect"); + bar.style.position="absolute"; + bar.style.top=y+1+"px"; + bar.style.left=x+"px"; + bar.style.width=w+"px"; + bar.style.height=barH+"px"; + bar.setAttribute("fillColor", data[j][i].series.color); + bar.setAttribute("stroked", "false"); + bar.style.antialias="false"; + var fill=document.createElement("v:fill"); + fill.setAttribute("opacity", "0.6"); + bar.appendChild(fill); + if(applyTo){ applyTo(bar, data[j][i].src); } + group.appendChild(bar); + } + } + return group; // HTMLDivElement + }, + StackedArea: function( + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* object? */kwArgs, + /* function? */applyTo + ){ + // summary + // Plots a set of stacked areas. + // Bindings: x/y + var area = plotarea.getArea(); + var group = dojo.charting.Plotters._group(plotarea); + + // precompile the data + var n = plot.series.length; // how many series + var data = []; + var totals = []; + + // we're assuming that all series for this plot has the name x assignment for now. + for(var i=0; i=0; i--){ + var path=document.createElement("v:shape"); + path.setAttribute("strokeweight", "1px"); + path.setAttribute("strokecolor", data[i][0].series.color); + path.setAttribute("fillcolor", data[i][0].series.color); + path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top)); + path.style.position="absolute"; + path.style.top="0px"; + path.style.left="0px"; + path.style.width=area.right-area.left+"px"; + path.style.height=area.bottom-area.top+"px"; + var stroke=document.createElement("v:stroke"); + stroke.setAttribute("opacity", "0.8"); + path.appendChild(stroke); + var fill=document.createElement("v:fill"); + fill.setAttribute("opacity", "0.4"); + path.appendChild(fill); + + var cmd = []; + var r=3; + for(var j=0; j=0; j--){ + var x = Math.round(plot.axisX.getCoord(values[j].x, plotarea, plot)); + var y = Math.round(plot.axisY.getCoord(values[j].y, plotarea, plot)); + + cmd.push("l"); + cmd.push(x+","+y); + } + } + path.setAttribute("path", cmd.join(" ")+" x e"); + group.appendChild(path); + } + return group; // HTMLDivElement + }, + StackedCurvedArea: function( + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* object? */kwArgs, + /* function? */applyTo + ){ + // summary + // Plots a set of stacked areas, using a tensioning factor to soften points. + // Bindings: x/y + var tension = 3; + var area = plotarea.getArea(); + var group = dojo.charting.Plotters._group(plotarea); + + // precompile the data + var n = plot.series.length; // how many series + var data = []; + var totals = []; + + // we're assuming that all series for this plot has the name x assignment for now. + for(var i=0; i=0; i--){ + var path=document.createElement("v:shape"); + path.setAttribute("strokeweight", "1px"); + path.setAttribute("strokecolor", data[i][0].series.color); + path.setAttribute("fillcolor", data[i][0].series.color); + path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top)); + path.style.position="absolute"; + path.style.top="0px"; + path.style.left="0px"; + path.style.width=area.right-area.left+"px"; + path.style.height=area.bottom-area.top+"px"; + var stroke=document.createElement("v:stroke"); + stroke.setAttribute("opacity", "0.8"); + path.appendChild(stroke); + var fill=document.createElement("v:fill"); + fill.setAttribute("opacity", "0.4"); + path.appendChild(fill); + + var cmd = []; + var r=3; + for(var j=0; j=0; j--){ + var x = Math.round(plot.axisX.getCoord(values[j].x, plotarea, plot)); + var y = Math.round(plot.axisY.getCoord(values[j].y, plotarea, plot)); + + var lastx = Math.round(plot.axisX.getCoord(values[j+1].x, plotarea, plot)); + var lasty = Math.round(plot.axisY.getCoord(values[j+1].y, plotarea, plot)); + var dx=x-lastx; + var dy=y-lasty; + + cmd.push("c"); + var cx=Math.round((x-(tension-1)*(dx/tension))); + cmd.push(cx+","+lasty); + cx=Math.round((x-(dx/tension))); + cmd.push(cx+","+y); + cmd.push(x+","+y); + } + } + path.setAttribute("path", cmd.join(" ")+" x e"); + group.appendChild(path); + } + return group; // HTMLDivElement + }, + + /********************************************************* + * Single plotters: one series at a time. + *********************************************************/ + DataBar: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots a set of bars in relation to y==0. + // Bindings: x/y + var area = plotarea.getArea(); + var group = dojo.charting.Plotters._group(plotarea); + + var n = data.length; + var w = (area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower); // the width of each group. + var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot); + + for(var i=0; i high){ + var t = low; + low = high; + high = t; + } + + var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2); + var y = plot.axisY.getCoord(high, plotarea, plot); + var h = plot.axisY.getCoord(low, plotarea, plot)-y; + + // high + low + var bar=document.createElement("v:rect"); + bar.style.position="absolute"; + bar.style.top=y+1+"px"; + bar.style.left=x+"px"; + bar.style.width=w+"px"; + bar.style.height=h+"px"; + bar.setAttribute("fillColor", data[i].series.color); + bar.setAttribute("stroked", "false"); + bar.style.antialias="false"; + var fill=document.createElement("v:fill"); + fill.setAttribute("opacity", "0.6"); + bar.appendChild(fill); + if(applyTo){ applyTo(bar, data[i].src); } + group.appendChild(bar); + } + return group; // HTMLDivElement + }, + HighLowClose: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as a set of high/low bars with a close indicator. + // Bindings: x/high/low/close + var area = plotarea.getArea(); + var group = dojo.charting.Plotters._group(plotarea); + + var n = data.length; + var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4; + var w = part*2; + + for(var i=0; i high){ + var t = low; + low = high; + high = t; + } + var c = data[i].close; + + var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2); + var y = plot.axisY.getCoord(high, plotarea, plot); + var h = plot.axisY.getCoord(low, plotarea, plot)-y; + var close = plot.axisY.getCoord(c, plotarea, plot); + + var g = document.createElement("div"); + + // high + low + var bar=document.createElement("v:rect"); + bar.style.position="absolute"; + bar.style.top=y+1+"px"; + bar.style.left=x+"px"; + bar.style.width=w+"px"; + bar.style.height=h+"px"; + bar.setAttribute("fillColor", data[i].series.color); + bar.setAttribute("stroked", "false"); + bar.style.antialias="false"; + var fill=document.createElement("v:fill"); + fill.setAttribute("opacity", "0.6"); + bar.appendChild(fill); + g.appendChild(bar); + + var line = document.createElement("v:line"); + line.setAttribute("strokecolor", data[i].series.color); + line.setAttribute("strokeweight", "1px"); + line.setAttribute("from", x+"px,"+close+"px"); + line.setAttribute("to", (x+w+(part*2)-2)+"px,"+close+"px"); + var s=line.style; + s.position="absolute"; + s.top="0px"; + s.left="0px"; + s.antialias="false"; + var str=document.createElement("v:stroke"); + str.setAttribute("opacity","0.6"); + line.appendChild(str); + g.appendChild(line); + + if(applyTo){ applyTo(g, data[i].src); } + group.appendChild(g); + } + return group; // HTMLDivElement + }, + HighLowOpenClose: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as a set of high/low bars with open and close indicators. + // Bindings: x/high/low/open/close + var area = plotarea.getArea(); + var group = dojo.charting.Plotters._group(plotarea); + + var n = data.length; + var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4; + var w = part*2; + + for(var i=0; i high){ + var t = low; + low = high; + high = t; + } + var o = data[i].open; + var c = data[i].close; + + var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2); + var y = plot.axisY.getCoord(high, plotarea, plot); + var h = plot.axisY.getCoord(low, plotarea, plot)-y; + var open = plot.axisY.getCoord(o, plotarea, plot); + var close = plot.axisY.getCoord(c, plotarea, plot); + + var g = document.createElement("div"); + + // high + low + var bar=document.createElement("v:rect"); + bar.style.position="absolute"; + bar.style.top=y+1+"px"; + bar.style.left=x+"px"; + bar.style.width=w+"px"; + bar.style.height=h+"px"; + bar.setAttribute("fillColor", data[i].series.color); + bar.setAttribute("stroked", "false"); + bar.style.antialias="false"; + var fill=document.createElement("v:fill"); + fill.setAttribute("opacity", "0.6"); + bar.appendChild(fill); + g.appendChild(bar); + + var line = document.createElement("v:line"); + line.setAttribute("strokecolor", data[i].series.color); + line.setAttribute("strokeweight", "1px"); + line.setAttribute("from", (x-(part*2))+"px,"+open+"px"); + line.setAttribute("to", (x+w-2)+"px,"+open+"px"); + var s=line.style; + s.position="absolute"; + s.top="0px"; + s.left="0px"; + s.antialias="false"; + var str=document.createElement("v:stroke"); + str.setAttribute("opacity","0.6"); + line.appendChild(str); + g.appendChild(line); + + var line = document.createElement("v:line"); + line.setAttribute("strokecolor", data[i].series.color); + line.setAttribute("strokeweight", "1px"); + line.setAttribute("from", x+"px,"+close+"px"); + line.setAttribute("to", (x+w+(part*2)-2)+"px,"+close+"px"); + var s=line.style; + s.position="absolute"; + s.top="0px"; + s.left="0px"; + s.antialias="false"; + var str=document.createElement("v:stroke"); + str.setAttribute("opacity","0.6"); + line.appendChild(str); + g.appendChild(line); + + if(applyTo){ applyTo(g, data[i].src); } + group.appendChild(g); + } + return group; // HTMLDivElement + }, + Scatter: function( + /* array */data, + /* dojo.charting.PlotArea */plotarea, + /* dojo.charting.Plot */plot, + /* function? */applyTo + ){ + // summary + // Plots the series as a set of points. + // Bindings: x/y + var r=6; + var mod=r/2; + + var area = plotarea.getArea(); + var group = dojo.charting.Plotters._group(plotarea); + + for(var i=0; i=0) { + items.splice(i,1); + } + this.count=items.length; + }; + this.removeAt=function(/* int */ i){ + // summary + // return an array with function applied to all elements + items.splice(i,1); + this.count=items.length; + }; + this.reverse=function(){ + // summary + // Reverse the internal array + items.reverse(); + }; + this.sort=function(/* function? */ fn){ + // summary + // sort the internal array + if(fn){ + items.sort(fn); + }else{ + items.sort(); + } + }; + this.setByIndex=function(/* int */ i, /* object */ obj){ + // summary + // Set an element in the array by the passed index. + items[i]=obj; + this.count=items.length; + }; + this.toArray=function(){ + // summary + // Return a new array with all of the items of the internal array concatenated. + return [].concat(items); + } + this.toString=function(/* string */ delim){ + // summary + // implementation of toString, follows [].toString(); + return items.join((delim||",")); + }; +}; diff --git a/source/web/scripts/ajax/dojo/src/collections/BinaryTree.js b/source/web/scripts/ajax/dojo/src/collections/BinaryTree.js new file mode 100644 index 0000000000..445e1059b1 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/collections/BinaryTree.js @@ -0,0 +1,203 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.collections.BinaryTree"); +dojo.require("dojo.collections.Collections"); +dojo.require("dojo.experimental"); + +dojo.experimental("dojo.collections.BinaryTree"); + +dojo.collections.BinaryTree=function(data){ + function node(data, rnode, lnode){ + this.value=data||null; + this.right=rnode||null; + this.left=lnode||null; + this.clone=function(){ + var c=new node(); + if (this.value.value) c.value=this.value.clone(); + else c.value=this.value; + if (this.left) c.left=this.left.clone(); + if (this.right) c.right=this.right.clone(); + } + this.compare=function(n){ + if (this.value > n.value) return 1; + if (this.value < n.value) return -1; + return 0; + } + this.compareData=function(d){ + if (this.value > d) return 1; + if (this.value < d) return -1; + return 0; + } + } + + function inorderTraversalBuildup(current, a){ + if (current){ + inorderTraversalBuildup(current.left, a); + a.add(current); + inorderTraversalBuildup(current.right, a); + } + } + + function preorderTraversal(current, sep){ + var s=""; + if (current){ + s=current.value.toString() + sep; + s += preorderTraversal(current.left, sep); + s += preorderTraversal(current.right, sep); + } + return s; + } + function inorderTraversal(current, sep){ + var s=""; + if (current){ + s=inorderTraversal(current.left, sep); + s += current.value.toString() + sep; + s += inorderTraversal(current.right, sep); + } + return s; + } + function postorderTraversal(current, sep){ + var s=""; + if (current){ + s=postorderTraversal(current.left, sep); + s += postorderTraversal(current.right, sep); + s += current.value.toString() + sep; + } + return s; + } + + function searchHelper(current, data){ + if (!current) return null; + var i=current.compareData(data); + if (i==0) return current; + if (i>0) return searchHelper(current.left, data); + else return searchHelper(current.right, data); + } + + this.add=function(data){ + var n=new node(data); + var i; + var current=root; + var parent=null; + while (current){ + i=current.compare(n); + if (i == 0) return; + parent=current; + if (i > 0) current=current.left; + else current=current.right; + } + this.count++; + if (!parent) root=n; + else { + i=parent.compare(n); + if (i > 0) parent.left=n; + else parent.right=n; + } + }; + this.clear=function(){ + root=null; + this.count=0; + }; + this.clone=function(){ + var c=new dojo.collections.BinaryTree(); + c.root=root.clone(); + c.count=this.count; + return c; + }; + this.contains=function(data){ + return this.search(data) != null; + }; + this.deleteData=function(data){ + var current=root; + var parent=null; + var i=current.compareData(data); + while (i != 0 && current != null){ + if (i > 0){ + parent=current; + current=current.left; + } else if (i < 0) { + parent=current; + current=current.right; + } + i=current.compareData(data); + } + if (!current) return; + this.count--; + if (!current.right) { + if (!parent) root=current.left; + else { + i=parent.compare(current); + if (i > 0) parent.left=current.left; + else if (i < 0) parent.right=current.left; + } + } else if (!current.right.left){ + if (!parent) root=current.right; + else { + i=parent.compare(current); + if (i > 0) parent.left=current.right; + else if (i < 0) parent.right=current.right; + } + } else { + var leftmost=current.right.left; + var lmParent=current.right; + while (leftmost.left != null){ + lmParent=leftmost; + leftmost=leftmost.left; + } + lmParent.left=leftmost.right; + leftmost.left=current.left; + leftmost.right=current.right; + if (!parent) root=leftmost; + else { + i=parent.compare(current); + if (i > 0) parent.left=leftmost; + else if (i < 0) parent.right=leftmost; + } + } + }; + this.getIterator=function(){ + var a=[]; + inorderTraversalBuildup(root, a); + return new dojo.collections.Iterator(a); + }; + this.search=function(data){ + return searchHelper(root, data); + }; + this.toString=function(order, sep){ + if (!order) var order=dojo.collections.BinaryTree.TraversalMethods.Inorder; + if (!sep) var sep=" "; + var s=""; + switch (order){ + case dojo.collections.BinaryTree.TraversalMethods.Preorder: + s=preorderTraversal(root, sep); + break; + case dojo.collections.BinaryTree.TraversalMethods.Inorder: + s=inorderTraversal(root, sep); + break; + case dojo.collections.BinaryTree.TraversalMethods.Postorder: + s=postorderTraversal(root, sep); + break; + }; + if (s.length == 0) return ""; + else return s.substring(0, s.length - sep.length); + }; + + this.count=0; + var root=this.root=null; + if (data) { + this.add(data); + } +} +dojo.collections.BinaryTree.TraversalMethods={ + Preorder : 1, + Inorder : 2, + Postorder : 3 +}; diff --git a/source/web/scripts/ajax/dojo/src/collections/Collections.js b/source/web/scripts/ajax/dojo/src/collections/Collections.js new file mode 100644 index 0000000000..6c1cf628fb --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/collections/Collections.js @@ -0,0 +1,124 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.collections.Collections"); + +dojo.collections.DictionaryEntry=function(/* string */k, /* object */v){ + // summary + // return an object of type dojo.collections.DictionaryEntry + this.key=k; + this.value=v; + this.valueOf=function(){ + return this.value; // object + }; + this.toString=function(){ + return String(this.value); // string + }; +} + +/* Iterators + * The collections.Iterators (Iterator and DictionaryIterator) are built to + * work with the Collections included in this module. However, they *can* + * be used with arrays and objects, respectively, should one choose to do so. + */ +dojo.collections.Iterator=function(/* array */arr){ + // summary + // return an object of type dojo.collections.Iterator + var a=arr; + var position=0; + this.element=a[position]||null; + this.atEnd=function(){ + // summary + // Test to see if the internal cursor has reached the end of the internal collection. + return (position>=a.length); // bool + }; + this.get=function(){ + // summary + // Test to see if the internal cursor has reached the end of the internal collection. + if(this.atEnd()){ + return null; // object + } + this.element=a[position++]; + return this.element; // object + }; + this.map=function(/* function */fn, /* object? */scope){ + // summary + // Functional iteration with optional scope. + var s=scope||dj_global; + if(Array.map){ + return Array.map(a,fn,s); // array + }else{ + var arr=[]; + for(var i=0; i=a.length); // bool + }; + this.get=function(){ + // summary + // Test to see if the internal cursor has reached the end of the internal collection. + if(this.atEnd()){ + return null; // object + } + this.element=a[position++]; + return this.element; // object + }; + this.map=function(/* function */fn, /* object? */scope){ + // summary + // Functional iteration with optional scope. + var s=scope||dj_global; + if(Array.map){ + return Array.map(a,fn,s); // array + }else{ + var arr=[]; + for(var i=0; i=o.length); + } + this.get=function(){ + if(this.atEnd()){ + return null; // object + } + this.element=o[position++]; + return this.element; // object + }; + this.map=function(/* function */fn, /* object? */scope){ + var s=scope||dj_global; + if(Array.map){ + return Array.map(o,fn,s); // array + }else{ + var arr=[]; + for(var i=0; i 1){ + n=new node(arguments[0],arguments[1]); + } + if(!this.nodes.containsKey(n.key)){ + this.nodes.add(n); + this.count++; + } + }; + this.addDirectedEdge=function(uKey, vKey, cost){ + var uNode,vNode; + if(uKey.constructor!= node){ + uNode=this.nodes.item(uKey); + vNode=this.nodes.item(vKey); + }else{ + uNode=uKey; + vNode=vKey; + } + var c=cost||0; + uNode.addDirected(vNode,c); + }; + this.addUndirectedEdge=function(uKey, vKey, cost){ + var uNode, vNode; + if(uKey.constructor!=node){ + uNode=this.nodes.item(uKey); + vNode=this.nodes.item(vKey); + }else{ + uNode=uKey; + vNode=vKey; + } + var c=cost||0; + uNode.addDirected(vNode,c); + vNode.addDirected(uNode,c); + }; + this.contains=function(n){ + return this.nodes.containsKey(n.key); + }; + this.containsKey=function(k){ + return this.nodes.containsKey(k); + }; +} diff --git a/source/web/scripts/ajax/dojo/src/collections/Queue.js b/source/web/scripts/ajax/dojo/src/collections/Queue.js new file mode 100644 index 0000000000..739259b13d --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/collections/Queue.js @@ -0,0 +1,87 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.collections.Queue"); +dojo.require("dojo.collections.Collections"); + +dojo.collections.Queue=function(/* array? */arr){ + // summary + // return an object of type dojo.collections.Queue + var q=[]; + if (arr){ + q=q.concat(arr); + } + this.count=q.length; + this.clear=function(){ + // summary + // clears the internal collection + q=[]; + this.count=q.length; + }; + this.clone=function(){ + // summary + // creates a new Queue based on this one + return new dojo.collections.Queue(q); // dojo.collections.Queue + }; + this.contains=function(/* object */ o){ + // summary + // Check to see if the passed object is an element in this queue + for(var i=0; i val) return 1; + if (this.value < val) return -1; + return 0; + } + this.incrementHeight = function(){ + this.nodes.incrementHeight(); + this.height++; + }; + this.decrementHeight = function(){ + this.nodes.decrementHeight(); + this.height--; + }; + } + function nodeList(height){ + var arr = []; + this.height = height; + for (var i = 0; i < height; i++) arr[i] = null; + this.item = function(i){ + return arr[i]; + }; + this.incrementHeight = function(){ + this.height++; + arr[this.height] = null; + }; + this.decrementHeight = function(){ + arr.splice(arr.length - 1, 1); + this.height--; + }; + } + function iterator(list){ + this.element = list.head; + this.atEnd = function(){ + return (this.element==null); + } + this.get = function(){ + if(this.atEnd()){ + return null; + } + this.element=this.element.nodes[0]; + return this.element; + } + this.reset = function(){ + this.element = list.head; + } + } + + function chooseRandomHeight(max){ + var level = 1; + while (Math.random() < PROB && level < max) level++; + return level; + } + + var PROB = 0.5; + var comparisons = 0; + + this.head = new node(1); + this.count = 0; + this.add = function(val){ + var updates = []; + var current = this.head; + for (var i = this.head.height; i >= 0; i--){ + if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) comparisons++; + while (current.nodes[i] != null && current.nodes[i].compare(val) < 0){ + current = current.nodes[i]; + comparisons++; + } + updates[i] = current; + } + if (current.nodes[0] != null && current.nodes[0].compare(val) == 0) return; + var n = new node(val, chooseRandomHeight(this.head.height + 1)); + this.count++; + if (n.height > this.head.height){ + this.head.incrementHeight(); + this.head.nodes[this.head.height - 1] = n; + } + for (i = 0; i < n.height; i++){ + if (i < updates.length) { + n.nodes[i] = updates[i].nodes[i]; + updates[i].nodes[i] = n; + } + } + }; + + this.contains = function(val){ + var current = this.head; + var i; + for (i = this.head.height - 1; i >= 0; i--) { + while (current.item(i) != null) { + comparisons++; + var result = current.nodes[i].compare(val); + if (result == 0) return true; + else if (result < 0) current = current.nodes[i]; + else break; + } + } + return false; + }; + this.getIterator = function(){ + return new iterator(this); + }; + + this.remove = function(val){ + var updates = []; + var current = this.head; + for (var i = this.head.height - 1; i >= 0; i--){ + if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) comparisons++; + while (current.nodes[i] != null && current.nodes[i].compare(val) < 0) { + current = current.nodes[i]; + comparisons++; + } + updates[i] = current; + } + + current = current.nodes[0]; + if (current != null && current.compare(val) == 0){ + this.count--; + for (var i = 0; i < this.head.height; i++){ + if (updates[i].nodes[i] != current) break; + else updates[i].nodes[i] = current.nodes[i]; + } + if (this.head.nodes[this.head.height - 1] == null) this.head.decrementHeight(); + } + }; + this.resetComparisons = function(){ + comparisons = 0; + }; +} diff --git a/source/web/scripts/ajax/dojo/src/collections/SortedList.js b/source/web/scripts/ajax/dojo/src/collections/SortedList.js new file mode 100644 index 0000000000..0ba84da63e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/collections/SortedList.js @@ -0,0 +1,211 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.collections.SortedList"); +dojo.require("dojo.collections.Collections"); + +dojo.collections.SortedList=function(/* object? */ dictionary){ + // summary + // creates a collection that acts like a dictionary but is also internally sorted. + // Note that the act of adding any elements forces an internal resort, making this object potentially slow. + var _this=this; + var items={}; + var q=[]; + var sorter=function(a,b){ + if (a.key > b.key) return 1; + if (a.key < b.key) return -1; + return 0; + }; + var build=function(){ + q=[]; + var e=_this.getIterator(); + while (!e.atEnd()){ + q.push(e.get()); + } + q.sort(sorter); + }; + var testObject={}; + + this.count=q.length; + this.add=function(/* string */ k,/* object */v){ + // summary + // add the passed value to the dictionary at location k + if (!items[k]) { + items[k]=new dojo.collections.DictionaryEntry(k,v); + this.count=q.push(items[k]); + q.sort(sorter); + } + }; + this.clear=function(){ + // summary + // clear the internal collections + items={}; + q=[]; + this.count=q.length; + }; + this.clone=function(){ + // summary + // create a clone of this sorted list + return new dojo.collections.SortedList(this); // dojo.collections.SortedList + }; + this.contains=this.containsKey=function(/* string */ k){ + // summary + // Check to see if the list has a location k + if(testObject[k]){ + return false; // bool + } + return (items[k]!=null); // bool + }; + this.containsValue=function(/* object */ o){ + // summary + // Check to see if this list contains the passed object + var e=this.getIterator(); + while (!e.atEnd()){ + var item=e.get(); + if(item.value==o){ + return true; // bool + } + } + return false; // bool + }; + this.copyTo=function(/* array */ arr, /* int */ i){ + // summary + // copy the contents of the list into array arr at index i + var e=this.getIterator(); + var idx=i; + while(!e.atEnd()){ + arr.splice(idx,0,e.get()); + idx++; + } + }; + this.entry=function(/* string */ k){ + // summary + // return the object at location k + return items[k]; // dojo.collections.DictionaryEntry + }; + this.forEach=function(/* function */ fn, /* object? */ scope){ + // summary + // functional iterator, following the mozilla spec. + var s=scope||dj_global; + if(Array.forEach){ + Array.forEach(q, fn, s); + }else{ + for(var i=0; i1) { + field = parts.pop(); + do{ + if(parts[i].indexOf("()")>-1){ + var temp=parts[i++].split("()")[0]; + if(!o[temp]){ + dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + temp + "' is not a property of the passed object."); + } else { + // this *will* throw an error if the method in question can't be invoked without arguments. + o = o[temp](); + } + } else { + o = o[parts[i++]]; + } + } while (i-1){ + data.splice(idx,1); + } + }; + this.removeDataByKey = function(/*string*/key){ + // summary + // remove the object at key from the internal data array. + this.removeData(this.getDataByKey(key)); + }; + this.removeDataByIndex = function(/*number*/idx){ + // summary + // remove the object at idx from the internal data array. + this.removeData(this.getDataByIndex(idx)); + }; + + if(jsonArray && jsonArray.length && jsonArray[0]){ + this.setData(jsonArray); + } +}; + +dojo.extend(dojo.collections.Store, { + getField:function(/*object*/obj, /*string*/field){ + // helper to get the nested value if needed. + var parts=field.split("."), i=0, o=obj; + do{ + if(parts[i].indexOf("()")>-1){ + var temp=parts[i++].split("()")[0]; + if(!o[temp]){ + dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + temp + "' is not a property of the passed object."); + } else { + // this *will* throw an error if the method in question can't be invoked without arguments. + o = o[temp](); + } + } else { + o = o[parts[i++]]; + } + } while (i -1){ + p = p.split("."); + while(p.length>1){ + var pr = p.shift(); + o[pr] = {}; + o = o[pr]; + } + p = p[0]; + } + + var type = meta[i].getType(); + if(type == String){ + o[p] = data; + } else { + if(data){ + o[p] = new type(data); + } else { + o[p] = new type(); + } + } + } + return obj; + }; + + // we have initialization data, let's parse it. + var arr=[]; + for(var i=0; i>16)^0xffff))+(((sum&0xffff)^0xffff)+1); + } + return sum; + } + function split(x){ + var r=x&0xffffffff; + if(r<0) { + r=-r; + return [((r&0xffff)^0xffff)+1,(r>>16)^0xffff]; + } + return [r&0xffff,(r>>16)]; + } + function xor(x,y){ + var xs=split(x); + var ys=split(y); + return (0x10000*(xs[1]^ys[1]))+(xs[0]^ys[0]); + } + function $(v, box){ + var d=v&0xff; v>>=8; + var c=v&0xff; v>>=8; + var b=v&0xff; v>>=8; + var a=v&0xff; + var r=add(box.s0[a],box.s1[b]); + r=xor(r,box.s2[c]); + return add(r,box.s3[d]); + } +//////////////////////////////////////////////////////////////////////////// + function eb(o, box){ + var l=o.left; + var r=o.right; + l=xor(l,box.p[0]); + r=xor(r,xor($(l,box),box.p[1])); + l=xor(l,xor($(r,box),box.p[2])); + r=xor(r,xor($(l,box),box.p[3])); + l=xor(l,xor($(r,box),box.p[4])); + r=xor(r,xor($(l,box),box.p[5])); + l=xor(l,xor($(r,box),box.p[6])); + r=xor(r,xor($(l,box),box.p[7])); + l=xor(l,xor($(r,box),box.p[8])); + r=xor(r,xor($(l,box),box.p[9])); + l=xor(l,xor($(r,box),box.p[10])); + r=xor(r,xor($(l,box),box.p[11])); + l=xor(l,xor($(r,box),box.p[12])); + r=xor(r,xor($(l,box),box.p[13])); + l=xor(l,xor($(r,box),box.p[14])); + r=xor(r,xor($(l,box),box.p[15])); + l=xor(l,xor($(r,box),box.p[16])); + o.right=l; + o.left=xor(r,box.p[17]); + } + + function db(o, box){ + var l=o.left; + var r=o.right; + l=xor(l,box.p[17]); + r=xor(r,xor($(l,box),box.p[16])); + l=xor(l,xor($(r,box),box.p[15])); + r=xor(r,xor($(l,box),box.p[14])); + l=xor(l,xor($(r,box),box.p[13])); + r=xor(r,xor($(l,box),box.p[12])); + l=xor(l,xor($(r,box),box.p[11])); + r=xor(r,xor($(l,box),box.p[10])); + l=xor(l,xor($(r,box),box.p[9])); + r=xor(r,xor($(l,box),box.p[8])); + l=xor(l,xor($(r,box),box.p[7])); + r=xor(r,xor($(l,box),box.p[6])); + l=xor(l,xor($(r,box),box.p[5])); + r=xor(r,xor($(l,box),box.p[4])); + l=xor(l,xor($(r,box),box.p[3])); + r=xor(r,xor($(l,box),box.p[2])); + l=xor(l,xor($(r,box),box.p[1])); + o.right=l; + o.left=xor(r,box.p[0]); + } + + // Note that we aren't caching contexts here; it might take a little longer + // but we should be more secure this way. + function init(key){ + var k=key; + if (typeof(k)=="string"){ + var a=[]; + for(var i=0; i>>18)&0x3f)); + s.push(tab.charAt((t>>>12)&0x3f)); + s.push(tab.charAt((t>>>6)&0x3f)); + s.push(tab.charAt(t&0x3f)); + } + // deal with trailers, based on patch from Peter Wood. + switch(rm){ + case 2:{ + var t=ba[i++]<<16|ba[i++]<<8; + s.push(tab.charAt((t>>>18)&0x3f)); + s.push(tab.charAt((t>>>12)&0x3f)); + s.push(tab.charAt((t>>>6)&0x3f)); + s.push(p); + break; + } + case 1:{ + var t=ba[i++]<<16; + s.push(tab.charAt((t>>>18)&0x3f)); + s.push(tab.charAt((t>>>12)&0x3f)); + s.push(p); + s.push(p); + break; + } + } + return s.join(""); + } + function fromBase64(str){ + var s=str.split(""); + var p="="; + var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var out=[]; + var l=s.length; + while(s[--l]==p){ } + for (var i=0; i>>16)&0xff); + out.push((t>>>8)&0xff); + out.push(t&0xff); + } + return out; + } +//////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +// 0.2: Only supporting ECB mode for now. +//////////////////////////////////////////////////////////////////////////// + this.getIV=function(/* dojo.crypto.outputTypes? */ outputType){ + // summary + // returns the initialization vector in the output format specified by outputType + var out=outputType||dojo.crypto.outputTypes.Base64; + switch(out){ + case dojo.crypto.outputTypes.Hex:{ + var s=[]; + for(var i=0; i> 3; + var pos=0; + var o={}; + var isCBC=(mode==dojo.crypto.cipherModes.CBC); + var vector={left:iv.left||null, right:iv.right||null}; + for(var i=0; i>24)&0xff); + cipher.push((o.left>>16)&0xff); + cipher.push((o.left>>8)&0xff); + cipher.push(o.left&0xff); + cipher.push((o.right>>24)&0xff); + cipher.push((o.right>>16)&0xff); + cipher.push((o.right>>8)&0xff); + cipher.push(o.right&0xff); + pos+=8; + } + switch(out){ + case dojo.crypto.outputTypes.Hex:{ + var s=[]; + for(var i=0; i> 3; + var pos=0; + var o={}; + var isCBC=(mode==dojo.crypto.cipherModes.CBC); + var vector={left:iv.left||null, right:iv.right||null}; + for(var i=0; i>24)&0xff); + pt.push((o.left>>16)&0xff); + pt.push((o.left>>8)&0xff); + pt.push(o.left&0xff); + pt.push((o.right>>24)&0xff); + pt.push((o.right>>16)&0xff); + pt.push((o.right>>8)&0xff); + pt.push(o.right&0xff); + pos+=8; + } + + // check for padding, and remove. + if(pt[pt.length-1]==pt[pt.length-2]||pt[pt.length-1]==0x01){ + var n=pt[pt.length-1]; + pt.splice(pt.length-n, n); + } + + // convert to string + for(var i=0; i>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32); + return wa; + } + function toString(wa){ + var s=[]; + for(var i=0; i>5]>>>(i%32))&mask)); + return s.join(""); + } + function toHex(wa) { + var h="0123456789abcdef"; + var s=[]; + for(var i=0; i>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF)); + } + return s.join(""); + } + function toBase64(wa){ + var p="="; + var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var s=[]; + for(var i=0; i>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF); + for(var j=0; j<4; j++){ + if(i*8+j*6>wa.length*32) s.push(p); + else s.push(tab.charAt((t>>6*(3-j))&0x3F)); + } + } + return s.join(""); + } + function add(x,y) { + var l=(x&0xFFFF)+(y&0xFFFF); + var m=(x>>16)+(y>>16)+(l>>16); + return (m<<16)|(l&0xFFFF); + } + function R(n,c){ return (n<>>(32-c)); } + function C(q,a,b,x,s,t){ return add(R(add(add(a,q),add(x,t)),s),b); } + function FF(a,b,c,d,x,s,t){ return C((b&c)|((~b)&d),a,b,x,s,t); } + function GG(a,b,c,d,x,s,t){ return C((b&d)|(c&(~d)),a,b,x,s,t); } + function HH(a,b,c,d,x,s,t){ return C(b^c^d,a,b,x,s,t); } + function II(a,b,c,d,x,s,t){ return C(c^(b|(~d)),a,b,x,s,t); } + function core(x,len){ + x[len>>5]|=0x80<<((len)%32); + x[(((len+64)>>>9)<<4)+14]=len; + var a= 1732584193; + var b=-271733879; + var c=-1732584194; + var d= 271733878; + for(var i=0; i16) wa=core(wa,key.length*chrsz); + var l=[], r=[]; + for(var i=0; i<16; i++){ + l[i]=wa[i]^0x36363636; + r[i]=wa[i]^0x5c5c5c5c; + } + var h=core(l.concat(toWord(data)),512+data.length*chrsz); + return core(r.concat(h),640); + } + + // Public functions + this.compute=function(/* string */data, /* dojo.crypto.outputTypes */outputType){ + // summary + // computes the digest of data, and returns the result as a string of type outputType + var out=outputType||dojo.crypto.outputTypes.Base64; + switch(out){ + case dojo.crypto.outputTypes.Hex:{ + return toHex(core(toWord(data),data.length*chrsz)); // string + } + case dojo.crypto.outputTypes.String:{ + return toString(core(toWord(data),data.length*chrsz)); // string + } + default:{ + return toBase64(core(toWord(data),data.length*chrsz)); // string + } + } + }; + this.getHMAC=function(/* string */data, /* string */key, /* dojo.crypto.outputTypes */outputType){ + // summary + // computes a digest of data using key, and returns the result as a string of outputType + var out=outputType||dojo.crypto.outputTypes.Base64; + switch(out){ + case dojo.crypto.outputTypes.Hex:{ + return toHex(hmac(data,key)); // string + } + case dojo.crypto.outputTypes.String:{ + return toString(hmac(data,key)); // string + } + default:{ + return toBase64(hmac(data,key)); // string + } + } + }; +}(); diff --git a/source/web/scripts/ajax/dojo/src/crypto/Rijndael.js b/source/web/scripts/ajax/dojo/src/crypto/Rijndael.js new file mode 100644 index 0000000000..3fa88cc07b --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/crypto/Rijndael.js @@ -0,0 +1,22 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.crypto.Rijndael"); +dojo.require("dojo.crypto"); +dojo.require("dojo.experimental"); + +dojo.experimental("dojo.crypto.Rijndael"); + +dojo.crypto.Rijndael = new function(){ + this.encrypt=function(plaintext, key){ + }; + this.decrypt=function(ciphertext, key){ + }; +}(); diff --git a/source/web/scripts/ajax/dojo/src/crypto/SHA1.js b/source/web/scripts/ajax/dojo/src/crypto/SHA1.js new file mode 100644 index 0000000000..7119a7c1c9 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/crypto/SHA1.js @@ -0,0 +1,154 @@ +dojo.require("dojo.crypto"); +dojo.provide("dojo.crypto.SHA1"); +dojo.require("dojo.experimental"); + +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + * + * Dojo port by Tom Trenka + */ +dojo.experimental("dojo.crypto.SHA1"); + +dojo.crypto.SHA1 = new function(){ + var chrsz=8; + var mask=(1<>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32); + return wa; + } + function toString(wa){ + var s=[]; + for(var i=0; i>5]>>>(i%32))&mask)); + return s.join(""); + } + function toHex(wa) { + var h="0123456789abcdef"; + var s=[]; + for(var i=0; i>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF)); + } + return s.join(""); + } + function toBase64(wa){ + var p="="; + var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var s=[]; + for(var i=0; i>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF); + for(var j=0; j<4; j++){ + if(i*8+j*6>wa.length*32) s.push(p); + else s.push(tab.charAt((t>>6*(3-j))&0x3F)); + } + } + return s.join(""); + } + + // math + function add(x,y){ + var l=(x&0xffff)+(y&0xffff); + var m=(x>>16)+(y>>16)+(l>>16); + return (m<<16)|(l&0xffff); + } + function r(x,n){ return (x<>>(32-n)); } + + // SHA rounds + function f(u,v,w){ return ((u&v)|(~u&w)); } + function g(u,v,w){ return ((u&v)|(u&w)|(v&w)); } + function h(u,v,w){ return (u^v^w); } + + function fn(i,u,v,w){ + if(i<20) return f(u,v,w); + if(i<40) return h(u,v,w); + if(i<60) return g(u,v,w); + return h(u,v,w); + } + function cnst(i){ + if(i<20) return 1518500249; + if(i<40) return 1859775393; + if(i<60) return -1894007588; + return -899497514; + } + + function core(x,len){ + x[len>>5]|=0x80<<(24-len%32); + x[((len+64>>9)<<4)+15]=len; + + var w=[]; + var a= 1732584193; // 0x67452301 + var b=-271733879; // 0xefcdab89 + var c=-1732584194; // 0x98badcfe + var d= 271733878; // 0x10325476 + var e=-1009589776; // 0xc3d2e1f0 + + for(var i=0; i16) wa=core(wa,key.length*chrsz); + var l=[], r=[]; + for(var i=0; i<16; i++){ + l[i]=wa[i]^0x36363636; + r[i]=wa[i]^0x5c5c5c5c; + } + var h=core(l.concat(toWord(data)),512+data.length*chrsz); + return core(r.concat(h),640); + } + + this.compute=function(data,outputType){ + var out=outputType||dojo.crypto.outputTypes.Base64; + switch(out){ + case dojo.crypto.outputTypes.Hex:{ + return toHex(core(toWord(data),data.length*chrsz)); + } + case dojo.crypto.outputTypes.String:{ + return toString(core(toWord(data),data.length*chrsz)); + } + default:{ + return toBase64(core(toWord(data),data.length*chrsz)); + } + } + }; + this.getHMAC=function(data,key,outputType){ + var out=outputType||dojo.crypto.outputTypes.Base64; + switch(out){ + case dojo.crypto.outputTypes.Hex:{ + return toHex(hmac(data,key)); + } + case dojo.crypto.outputTypes.String:{ + return toString(hmac(data,key)); + } + default:{ + return toBase64(hmac(data,key)); + } + } + }; +}(); diff --git a/source/web/scripts/ajax/dojo/src/crypto/SHA256.js b/source/web/scripts/ajax/dojo/src/crypto/SHA256.js new file mode 100644 index 0000000000..00a97c6b83 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/crypto/SHA256.js @@ -0,0 +1,20 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.crypto.SHA256"); +dojo.require("dojo.crypto"); +dojo.require("dojo.experimental"); + +dojo.experimental("dojo.crypto.SHA256"); + +dojo.crypto.SHA256 = new function(){ + this.compute=function(s){ + }; +}(); diff --git a/source/web/scripts/ajax/dojo/src/crypto/__package__.js b/source/web/scripts/ajax/dojo/src/crypto/__package__.js new file mode 100644 index 0000000000..652b66d795 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/crypto/__package__.js @@ -0,0 +1,17 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: [ + "dojo.crypto", + "dojo.crypto.MD5" + ] +}); +dojo.provide("dojo.crypto.*"); diff --git a/source/web/scripts/ajax/dojo/src/data.js b/source/web/scripts/ajax/dojo/src/data.js new file mode 100644 index 0000000000..36532e9f77 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data"); + +// currently a stub for dojo.data + +dojo.data = {}; diff --git a/source/web/scripts/ajax/dojo/src/data/CsvStore.js b/source/web/scripts/ajax/dojo/src/data/CsvStore.js new file mode 100644 index 0000000000..b9da442671 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/CsvStore.js @@ -0,0 +1,207 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.CsvStore"); +dojo.require("dojo.data.core.RemoteStore"); +dojo.require("dojo.lang.assert"); + +dojo.declare("dojo.data.CsvStore", dojo.data.core.RemoteStore, { + /* summary: + * The CsvStore subclasses dojo.data.core.RemoteStore to implement + * the dojo.data.core.Read API. + */ + + /* examples: + * var csvStore = new dojo.data.CsvStore({queryUrl:"movies.csv"); + * var csvStore = new dojo.data.CsvStore({url:"http://example.com/movies.csv"); + */ + _setupQueryRequest: function(/* dojo.data.core.Result */ result, /* object */ requestKw) { + // summary: See dojo.data.core.RemoteStore._setupQueryRequest() + var serverQueryUrl = this._serverQueryUrl ? this._serverQueryUrl : ""; + var queryUrl = result.query ? result.query : ""; + requestKw.url = serverQueryUrl + queryUrl; + requestKw.method = 'get'; + }, + + _resultToQueryData: function(/* varies */ serverResponseData) { + // summary: See dojo.data.core.RemoteStore._resultToQueryData() + var csvFileContentString = serverResponseData; + var arrayOfArrays = this._getArrayOfArraysFromCsvFileContents(csvFileContentString); + var arrayOfObjects = this._getArrayOfObjectsFromArrayOfArrays(arrayOfArrays); + var remoteStoreData = this._getRemoteStoreDataFromArrayOfObjects(arrayOfObjects); + return remoteStoreData; + }, + + _setupSaveRequest: function(/* object */ saveKeywordArgs, /* object */ requestKw) { + // summary: See dojo.data.core.RemoteStore._setupSaveRequest() + // description: NOT IMPLEMENTED -- CsvStore is a read-only store + }, + + // ------------------------------------------------------------------- + // Private methods + _getArrayOfArraysFromCsvFileContents: function(/* string */ csvFileContents) { + /* summary: + * Parses a string of CSV records into a nested array structure. + * description: + * Given a string containing CSV records, this method parses + * the string and returns a data structure containing the parsed + * content. The data structure we return is an array of length + * R, where R is the number of rows (lines) in the CSV data. The + * return array contains one sub-array for each CSV line, and each + * sub-array contains C string values, where C is the number of + * columns in the CSV data. + */ + + /* example: + * For example, given this CSV string as input: + * "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott" + * We will return this data structure: + * [["Title", "Year", "Producer"] + * ["Alien", "1979", "Ridley Scott"], + * ["Blade Runner", "1982", "Ridley Scott"]] + */ + dojo.lang.assertType(csvFileContents, String); + + var lineEndingCharacters = new RegExp("\r\n|\n|\r"); + var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g'); + var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g'); + var doubleQuotes = new RegExp('""','g'); + var arrayOfOutputRecords = []; + + var arrayOfInputLines = csvFileContents.split(lineEndingCharacters); + for (var i in arrayOfInputLines) { + var singleLine = arrayOfInputLines[i]; + if (singleLine.length > 0) { + var listOfFields = singleLine.split(','); + var j = 0; + while (j < listOfFields.length) { + var space_field_space = listOfFields[j]; + var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace + var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace + var firstChar = field.charAt(0); + var lastChar = field.charAt(field.length - 1); + var secondToLastChar = field.charAt(field.length - 2); + var thirdToLastChar = field.charAt(field.length - 3); + if ((firstChar == '"') && + ((lastChar != '"') || + ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) { + if (j+1 === listOfFields.length) { + // alert("The last field in record " + i + " is corrupted:\n" + field); + return null; + } + var nextField = listOfFields[j+1]; + listOfFields[j] = field_space + ',' + nextField; + listOfFields.splice(j+1, 1); // delete element [j+1] from the list + } else { + if ((firstChar == '"') && (lastChar == '"')) { + field = field.slice(1, (field.length - 1)); // trim the " characters off the ends + field = field.replace(doubleQuotes, '"'); // replace "" with " + } + listOfFields[j] = field; + j += 1; + } + } + arrayOfOutputRecords.push(listOfFields); + } + } + return arrayOfOutputRecords; // Array + }, + + _getArrayOfObjectsFromArrayOfArrays: function(/* array[] */ arrayOfArrays) { + /* summary: + * Converts a nested array structure into an array of keyword objects. + */ + + /* example: + * For example, given this as input: + * [["Title", "Year", "Producer"] + * ["Alien", "1979", "Ridley Scott"], + * ["Blade Runner", "1982", "Ridley Scott"]] + * We will return this as output: + * [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"}, + * {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}] + */ + dojo.lang.assertType(arrayOfArrays, Array); + var arrayOfItems = []; + if (arrayOfArrays.length > 1) { + var arrayOfKeys = arrayOfArrays[0]; + for (var i = 1; i < arrayOfArrays.length; ++i) { + var row = arrayOfArrays[i]; + var item = {}; + for (var j in row) { + var value = row[j]; + var key = arrayOfKeys[j]; + item[key] = value; + } + arrayOfItems.push(item); + } + } + return arrayOfItems; // Array + }, + + _getRemoteStoreDataFromArrayOfObjects: function(/* object[] */ arrayOfObjects) { + /* summary: + * Converts an array of keyword objects in the internal record data + * structure used by RemoteStore. + */ + + /* example: + * For example, given this as input: + * [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"}, + * {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}] + * We will return this as output: + * { "1": {"Title":["Alien"], "Year":["1979"], "Producer":["Ridley Scott"]}, + * "2": {"Title":["Blade Runner"], "Year":["1982"], "Producer":["Ridley Scott"]} + * } + */ + dojo.lang.assertType(arrayOfObjects, Array); + var output = {}; + for (var i = 0; i < arrayOfObjects.length; ++i) { + var object = arrayOfObjects[i]; + for (var key in object) { + var value = object[key]; // {"Title":"Alien"} --> "Alien" + object[key] = [value]; // {"Title":["Alien"]} + } + output[i] = object; + } + return output; // Object + }, + + // CsvStore implements the dojo.data.core.Read API, but does not yet + // implements the dojo.data.core.Write API. CsvStore extends RemoteStore, + // and RemoteStore does implement the Write API, so we need to explicitly + // mark those Write API methods as being unimplemented. + newItem: function(/* object? */ attributes, /* object? */ keywordArgs) { + dojo.unimplemented('dojo.data.CsvStore.newItem'); + }, + deleteItem: function(/* item */ item) { + dojo.unimplemented('dojo.data.CsvStore.deleteItem'); + }, + setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) { + dojo.unimplemented('dojo.data.CsvStore.setValues'); + }, + set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) { + dojo.unimplemented('dojo.data.CsvStore.set'); + }, + unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) { + dojo.unimplemented('dojo.data.CsvStore.unsetAttribute'); + }, + save: function(/* object? */ keywordArgs) { + dojo.unimplemented('dojo.data.CsvStore.save'); + }, + revert: function() { + dojo.unimplemented('dojo.data.CsvStore.revert'); + }, + isDirty: function(/*item?*/ item) { + dojo.unimplemented('dojo.data.CsvStore.isDirty'); + } + +}); + diff --git a/source/web/scripts/ajax/dojo/src/data/OpmlStore.js b/source/web/scripts/ajax/dojo/src/data/OpmlStore.js new file mode 100644 index 0000000000..3b4904fe0d --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/OpmlStore.js @@ -0,0 +1,224 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.OpmlStore"); +dojo.require("dojo.data.core.Read"); +dojo.require("dojo.data.core.Result"); +dojo.require("dojo.lang.assert"); +dojo.require("dojo.json"); + +dojo.require("dojo.experimental"); +dojo.experimental("dojo.data.OpmlStore"); +// FIXME: The OpmlStore works in Firefox but does not yet work in IE. + +dojo.declare("dojo.data.OpmlStore", dojo.data.core.Read, { + /* summary: + * The OpmlStore implements the dojo.data.core.Read API. + */ + + /* examples: + * var opmlStore = new dojo.data.OpmlStore({url:"geography.opml"}); + * var opmlStore = new dojo.data.OpmlStore({url:"http://example.com/geography.opml"}); + */ + initializer: function(/* object */ keywordParameters) { + // keywordParameters: {url: String} + this._arrayOfTopLevelItems = []; + this._metadataNodes = null; + this._loadFinished = false; + this._opmlFileUrl = keywordParameters["url"]; + }, + + _assertIsItem: function(/* item */ item) { + if (!this.isItem(item)) { + throw new Error("dojo.data.OpmlStore: a function was passed an item argument that was not an item"); + } + }, + + _removeChildNodesThatAreNotElementNodes: function(/* node */ node, /* boolean */ recursive) { + var childNodes = node.childNodes; + if (childNodes.length == 0) { + return; + } + var nodesToRemove = []; + var i, childNode; + for (i = 0; i < childNodes.length; ++i) { + childNode = childNodes[i]; + if (childNode.nodeType != Node.ELEMENT_NODE) { + nodesToRemove.push(childNode); + } + }; + // dojo.debug('trim: ' + childNodes.length + ' total, ' + nodesToRemove.length + ' junk'); + for (i = 0; i < nodesToRemove.length; ++i) { + childNode = nodesToRemove[i]; + node.removeChild(childNode); + } + // dojo.debug('trim: ' + childNodes.length + ' remaining'); + if (recursive) { + for (i = 0; i < childNodes.length; ++i) { + childNode = childNodes[i]; + this._removeChildNodesThatAreNotElementNodes(childNode, recursive); + } + } + }, + + _processRawXmlTree: function(/* xmlDoc */ rawXmlTree) { + var headNodes = rawXmlTree.getElementsByTagName('head'); + var headNode = headNodes[0]; + this._removeChildNodesThatAreNotElementNodes(headNode); + this._metadataNodes = headNode.childNodes; + var bodyNodes = rawXmlTree.getElementsByTagName('body'); + var bodyNode = bodyNodes[0]; + this._removeChildNodesThatAreNotElementNodes(bodyNode, true); + + var bodyChildNodes = bodyNodes[0].childNodes; + for (var i = 0; i < bodyChildNodes.length; ++i) { + var node = bodyChildNodes[i]; + if (node.tagName == 'outline') { + this._arrayOfTopLevelItems.push(node); + } + } + }, + + get: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) { + // summary: See dojo.data.core.Read.get() + this._assertIsItem(item); + if (attribute == 'children') { + return (item.firstChild || defaultValue); + } else { + var value = item.getAttribute(attribute); + value = (value != undefined) ? value : defaultValue; + return value; + } + }, + + getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute) { + // summary: See dojo.data.core.Read.getValues() + this._assertIsItem(item); + if (attribute == 'children') { + var array = []; + for (var i = 0; i < item.childNodes.length; ++i) { + array.push(item.childNodes[i]); + } + return array; // Array + // return item.childNodes; // FIXME: this isn't really an Array + } else { + return [item.getAttribute(attribute)]; // Array + } + }, + + getAttributes: function(/* item */ item) { + // summary: See dojo.data.core.Read.getAttributes() + this._assertIsItem(item); + var attributes = []; + var xmlNode = item; + var xmlAttributes = xmlNode.attributes; + for (var i = 0; i < xmlAttributes.length; ++i) { + var xmlAttribute = xmlAttributes.item(i); + attributes.push(xmlAttribute.nodeName); + } + if (xmlNode.childNodes.length > 0) { + attributes.push('children'); + } + return attributes; // array + }, + + hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute) { + // summary: See dojo.data.core.Read.hasAttribute() + return (this.getValues(item, attribute).length > 0); + }, + + containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) { + // summary: See dojo.data.core.Read.containsValue() + var values = this.getValues(item, attribute); + for (var i = 0; i < values.length; ++i) { + var possibleValue = values[i]; + if (value == possibleValue) { + return true; + } + } + return false; // boolean + }, + + isItem: function(/* anything */ something) { + return (something && + something.nodeType == Node.ELEMENT_NODE && + something.tagName == 'outline'); // boolean + }, + + isItemAvailable: function(/* anything */ something) { + return this.isItem(something); + }, + + find: function(/* object? || dojo.data.core.Result */ keywordArgs) { + // summary: See dojo.data.core.Read.find() + var result = null; + if (keywordArgs instanceof dojo.data.core.Result) { + result = keywordArgs; + result.store = this; + } else { + result = new dojo.data.core.Result(keywordArgs, this); + } + var self = this; + var bindHandler = function(type, data, evt) { + var scope = result.scope || dj_global; + if (type == "load") { + self._processRawXmlTree(data); + if (result.saveResult) { + result.items = self._arrayOfTopLevelItems; + } + if (result.onbegin) { + result.onbegin.call(scope, result); + } + for (var i=0; i < self._arrayOfTopLevelItems.length; i++) { + var item = self._arrayOfTopLevelItems[i]; + if (result.onnext && !result._aborted) { + result.onnext.call(scope, item, result); + } + } + if (result.oncompleted && !result._aborted) { + result.oncompleted.call(scope, result); + } + } else if(type == "error" || type == 'timeout') { + // todo: how to handle timeout? + var errorObject = data; + // dojo.debug("error in dojo.data.OpmlStore.find(): " + dojo.json.serialize(errorObject)); + if (result.onerror) { + result.onerror.call(scope, data); + } + } + }; + + if (!this._loadFinished) { + if (this._opmlFileUrl) { + var bindRequest = dojo.io.bind({ + url: this._opmlFileUrl, // "playlist.opml", + handle: bindHandler, + mimetype: "text/xml", + sync: (result.sync || false) }); + result._abortFunc = bindRequest.abort; + } + } + return result; // dojo.data.csv.Result + }, + + getIdentity: function(/* item */ item) { + // summary: See dojo.data.core.Read.getIdentity() + dojo.unimplemented('dojo.data.OpmlStore.getIdentity()'); + return null; + }, + + findByIdentity: function(/* string */ identity) { + // summary: See dojo.data.core.Read.findByIdentity() + dojo.unimplemented('dojo.data.OpmlStore.findByIdentity()'); + return null; + } +}); + + diff --git a/source/web/scripts/ajax/dojo/src/data/RdfStore.js b/source/web/scripts/ajax/dojo/src/data/RdfStore.js new file mode 100644 index 0000000000..74c4751be7 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/RdfStore.js @@ -0,0 +1,292 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.RdfStore"); +dojo.provide("dojo.data.RhizomeStore"); +dojo.require("dojo.lang.declare"); +dojo.require("dojo.data.core.RemoteStore"); +dojo.require("dojo.experimental"); + +/* summary: + * RdfStore provides a dojo.data Store for querying and updating a server + * that supports the SPARQL Query Result JSON format. + * (see http://www.w3.org/TR/rdf-sparql-json-res/) + * + * It also maps RDF datatypes to Javascript objects. + * + * RdfStore makes following assumptions about the Result JSON: + * (1) The result always contains 3 bound variables named "s","p", and "o", + * and each result binding is treated as an RDF statement. + * (2) When saving changes to the store, the JSON "results" object will also + * contain a "deleted" key whose value is a list of deleted RDF resources. + * + */ + +dojo.data.RdfDatatypeSerializer = function(/* JavaScript type */type, /* function */convertFunc, /* RDF datatype URI */uri) { + /* summary: + This class serializes a javascript object into a RDF datatype literal. + */ + this.type = type; + this._converter = convertFunc; + this.uri = uri; + this.serialize = function(value) { + return this._converter.call(value, value); + }; +} + +dojo.declare("dojo.data.RdfStore", dojo.data.core.RemoteStore, { + + _datatypeMap: { + //map datatype strings to constructor function + literal: function(value) { + var literal = value.value; + if (value["xml:lang"]) { + literal.lang = value["xml:lang"]; + } + return literal; + }, + + uri: function(value) { + return { id: value.value }; + }, + + bnode: function(value) { + return { id: '_:' + value.value }; + }, + + 'http://www.w3.org/2001/XMLSchema#int': function(value) { + return parseInt(value.value); + }, + 'http://www.w3.org/2001/XMLSchema#integer': function(value) { + return parseInt(value.value); + }, + 'http://www.w3.org/2001/XMLSchema#long': function(value) { + return parseInt(value.value); + }, + 'http://www.w3.org/2001/XMLSchema#float': function(value) { + return parseFloat(value.value); + }, + 'http://www.w3.org/2001/XMLSchema#double': function(value) { + return parseFloat(value.value); + }, + 'http://www.w3.org/2001/XMLSchema#boolean': function(value) { + return !value || value == "false" || value == "0" ? false : true; + } + //todo: more datatypes: + //integer subtypes, string types, XMLiteral + //,'http://www.w3.org/2001/XMLSchema#... : function(value) { return parseInt(value.value); } + }, + + _datatypeSerializers: [ + new dojo.data.RdfDatatypeSerializer(Number, Number.toString, 'http://www.w3.org/2001/XMLSchema#float'), + new dojo.data.RdfDatatypeSerializer(Boolean, Boolean.toString, 'http://www.w3.org/2001/XMLSchema#boolean') + ], + + _findDatatypeSerializer: function(value) { + var length = this._datatypeSerializers.length; + for (var i = 0; i < length; i++) { + var datatype = this._datatypeSerializers[i]; + if (value instanceof datatype.type) { + return datatype; + } + } + }, + + _toRDFValue: function(value) { + //convert values to rdf json format + //(from http://www.w3.org/TR/2006/NOTE-rdf-sparql-json-res-20061004/) + + var rdfvalue = {}; + if (value.id) { + if (value.id.slice(0, 2) == '_:') { + rdfvalue.type = 'bnode'; + rdfvalue.value = value.id.substring(2); + } else { + rdfvalue.type = 'uri'; + rdfvalue.value = value.id; + } + } else if (typeof value == "string" || value instanceof String) { + rdfvalue.type = 'literal'; + rdfvalue.value = value; + if (value.lang) + rdfvalue["xml:lang"] = value.lang; + } else { + if (typeof value == "number") + value = new Number(value); + else if (typeof value == "boolean") + value = new Boolean(value); + + var datatype = this._findDatatypeSerializer(value); + if (datatype) { + rdfvalue = { + "type": "typed-literal", + "datatype": datatype.uri, + "value": value.toString() + //todo: datatype.serialize(value) causes + //Error: Function.prototype.toString called on incompatible number + }; + } else { + //treat it as a string + //todo: warn? + rdfvalue = { + "type": "literal", + "value": value.toString() }; + } + } + return rdfvalue; + }, + + _setupSaveRequest: function(saveKeywordArgs, requestKw) { + /* + This function prepares the save request by populating requestKw, + an associative array that will be passed to dojo.io.bind. + */ + + //see http://www.w3.org/TR/rdf-sparql-json-res/ + var rdfResult = { "head": {'vars': ['s','p','o']}, + "results": {'bindings': []} }; + + var resources = []; + for (var key in this._deleted) { + resources.push(key); + } + rdfResult.results.deleted = resources; + + for (key in this._changed) { + var subject = this._toRDFValue(this.getIdentity(key)) + + var attributes = this._changed[key]; + for (var attr in attributes) { + var predicate = {type:'uri', value: attr}; + + var values = attributes[attr]; + if (!values.length) + continue; + var rdfvalues = []; + for (var i = 0; i < values.length; i++) { + var rdfvalue = this._toRDFValue(values[i]); + rdfResult.results.bindings.push( + {s: subject, p: predicate, o: rdfvalue}); + } + } + } + + var oldRegistry = dojo.json.jsonRegistry; + dojo.json.jsonRegistry = this._jsonRegistry; + var jsonString = dojo.json.serialize(rdfResult); + dojo.json.jsonRegistry = oldRegistry; + + //dojo.debug('save json' , jsonString); + + requestKw.postContent = jsonString; + }, + + _resultToQueryMetadata: function(json) { + return json.head; + }, + + _resultToQueryData: function(json) { + //assume s, p, o bindings + var items = {}; + var stmts = json.results.bindings; + for (var i = 0; i < stmts.length; i++) { + var stmt = stmts[i]; + //assert stmt.s && stmt.p && stmt.o; + var subject = stmt.s.value; + if (stmt.s.type == 'bnode') { + subject = '_:' + subject; + } + //else { assert stmt.s.type == 'uri';} + var attributes = data[subject]; + if (!attributes) { + attributes = {}; + data[stmt.s] = attributes; + } + var attr = attributes[stmt.p.value]; + if (!attr) { + attributes[stmt.p.value] = [stmt.o]; + } else { + attr.push(stmt.o); + } + } + return items; + } +}); + +dojo.declare("dojo.data.RhizomeStore", dojo.data.RdfStore, { + /* summary: + * RhizomeStore is a subclass of RdfStore that works with + * the Rhizome semantic wiki (see http://www.liminalzone.org) + * Rhizome understands the RemoteStore's "native" json format + * so it doesn't need to convert it to the SPARQL Query Result format. + */ + + initializer: function(kwArgs) { + this._serverQueryUrl = kwArgs.baseUrl + 'search?view=json&searchType=RxPath&search='; + this._serverSaveUrl = kwArgs.baseUrl + 'save-metadata'; + }, + + _resultToQueryMetadata: function(json) { + return json; + }, + + _resultToQueryData: function(json) { + //dojo.debug( 'resultjson ' + dojo.json.serialize(json) ); + return json; + }, + + _setupSaveRequest: function(saveKeywordArgs, requestKw) { + /* + This function prepares the save request by populating requestKw, + an associative array that will be passed to dojo.io.bind. + */ + requestKw.url = this._serverSaveUrl; + requestKw.method = 'post'; + requestKw.mimetype = "text/plain"; + + var resources = []; + for (var key in this._deleted) { + resources.push(key); + } + + var changes = {}; + for (key in this._changed) { + if (!this._added[key]) { //don't put new resources in this list + resources.push(key); + } + + var attributes = this._changed[key]; + var rdfattributes = {}; + for (var attr in attributes) { + var values = attributes[attr]; + if (!values.length) + continue; + var rdfvalues = []; + for (var i = 0; i < values.length; i++) { + var rdfvalue = this._toRDFValue(values[i]); + rdfvalues.push(rdfvalue); + } + rdfattributes[attr] = rdfvalues; + } + changes[key] = rdfattributes; + } + + var oldRegistry = dojo.json.jsonRegistry; + dojo.json.jsonRegistry = this._jsonRegistry; + var jsonString = dojo.json.serialize(changes); + dojo.json.jsonRegistry = oldRegistry; + + requestKw.content = { + rdfFormat: 'json', + resource: resources, + metadata: jsonString + }; + } +}); diff --git a/source/web/scripts/ajax/dojo/src/data/YahooStore.js b/source/web/scripts/ajax/dojo/src/data/YahooStore.js new file mode 100644 index 0000000000..52ad0cdfeb --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/YahooStore.js @@ -0,0 +1,53 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.YahooStore"); +dojo.require("dojo.data.core.RemoteStore"); +dojo.require("dojo.lang.declare"); +dojo.require("dojo.io.ScriptSrcIO"); + +dojo.declare("dojo.data.YahooStore", dojo.data.core.RemoteStore, { + /* Summary: + * The YahooStore implements the dojo.data.core.Read API. + */ + _setupQueryRequest: function(result, requestKw) { + var start = 1; + var count = 1; + if (result) { + start = result.start || start; + count = result.count || count; + } + var sourceUrl = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=dojo&language=en&query=" + + result.query + "&start=" + start + "&results=" + count + "&output=json"; + requestKw.url = sourceUrl; + requestKw.transport = "ScriptSrcTransport"; + requestKw.mimetype = "text/json"; + requestKw.jsonParamName = 'callback'; + }, + + _resultToQueryMetadata: function(json) { + return json.ResultSet; + }, + + _resultToQueryData: function(json) { + var data = {} + for (var i = 0; i < json.ResultSet.totalResultsReturned; ++i) { + var record = json.ResultSet.Result[i]; + var item = {}; + item["Url"] = [record.Url]; + item["Title"] = [record.Title]; + item["Summary"] =[ record.Summary]; + var arrayIndex = (json.ResultSet.firstResultPosition - 1) + i; + data[ arrayIndex.toString() ] = item; + } + return data; + } +}); + diff --git a/source/web/scripts/ajax/dojo/src/data/core/Read.js b/source/web/scripts/ajax/dojo/src/data/core/Read.js new file mode 100644 index 0000000000..f687e2ebef --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/core/Read.js @@ -0,0 +1,321 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.core.Read"); +dojo.require("dojo.data.core.Result"); +dojo.require("dojo.lang.declare"); +dojo.require("dojo.experimental"); + +/* summary: + * This is an abstract API that data provider implementations conform to. + * This file defines methods signatures and intentionally leaves all the + * methods unimplemented. + */ +dojo.experimental("dojo.data.core.Read"); + +dojo.declare("dojo.data.core.Read", null, { + get: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) { + /* summary: + * Returns a single attribute value. + * Returns defaultValue if *item* does not have a value for *attribute*. + * Returns null if null was explicitly set as the attribute value. + * Returns undefined if the item does not have a value for the given + * attribute, or if the item does not have the attribute. + * description: + * Saying that an "item x does not have a value for an attribute y" + * is identical to saying that an "item x does not have attribute y". + * It is an oxymoron to say "that attribute is present but has no values" + * or "the item has that attribute but does not have any attribute values". + * If store.hasAttribute(item, attribute) returns false, then + * store.get(item, attribute) will return undefined. + */ + + /* exceptions: + * Conforming implementations should throw an exception if *item* is not + * an item, or *attribute* is neither an attribute object or a string. + * examples: + * var darthVader = store.get(lukeSkywalker, "father"); + */ + dojo.unimplemented('dojo.data.core.Read.get'); + var attributeValue = null; + return attributeValue; // a literal, an item, null, or undefined (never an array) + }, + + getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute) { + /* summary: + * This getValues() method works just like the get() method, but getValues() + * always returns an array rather than a single attribute value. The array + * may be empty, may contain a single attribute value, or may contain many + * attribute values. + * If the item does not have a value for the given attribute, then getValues() + * will return an empty array: []. (So, if store.hasAttribute(item, attribute) + * returns false, then store.getValues(item, attribute) will return [].) + */ + + /* exceptions: + * Throws an exception if *item* is not an item, or *attribute* is neither an + * attribute object or a string. + * examples: + * var friendsOfLuke = store.get(lukeSkywalker, "friends"); + */ + dojo.unimplemented('dojo.data.core.Read.getValues'); + var array = null; + return array; // an array that may contain literals and items + }, + + getAttributes: function(/* item */ item) { + /* summary: + * Returns an array with all the attributes that this item has. This + * method will always return an array; if the item has no attributes + * at all, getAttributes() will return an empty array: []. + */ + + /* exceptions: + * Throws an exception if *item* is not an item. + * examples: + * var array = store.getAttributes(kermit); + */ + dojo.unimplemented('dojo.data.core.Read.getAttributes'); + var array = null; + return array; // array + }, + + hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute) { + /* summary: + * Returns true if the given *item* has a value for the given *attribute*. + */ + + /* exceptions: + * Throws an exception if *item* is not an item, or *attribute* is neither an + * attribute object or a string. + * examples: + * var trueOrFalse = store.hasAttribute(kermit, "color"); + */ + dojo.unimplemented('dojo.data.core.Read.hasAttribute'); + return false; // boolean + }, + + containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) { + /* summary: + * Returns true if the given *value* is one of the values that getValue() + * would return. + */ + + /* exceptions: + * Throws an exception if *item* is not an item, or *attribute* is neither an + * attribute object or a string. + * examples: + * var trueOrFalse = store.containsValue(kermit, "color", "green"); + */ + dojo.unimplemented('dojo.data.core.Read.containsValue'); + return false; // boolean + }, + + isItem: function(/* anything */ something) { + /* summary: + * Returns true if *something* is an item. Returns false if *something* + * is a literal or is any object other than an item. + */ + + /* examples: + * var yes = store.isItem(store.newItem()); + * var no = store.isItem("green"); + */ + dojo.unimplemented('dojo.data.core.Read.isItem'); + return false; // boolean + }, + + isItemAvailable: function(/* anything */ something) { + /* summary: + * Returns false if isItem(something) is false. Returns false if + * if isItem(something) is true but the the item is not yet available + * in local memory (for example, if the item has not yet been fully + * loaded from the server). + */ + + /* examples: + * var yes = store.isItemAvailable(store.newItem()); + * var no = store.isItemAvailable("green"); + */ + dojo.unimplemented('dojo.data.core.Read.isItemAvailable'); + return false; // boolean + }, + + find: function(/* object? || dojo.data.core.Result */ keywordArgs) { + /* summary: + * Given a query, this method executes the query and makes the + * results available as data items. + * description: + * A Result object will always be returned, even if the result set + * is empty. A Result object will always be returned immediately. + * By default the Result object will be fully populated with result + * items as soon as it is created (synchronously). The caller may + * request that the find() operation be executed asynchronously, in + * which case the Result object will be returned immediately but + * will not yet be populated with result items. + * For more info about the Result API, see dojo.data.core.Result + * keywordArgs: + * The keywordArgs parameter may either be an instance of + * dojo.data.core.Result or may be a simple anonymous object + * that may contain any of the following: + * { query: query-string or query-object, + * sync: Boolean, + * saveResult: Boolean, + * onbegin: Function, + * onnext: Function, + * oncompleted: Function, + * onerror: Function, + * scope: object + * } + * All implementations should accept keywordArgs objects with any of + * the 7 standard properties: query, sync, saveResult, onnext, oncompleted, + * onerror, and scope. Some implementations may accept additional + * properties in the keywordArgs object as valid parameters, such as + * {maxResults:100} or {includeOutliers:true}. + * The *query* parameter. + * The query may be optional in some data store implementations. + * The dojo.data.core.Read API does not specify the syntax or semantics + * of the query itself -- each different data store implementation + * may have its own notion of what a query should look like. + * In most implementations the query will probably be a string, but + * in some implementations the query might be a Date, or a number, + * or some complex keyword parameter object. The dojo.data.core.Read + * API is completely agnostic about what the query actually is. + * The *sync* parameter. + * The sync parameter specifies whether the find operation is asynchronous + * or not, with {sync:false} for asynchronous finds operations and + * {sync:true} for synchronous find operations. If no sync parameter + * is specified, the default is {sync:true}. + * The *saveResult* parameter. + * If saveResult is true, then the find call will return a Result + * object that includes a property called *items*, and *items* will + * contain an array of the items found by the query. If no saveResult + * parameter is specified and no onnext Function is set, the default + * saveResult value will be {saveResult:true}. If no saveResult + * parameter is specified but an onnext Function is set, the default + * saveResult value will be {saveResult:false}. + * The *onbegin* parameter. + * If an onbegin callback function is provided, the callback function + * will be called just once, before the first onnext callback is called. + * The onbegin callback function will be passed a single argument: + * the Result object. The onbegin callback will be called even if + * query returns zero items. + * The *onnext* parameter. + * If an onnext callback function is provided, the callback function + * will be called as each item in the result is received. The callback + * function will be passed two arguments: the item itself, and the + * Result object. + * The *oncompleted* parameter. + * If an oncompleted callback function is provided, the callback function + * will be called just once, after the last onnext callback is called. + * The oncompleted callback function will be passed a single argument: + * the Result object. The oncompleted callback will be called even if + * query returns zero items. + * The *onerror* parameter. + * If an onerror callback function is provided, the callback function + * will be called if there is any sort of error while attempting to + * execute the query.. + * The onerror callback function will be passed two arguments: + * an Error object and the Result object. + * The *scope* parameter. + * If a scope object is provided, all of the callback function (onnext, + * oncompleted, onerror) will be invoked in the context of the scope + * object. In the body of the callback function, the value of the "this" + * keyword will be the scope object. If no scope object is provided, + * the callback functions will be called in the context of dj_global. + * For example, onnext.call(scope, item, result) vs. + * onnext.call(dj_global, item, result) + * returns: + * The find() method will return an instance of dojo.data.core.Result + * (or an object that extends dojo.data.core.Result or conforms to the + * dojo.data.core.Result API). If the find() method was passed an + * instance of dojo.data.core.Result as an argument, the same instance + * will be returned. If the find() method was passed a simple + * keywordArgs object, like {sync:true}, then the properties in the + * keywordArgs object will be copied into the Result object that + * find() returns. The Result object will also have additional + * properties when it is returned. The result.store property will + * have a pointer to the datastore object that find() is a method of. + * The result.length will be -1 if the find() operation has not + * finished or if there was an error; if the find() operation + * finishes successfully, result.length will be the number of items + * that were found. If the saveResult property was set to true, or + * if no onnext callback was set, the result.item property will + * contain an array of data items. The result.resultMetadata property + * will contain an additional metaData that was returned by the query + * along with the data items. For example, if the query returned a + * list of 500 houses for sales, the resultMetadata property might + * contain the average asking price of the houses, or info about + * how long the query took to execute. + */ + + /* exceptions: + * Throws an exception if the query is not valid, or if the query + * is required but was not supplied. + * examples: + * var result = store.find({query:"all books"}); + * var result = store.find(); + * var result = store.find({query:"foo/bar", sync:true}); + * var result = store.find({query:"foo/bar", sync:false, onnext:callback}); + * var result = store.find({query:{author:"King"}, maxResults:100}); + */ + dojo.unimplemented('dojo.data.core.Read.find'); + var result = null; // new dojo.data.core.Result(). + return result; // a dojo.data.core.Result object + }, + + getIdentity: function(/* item */ item) { + /* summary: + * Returns a unique identifer for an item. The return value will be + * either a string or something that has a toString() method (such as, + * for example, a dojo.uuid.Uuid object). + * description: + * ISSUE - + * Should we move this method out of dojo.data.core.Read, and put it somewhere + * else, like maybe dojo.data.core.Identity? + */ + + /* exceptions: + * Conforming implementations may throw an exception or return null if + * item is not an item. + * examples: + * var itemId = store.getIdentity(kermit); + * assert(kermit === store.findByIdentity(store.getIdentity(kermit))); + */ + dojo.unimplemented('dojo.data.core.Read.getIdentity'); + var itemIdentifyString = null; + return itemIdentifyString; // string + }, + + findByIdentity: function(/* string */ identity) { + /* summary: + * Given the identity of an item, this method returns the item that has + * that identity. Conforming implementations should return null if there + * is no item with the given identity. Implementations of findByIdentity() + * may sometimes return an item from a local cache and may sometimes + * fetch an item from a remote server, in which case the call to + * findByIdentity() will block until the findByIdentity() implementation + * has the item to return. + * description: + * FIXME - + * In our meeting on 2006-10-03 we resolved to move the findByIdentity() + * method out of the Read.js API and into the Identity.js API, as soon + * as we have an Identity.js API. + */ + + /* examples: + * var alaska = store.getByIdentity("AK"); + * assert("AK" == store.getIdentity(store.getByIdentity("AK"))); + */ + dojo.unimplemented('dojo.data.core.Read.getByIdentity'); + var item = null; + return item; // item + } +}); diff --git a/source/web/scripts/ajax/dojo/src/data/core/RemoteStore.js b/source/web/scripts/ajax/dojo/src/data/core/RemoteStore.js new file mode 100644 index 0000000000..2a4c2db88d --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/core/RemoteStore.js @@ -0,0 +1,590 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.core.RemoteStore"); +dojo.require("dojo.data.core.Read"); +dojo.require("dojo.data.core.Write"); +dojo.require("dojo.data.core.Result"); +dojo.require("dojo.experimental"); +dojo.require("dojo.Deferred"); +dojo.require("dojo.lang.declare"); +dojo.require("dojo.json"); +dojo.require("dojo.io.*"); + +/* summary: + * RemoteStore is an implemention the dojo.data.core.Read and Write APIs. + * It is designed to serve as a base class for dojo.data stores which interact + * with stateless web services that can querying and modifying record-oriented + * data. Its features include asynchronous and synchronous querying and saving; + * caching of queries; transactions; and datatype mapping. + */ + +/************************************************************************** + Classes derived from RemoteStore should implement the following three + methods, which are each described in the documentation below: + _setupQueryRequest(result, requestKw) + _resultToQueryData(responseData) + _setupSaveRequest(saveKeywordArgs, requestKw) + + Data Consistency Guarantees + + * if two references to the same item are obtained (e.g. from two different query results) any changes to one item will be reflected in the other item reference. + * If an item has changed on the server and the item is retrieved via a new query, any previously obtained references to the item will (silently) reflect these new values. + * However, any uncommitted changes will not be "overwritten". + * If server queries are made while there are uncommitted changes, no attempt is made to evaluate whether the modifications would change the query result, e.g. add any uncommitted new items that match the query. + * However, uncomitted deleted items are removed from the query result. + * The transaction isolation level is equivalent to JDBC's "Read Committed": + each store instance is treated as separate transaction; since there is no row or table locking so nonrepeatable and phantom reads are possible. + + Memory Usage + + Because Javascript doesn't support weak references or user-defined finalize methods, there is a tradeoff between data consistency and memory usage. + In order to implement the above consistency guarantees (and to provide caching), RemoteStore remembers all the queries and items retrieved. + To reduce memory consumption, use the method forgetResults(query); + + Store assumptions + + RemoteStore makes some assumptions about the nature of the remote store, things may break if these aren't true: + * that the items contained in a query response include all the attributes of the item (e.g. all the columns of a row). + (to fix: changes need to record add and removes and fix self._data[key] = [ attributeDict, refCount]; ) + * the query result may contain references to items that are not available to the client; use isItem() to test for the presence of the item. + * that modification to an item's attributes won't change it's primary key. + +**************************************************************************/ + +/* dojo.data API issues to resolve: + * save should returns a Deferred, might want to add keyword argument with 'sync' + */ + +dojo.experimental("dojo.data.core.RemoteStore"); + +dojo.lang.declare("dojo.data.core.RemoteStore", [dojo.data.core.Read, dojo.data.core.Write], { + + _datatypeMap: { + //map datatype strings to constructor function + }, + + //set to customize json serialization + _jsonRegistry: dojo.json.jsonRegistry, + + initializer: function(/* object */ kwArgs) { + if (!kwArgs) { + kwArgs = {}; + } + this._serverQueryUrl = kwArgs.queryUrl || ""; + this._serverSaveUrl = kwArgs.saveUrl || ""; + + this._deleted = {}; // deleted items {id: 1} + this._changed = {}; // {id: {attr: [new values]}} // [] if attribute is removed + this._added = {}; // {id: 1} list of added items + this._results = {}; // {query: [ id1, ]}; // todo: make MRUDict of queries + /* data is a dictionary that conforms to this format: + { id-string: { attribute-string: [ value1, value2 ] } } + where value is either an atomic JSON data type or + { 'id': string } for references to items + or + { 'type': 'name', 'value': 'value' } for user-defined datatypes + */ + this._data = {}; // {id: [values, refcount]} // todo: handle refcount + this._numItems = 0; + }, + + _setupQueryRequest: function(/* dojo.data.core.Result */ result, /* object */ requestKw) { + /* summary: + * Classes derived from RemoteStore should override this method to + * provide their own implementations. + * This function prepares the query request by populating requestKw, + * an associative array that will be passed to dojo.io.bind. + */ + result.query = result.query || ""; + requestKw.url = this._serverQueryUrl + encodeURIComponent(result.query); + requestKw.method = 'get'; + requestKw.mimetype = "text/json"; + }, + + _resultToQueryMetadata: function(/* varies */ serverResponseData) { + /* summary: + * Classes derived from RemoteStore should override this method to + * provide their own implementations. + * Converts the server response data into the resultMetadata object + * that will be returned to the caller. + * returns: + * This simple default implementation just returns the entire raw + * serverResponseData, allowing the caller complete access to the + * raw response data and metadata. + */ + return serverResponseData; + }, + + _resultToQueryData: function(/* varies */ serverResponseData) { + /* summary: + * Classes derived from RemoteStore should override this method to + * provide their own implementations. + * Converts the server response data into the internal data structure + * used by RemoteStore. + * returns: + * The RemoteStore implementation requires _resultToQueryData() to + * return an object that looks like: + * {item1-identifier-string: { + * attribute1-string: [ value1, value2, ... ], + * attribute2-string: [ value3, value4, ... ], + * ... + * }, + * item2-identifier-string: { + * attribute1-string: [ value10, value11, ... ], + * attribute2-string: [ value12, value13, ... ], + * ... + * } + * } + * where value is either an atomic JSON data type or + * {'id': string } for references to items + * or + * {'type': 'name', 'value': 'value' } for user-defined datatypes + * data: + * This simple default implementation assumes that the *serverResponseData* + * argument is an object that looks like: + * { data:{ ... }, format:'format identifier', other metadata } + * + */ + return serverResponseData.data; + }, + + _remoteToLocalValues: function(/* object */ attributes) { + for (var key in attributes) { + var values = attributes[key]; + for (var i = 0; i < values.length; i++) { + var value = values[i]; + var type = value.datatype || value.type; + if (type) { + // todo: better error handling? + var localValue = value.value; + if (this._datatypeMap[type]) + localValue = this._datatypeMap[type](value); + values[i] = localValue; + } + } + } + return attributes; // object (attributes argument, modified in-place) + }, + + _queryToQueryKey: function(query) { + /* summary: + * Convert the query to a string that uniquely represents this query. + * (Used by the query cache.) + */ + if (typeof query == "string") + return query; + else + return dojo.json.serialize(query); + }, + + _assertIsItem: function(/* item */ item) { + if (!this.isItem(item)) { + throw new Error("dojo.data.RemoteStore: a function was passed an item argument that was not an item"); + } + }, + + get: function(/* item */ item, /* attribute || string */ attribute, /* value? */ defaultValue) { + // summary: See dojo.data.core.Read.get() + var valueArray = this.getValues(item, attribute); + if (valueArray.length == 0) { + return defaultValue; + } + return valueArray[0]; // value + }, + + getValues: function(/* item */ item, /* attribute || string */ attribute) { + // summary: See dojo.data.core.Read.getValues() + var itemIdentity = this.getIdentity(item); + this._assertIsItem(itemIdentity); + var changes = this._changed[itemIdentity]; + if (changes) { + var newvalues = changes[attribute]; + if (newvalues !== undefined) { + return newvalues; // Array + } + else { + return []; // Array + } + } + // return item.atts[attribute]; + return this._data[itemIdentity][0][attribute]; // Array + }, + + getAttributes: function(/* item */ item) { + // summary: See dojo.data.core.Read.getAttributes() + var itemIdentity = this.getIdentity(item); + if (!itemIdentity) + return undefined; //todo: raise exception + + var atts = []; + //var attrDict = item.attrs; + var attrDict = this._data[itemIdentity][0]; + for (var att in attrDict) { + atts.push(att); + } + return atts; // Array + }, + + hasAttribute: function(/* item */ item, /* attribute || string */ attribute) { + // summary: See dojo.data.core.Read.hasAttribute() + var valueArray = this.getValues(item, attribute); + return valueArray.length ? true : false; // Boolean + }, + + containsValue: function(/* item */ item, /* attribute || string */ attribute, /* value */ value) { + // summary: See dojo.data.core.Read.containsValue() + var valueArray = this.getValues(item, attribute); + for (var i=0; i < valueArray.length; i++) { + if (valueArray[i] == value) { + return true; // Boolean + } + } + return false; // Boolean + }, + + isItem: function(/* anything */ something) { + // summary: See dojo.data.core.Read.isItem() + if (!something) { return false; } + var itemIdentity = something; + // var id = something.id ? something.id : something; + // if (!id) { return false; } + if (this._deleted[itemIdentity]) { return false; } //todo: do this? + if (this._data[itemIdentity]) { return true; } + if (this._added[itemIdentity]) { return true; } + return false; // Boolean + }, + + find: function(/* object? || dojo.data.core.Result */ keywordArgs) { + // summary: See dojo.data.core.Read.find() + /* description: + * In addition to the keywordArgs parameters described in the + * dojo.data.core.Read.find() documentation, the keywordArgs for + * the RemoteStore find() method may include a bindArgs parameter, + * which the RemoteStore will pass to dojo.io.bind when it sends + * the query. The bindArgs parameter should be a keyword argument + * object, as described in the dojo.io.bind documentation. + */ + var result = null; + if (keywordArgs instanceof dojo.data.core.Result) { + result = keywordArgs; + result.store = this; + } else { + result = new dojo.data.core.Result(keywordArgs, this); + } + var query = result.query; + + //todo: use this._results to implement caching + var self = this; + var bindfunc = function(type, data, evt) { + var scope = result.scope || dj_global; + if(type == "load") { + //dojo.debug("loaded 1 " + dojo.json.serialize(data) ); + result.resultMetadata = self._resultToQueryMetadata(data); + var dataDict = self._resultToQueryData(data); + //dojo.debug("loaded 2 " + dojo.json.serialize(dataDict) ); + if (result.onbegin) { + result.onbegin.call(scope, result); + } + var count = 0; + var resultData = []; + var newItemCount = 0; + for (var key in dataDict) { + if (result._aborted) { + break; + } + if (!self._deleted[key]) { //skip deleted items + //todo if in _added, remove from _added + var values = dataDict[key]; + var attributeDict = self._remoteToLocalValues(values); + var existingValue = self._data[key]; + var refCount = 1; + if (existingValue) { + refCount = ++existingValue[1]; //increment ref count + } else { + newItemCount++; + } + //note: if the item already exists, we replace the item with latest set of attributes + //this assumes queries always return complete records + self._data[key] = [ attributeDict, refCount]; + resultData.push(key); + count++; + if (result.onnext) { + result.onnext.call(scope, key, result); + } + } + } + self._results[self._queryToQueryKey(query)] = resultData; + self._numItems += newItemCount; + + result.length = count; + if (result.saveResult) { + result.items = resultData; + } + if (!result._aborted && result.oncompleted) { + result.oncompleted.call(scope, result); + } + } else if(type == "error" || type == 'timeout') { + // here, "data" is our error object + //todo: how to handle timeout? + dojo.debug("find error: " + dojo.json.serialize(data)); + if (result.onerror) { + result.onerror.call(scope, data); + } + } + }; + + var bindKw = keywordArgs.bindArgs || {}; + bindKw.sync = result.sync; + bindKw.handle = bindfunc; + + this._setupQueryRequest(result, bindKw); + var request = dojo.io.bind(bindKw); + //todo: error if not bind success + //dojo.debug( "bind success " + request.bindSuccess); + result._abortFunc = request.abort; + return result; + }, + + getIdentity: function(item) { + // summary: See dojo.data.core.Read.getIdentity() + if (!this.isItem(item)) { + return null; + } + return (item.id ? item.id : item); // Identity + }, + +/* + findByIdentity: function(id) { + var item = this._latestData[id]; + var idQuery = "/" + "*[.='"+id+"']"; + //if (!item) item = this.find(idQuery, {async=0}); //todo: support bind(async=0) + if (item) + return new _Item(id, item, this); + return null; + }, +*/ + +/**** +Write API +***/ + newItem: function(/* object? */ attributes, /* object? */ keywordArgs) { + var itemIdentity = keywordArgs['identity']; + if (this._deleted[itemIdentity]) { + delete this._deleted[itemIdentity]; + } else { + this._added[itemIdentity] = 1; + //todo? this._numItems++; ?? but its not in this._data + } + if (attributes) { + // FIXME: + for (var attribute in attributes) { + var valueOrArrayOfValues = attributes[attribute]; + if (dojo.lang.isArray(valueOrArrayOfValues)) { + this.setValues(itemIdentity, attribute, valueOrArrayOfValues); + } else { + this.set(itemIdentity, attribute, valueOrArrayOfValues); + } + } + } + return { id: itemIdentity }; + }, + + deleteItem: function(/* item */ item) { + var identity = this.getIdentity(item); + if (!identity) { + return false; + } + + if (this._added[identity]) { + delete this._added[identity]; + } else { + this._deleted[identity] = 1; + //todo? this._numItems--; ?? but its still in this._data + } + + if (this._changed[identity]) { + delete this._changed[identity]; + } + return true; + }, + + setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) { + var identity = this.getIdentity(item); + if (!identity) { + return undefined; //todo: raise exception + } + + var changes = this._changed[identity]; + if (!changes) { + changes = {} + this._changed[identity] = changes; + } + changes[attribute] = values; + return true; // boolean + }, + + set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) { + return this.setValues(item, attribute, [value]); + }, + + unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) { + return this.setValues(item, attribute, []); + }, + + _initChanges: function() { + this._deleted = {}; + this._changed = {}; + this._added = {}; + }, + + _setupSaveRequest: function(saveKeywordArgs, requestKw) { + /* summary: + * This function prepares the save request by populating requestKw, + * an associative array that will be passed to dojo.io.bind. + */ + requestKw.url = this._serverSaveUrl; + requestKw.method = 'post'; + requestKw.mimetype = "text/plain"; + var deleted = []; + for (var key in this._deleted) { + deleted.push(key); + } + //don't need _added in saveStruct, changed covers that info + var saveStruct = {'changed': this._changed, 'deleted': deleted }; + var oldRegistry = dojo.json.jsonRegistry; + dojo.json.jsonRegistry = this._jsonRegistry; + var jsonString = dojo.json.serialize(saveStruct); + dojo.json.jsonRegistry = oldRegistry; + requestKw.postContent = jsonString; + }, + + save: function(/* object? */ keywordArgs) { + /* summary: + * Saves all the changes that have been made. + * keywordArgs: + * The optional keywordArgs parameter may contain 'sync' to specify + * whether the save operation is asynchronous or not. The default is + * asynchronous. + * examples: + * store.save(); + * store.save({sync:true}); + * store.save({sync:false}); + */ + keywordArgs = keywordArgs || {}; + var result = new dojo.Deferred(); + var self = this; + + var bindfunc = function(type, data, evt) { + if(type == "load"){ + if (result.fired == 1) { + //it seems that mysteriously "load" sometime + //gets called after "error" + //so check if an error has already occurred + //and stop if it has + return; + } + //update this._data upon save + var key = null; + for (key in self._added) { + if (!self._data[key]) + self._data[key] = [{} , 1]; + } + for (key in self._changed) { + var existing = self._data[key]; + var changes = self._changed[key]; + if (existing) { + existing[0] = changes; + } else { + self._data[key] = [changes, 1]; + } + } + for (key in self._deleted) { + if (self._data[key]) { + delete self._data[key]; + } + } + self._initChanges(); + result.callback(true); //todo: what result to pass? + } else if(type == "error" || type == 'timeout'){ + result.errback(data); //todo: how to handle timeout + } + }; + + var bindKw = { sync: keywordArgs["sync"], handle: bindfunc }; + this._setupSaveRequest(keywordArgs, bindKw); + var request = dojo.io.bind(bindKw); + result.canceller = function(deferred) { request.abort(); }; + + return result; + }, + + revert: function() { + this._initChanges(); + return true; + }, + + isDirty: function(/*item?*/ item) { + if (item) { + // return true if this item is dirty + var identity = item.id || item; + return this._deleted[identity] || this._changed[identity]; + } else { + // return true if any item is dirty + var key = null; + for (key in this._changed) { + return true; + } + for (key in this._deleted) { + return true; + } + for (key in this._added) { + return true; + } + + return false; + } + }, + +/** +additional public methods +*/ + createReference: function(idstring) { + return { id : idstring }; + }, + + getSize: function() { + return this._numItems; + }, + + forgetResults: function(query) { + var queryKey = this._queryToQueryKey(query); + var results = this._results[queryKey]; + if (!results) return false; + + var removed = 0; + for (var i = 0; i < results.length; i++) { + var key = results[i]; + var existingValue = this._data[key]; + if (existingValue[1] <= 1) { + delete this._data[key]; + removed++; + } + else + existingValue[1] = --existingValue[1]; + } + delete this._results[queryKey]; + this._numItems -= removed; + return true; + } +}); + + + diff --git a/source/web/scripts/ajax/dojo/src/data/core/Result.js b/source/web/scripts/ajax/dojo/src/data/core/Result.js new file mode 100644 index 0000000000..da6a4e63d9 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/core/Result.js @@ -0,0 +1,58 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.core.Result"); +dojo.require("dojo.lang.declare"); +dojo.require("dojo.experimental"); + +/* summary: + * Instances of dojo.data.core.Result are returned by the find() method + * of datastores that implement the dojo.data.core.Read API. For more + * documentation, see the find() method on dojo.data.core.Read. + */ +dojo.experimental("dojo.data.core.Result"); + +dojo.declare("dojo.data.core.Result", null, { + initializer: function(/* object */ keywordArgs, /* dojo.data.core.Read */ store) { + this.fromKwArgs(keywordArgs || {}); + this.items = null; + this.resultMetadata = null; + this.length = -1; // -1 until completion + this.store = store; + + this._aborted = false; + this._abortFunc = null; + }, + + /* Whether the request should be made synchronously. + * We default to true if there's no {sync:false} property in the keywordArgs + * in the initializer for a given instance of dojo.data.core.Result. + */ + sync: true, + + //timeout: function(type){ }, todo: support this + //timeoutSeconds: 0, todo: support this + + // the abort method needs to be filled in by the transport that accepts the + // bind() request + abort: function() { + this._aborted = true; + if (this._abortFunc) { + this._abortFunc(); + } + }, + + fromKwArgs: function(/* object */ kwArgs) { + if (typeof kwArgs.saveResult == "undefined") { + this.saveResult = kwArgs.onnext ? false : true; + } + dojo.lang.mixin(this, kwArgs); + } +}); diff --git a/source/web/scripts/ajax/dojo/src/data/core/Write.js b/source/web/scripts/ajax/dojo/src/data/core/Write.js new file mode 100644 index 0000000000..24df296a2e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/core/Write.js @@ -0,0 +1,169 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.core.Write"); +dojo.require("dojo.data.core.Read"); +dojo.require("dojo.lang.declare"); +dojo.require("dojo.experimental"); + +/* summary: + * This is an abstract API that data provider implementations conform to. + * This file defines methods signatures and intentionally leaves all the + * methods unimplemented. + */ +dojo.experimental("dojo.data.core.Write"); + +dojo.declare("dojo.data.core.Write", dojo.data.core.Read, { + newItem: function(/* object? */ keywordArgs) { + /* summary: + * Returns a newly created item. Sets the attributes of the new + * item based on the *keywordArgs* provided. + */ + + /* exceptions: + * Throws an exception if *keywordArgs* is a string or a number or + * anything other than a simple anonymous object. + * examples: + * var kermit = store.newItem({name: "Kermit", color:[blue, green]}); + */ + var newItem; + dojo.unimplemented('dojo.data.core.Write.newItem'); + return newItem; // item + }, + + deleteItem: function(/* item */ item) { + /* summary: + * Deletes an item from the store. + */ + + /* exceptions: + * Throws an exception if the argument *item* is not an item + * (if store.isItem(item) returns false). + * examples: + * var success = store.deleteItem(kermit); + */ + dojo.unimplemented('dojo.data.core.Write.deleteItem'); + return false; // boolean + }, + + set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) { + /* summary: + * Sets the value of an attribute on an item. + * Replaces any previous value or values. + */ + + /* exceptions: + * Throws an exception if *item* is not an item, or if *attribute* + * is neither an attribute object or a string. + * Throws an exception if *value* is undefined. + * examples: + * var success = store.set(kermit, "color", "green"); + */ + dojo.unimplemented('dojo.data.core.Write.set'); + return false; // boolean + }, + + setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) { + /* summary: + * Adds each value in the *values* array as a value of the given + * attribute on the given item. + * Replaces any previous value or values. + * Calling store.setValues(x, y, []) (with *values* as an empty array) has + * the same effect as calling store.clear(x, y). + */ + + /* exceptions: + * Throws an exception if *values* is not an array, if *item* is not an + * item, or if *attribute* is neither an attribute object or a string. + * examples: + * var success = store.setValues(kermit, "color", ["green", "aqua"]); + * success = store.setValues(kermit, "color", []); + * if (success) {assert(!store.hasAttribute(kermit, "color"));} + */ + dojo.unimplemented('dojo.data.core.Write.setValues'); + return false; // boolean + }, + + unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) { + /* summary: + * Deletes all the values of an attribute on an item. + */ + + /* exceptions: + * Throws an exception if *item* is not an item, or if *attribute* + * is neither an attribute object or a string. + * examples: + * var success = store.unsetAttribute(kermit, "color"); + * if (success) {assert(!store.hasAttribute(kermit, "color"));} + */ + dojo.unimplemented('dojo.data.core.Write.clear'); + return false; // boolean + }, + + save: function() { + /* summary: + * Saves to the server all the changes that have been made locally. + * The save operation may take some time. By default the save will + * be done synchronously, before the call returns. The caller may + * be request an asynchronous save by passing {async: true}. + * If the caller requests an asynchronous save, the data store may do + * either a synchronous or asynchronous save, whichever it prefers. + * Different data store implementations may take additional optional + * parameters. + * description: + * ISSUE - + * Should the async save take a callback, like this: + * store.save({sync: false, onComplete: callback}); + * Or should the async save return a Deferred, like this: + * var deferred = store.save({sync: false}); + * deferred.addCallbacks(successCallback, errorCallback); + * Or should save() return boolean, like this: + * var success = store.save(); + */ + + /* examples: + * var success = store.save(); + * var success = store.save({sync: false}); + */ + dojo.unimplemented('dojo.data.core.Write.save'); + return false; // boolean + }, + + revert: function() { + /* summary: + * Discards any unsaved changes. + */ + + /* examples: + * var success = store.revert(); + */ + dojo.unimplemented('dojo.data.core.Write.revert'); + return false; // boolean + }, + + isDirty: function(/* item? */ item) { + /* summary: + * Given an item, isDirty() returns true if the item has been modified + * since the last save(). If isDirty() is called with no *item* argument, + * then this method returns true if any item has been modified since + * the last save(). + */ + + /* exceptions: + * Throws an exception if isDirty() is passed an argument and the + * argument is not an item. + * examples: + * var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty + * var trueOrFalse = store.isDirty(); // true if any item is dirty + */ + dojo.unimplemented('dojo.data.core.Write.isDirty'); + return false; // boolean + } +}); diff --git a/source/web/scripts/ajax/dojo/src/data/old/Attribute.js b/source/web/scripts/ajax/dojo/src/data/old/Attribute.js new file mode 100644 index 0000000000..3c0a4ceb10 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/Attribute.js @@ -0,0 +1,62 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.Attribute"); +dojo.require("dojo.data.old.Item"); +dojo.require("dojo.lang.assert"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.Attribute = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ attributeId) { + /** + * summary: + * An Attribute object represents something like a column in + * a relational database. + */ + dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true}); + dojo.lang.assertType(attributeId, String); + dojo.data.old.Item.call(this, dataProvider); + this._attributeId = attributeId; +}; +dojo.inherits(dojo.data.old.Attribute, dojo.data.old.Item); + +// ------------------------------------------------------------------- +// Public instance methods +// ------------------------------------------------------------------- +dojo.data.old.Attribute.prototype.toString = function() { + return this._attributeId; // string +}; + +dojo.data.old.Attribute.prototype.getAttributeId = function() { + /** + * summary: + * Returns the string token that uniquely identifies this + * attribute within the context of a data provider. + * For a data provider that accesses relational databases, + * typical attributeIds might be tokens like "name", "age", + * "ssn", or "dept_key". + */ + return this._attributeId; // string +}; + +dojo.data.old.Attribute.prototype.getType = function() { + /** + * summary: Returns the data type of the values of this attribute. + */ + return this.get('type'); // dojo.data.old.Type or null +}; + +dojo.data.old.Attribute.prototype.setType = function(/* dojo.data.old.Type or null */ type) { + /** + * summary: Sets the data type for this attribute. + */ + this.set('type', type); +}; diff --git a/source/web/scripts/ajax/dojo/src/data/old/Item.js b/source/web/scripts/ajax/dojo/src/data/old/Item.js new file mode 100644 index 0000000000..0a2df32a0a --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/Item.js @@ -0,0 +1,327 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.Item"); +dojo.require("dojo.data.old.Observable"); +dojo.require("dojo.data.old.Value"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.lang.assert"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.Item = function(/* dojo.data.old.provider.Base */ dataProvider) { + /** + * summary: + * An Item has attributes and attribute values, sort of like + * a record in a database, or a 'struct' in C. Instances of + * the Item class know how to store and retrieve their + * attribute values. + */ + dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true}); + dojo.data.old.Observable.call(this); + this._dataProvider = dataProvider; + this._dictionaryOfAttributeValues = {}; +}; +dojo.inherits(dojo.data.old.Item, dojo.data.old.Observable); + +// ------------------------------------------------------------------- +// Public class methods +// ------------------------------------------------------------------- +dojo.data.old.Item.compare = function(/* dojo.data.old.Item */ itemOne, /* dojo.data.old.Item */ itemTwo) { + /** + * summary: + * Given two Items to compare, this method returns 0, 1, or -1. + * This method is designed to be used by sorting routines, like + * the JavaScript built-in Array sort() method. + * + * Example: + *
+	 *   var a = dataProvider.newItem("kermit");
+	 *   var b = dataProvider.newItem("elmo");
+	 *   var c = dataProvider.newItem("grover");
+	 *   var array = new Array(a, b, c);
+	 *   array.sort(dojo.data.old.Item.compare);
+	 * 
+ */ + dojo.lang.assertType(itemOne, dojo.data.old.Item); + if (!dojo.lang.isOfType(itemTwo, dojo.data.old.Item)) { + return -1; + } + var nameOne = itemOne.getName(); + var nameTwo = itemTwo.getName(); + if (nameOne == nameTwo) { + var attributeArrayOne = itemOne.getAttributes(); + var attributeArrayTwo = itemTwo.getAttributes(); + if (attributeArrayOne.length != attributeArrayTwo.length) { + if (attributeArrayOne.length > attributeArrayTwo.length) { + return 1; + } else { + return -1; + } + } + for (var i in attributeArrayOne) { + var attribute = attributeArrayOne[i]; + var arrayOfValuesOne = itemOne.getValues(attribute); + var arrayOfValuesTwo = itemTwo.getValues(attribute); + dojo.lang.assert(arrayOfValuesOne && (arrayOfValuesOne.length > 0)); + if (!arrayOfValuesTwo) { + return 1; + } + if (arrayOfValuesOne.length != arrayOfValuesTwo.length) { + if (arrayOfValuesOne.length > arrayOfValuesTwo.length) { + return 1; + } else { + return -1; + } + } + for (var j in arrayOfValuesOne) { + var value = arrayOfValuesOne[j]; + if (!itemTwo.hasAttributeValue(value)) { + return 1; + } + } + return 0; + } + } else { + if (nameOne > nameTwo) { + return 1; + } else { + return -1; // 0, 1, or -1 + } + } +}; + +// ------------------------------------------------------------------- +// Public instance methods +// ------------------------------------------------------------------- +dojo.data.old.Item.prototype.toString = function() { + /** + * Returns a simple string representation of the item. + */ + var arrayOfStrings = []; + var attributes = this.getAttributes(); + for (var i in attributes) { + var attribute = attributes[i]; + var arrayOfValues = this.getValues(attribute); + var valueString; + if (arrayOfValues.length == 1) { + valueString = arrayOfValues[0]; + } else { + valueString = '['; + valueString += arrayOfValues.join(', '); + valueString += ']'; + } + arrayOfStrings.push(' ' + attribute + ': ' + valueString); + } + var returnString = '{ '; + returnString += arrayOfStrings.join(',\n'); + returnString += ' }'; + return returnString; // string +}; + +dojo.data.old.Item.prototype.compare = function(/* dojo.data.old.Item */ otherItem) { + /** + * summary: Compares this Item to another Item, and returns 0, 1, or -1. + */ + return dojo.data.old.Item.compare(this, otherItem); // 0, 1, or -1 +}; + +dojo.data.old.Item.prototype.isEqual = function(/* dojo.data.old.Item */ otherItem) { + /** + * summary: Returns true if this Item is equal to the otherItem, or false otherwise. + */ + return (this.compare(otherItem) == 0); // boolean +}; + +dojo.data.old.Item.prototype.getName = function() { + return this.get('name'); +}; + +dojo.data.old.Item.prototype.get = function(/* string or dojo.data.old.Attribute */ attributeId) { + /** + * summary: Returns a single literal value, like "foo" or 33. + */ + // dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]); + var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId]; + if (dojo.lang.isUndefined(literalOrValueOrArray)) { + return null; // null + } + if (literalOrValueOrArray instanceof dojo.data.old.Value) { + return literalOrValueOrArray.getValue(); // literal + } + if (dojo.lang.isArray(literalOrValueOrArray)) { + var dojoDataValue = literalOrValueOrArray[0]; + return dojoDataValue.getValue(); // literal + } + return literalOrValueOrArray; // literal +}; + +dojo.data.old.Item.prototype.getValue = function(/* string or dojo.data.old.Attribute */ attributeId) { + /** + * summary: Returns a single instance of dojo.data.old.Value. + */ + // dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]); + var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId]; + if (dojo.lang.isUndefined(literalOrValueOrArray)) { + return null; // null + } + if (literalOrValueOrArray instanceof dojo.data.old.Value) { + return literalOrValueOrArray; // dojo.data.old.Value + } + if (dojo.lang.isArray(literalOrValueOrArray)) { + var dojoDataValue = literalOrValueOrArray[0]; + return dojoDataValue; // dojo.data.old.Value + } + var literal = literalOrValueOrArray; + dojoDataValue = new dojo.data.old.Value(literal); + this._dictionaryOfAttributeValues[attributeId] = dojoDataValue; + return dojoDataValue; // dojo.data.old.Value +}; + +dojo.data.old.Item.prototype.getValues = function(/* string or dojo.data.old.Attribute */ attributeId) { + /** + * summary: Returns an array of dojo.data.old.Value objects. + */ + // dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]); + var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId]; + if (dojo.lang.isUndefined(literalOrValueOrArray)) { + return null; // null + } + if (literalOrValueOrArray instanceof dojo.data.old.Value) { + var array = [literalOrValueOrArray]; + this._dictionaryOfAttributeValues[attributeId] = array; + return array; // Array + } + if (dojo.lang.isArray(literalOrValueOrArray)) { + return literalOrValueOrArray; // Array + } + var literal = literalOrValueOrArray; + var dojoDataValue = new dojo.data.old.Value(literal); + array = [dojoDataValue]; + this._dictionaryOfAttributeValues[attributeId] = array; + return array; // Array +}; + +dojo.data.old.Item.prototype.load = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) { + /** + * summary: + * Used for loading an attribute value into an item when + * the item is first being loaded into memory from some + * data store (such as a file). + */ + // dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]); + this._dataProvider.registerAttribute(attributeId); + var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId]; + if (dojo.lang.isUndefined(literalOrValueOrArray)) { + this._dictionaryOfAttributeValues[attributeId] = value; + return; + } + if (!(value instanceof dojo.data.old.Value)) { + value = new dojo.data.old.Value(value); + } + if (literalOrValueOrArray instanceof dojo.data.old.Value) { + var array = [literalOrValueOrArray, value]; + this._dictionaryOfAttributeValues[attributeId] = array; + return; + } + if (dojo.lang.isArray(literalOrValueOrArray)) { + literalOrValueOrArray.push(value); + return; + } + var literal = literalOrValueOrArray; + var dojoDataValue = new dojo.data.old.Value(literal); + array = [dojoDataValue, value]; + this._dictionaryOfAttributeValues[attributeId] = array; +}; + +dojo.data.old.Item.prototype.set = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) { + /** + * summary: + * Used for setting an attribute value as a result of a + * user action. + */ + // dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]); + this._dataProvider.registerAttribute(attributeId); + this._dictionaryOfAttributeValues[attributeId] = value; + this._dataProvider.noteChange(this, attributeId, value); +}; + +dojo.data.old.Item.prototype.setValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* dojo.data.old.Value */ value) { + this.set(attributeId, value); +}; + +dojo.data.old.Item.prototype.addValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) { + /** + * summary: + * Used for adding an attribute value as a result of a + * user action. + */ + this.load(attributeId, value); + this._dataProvider.noteChange(this, attributeId, value); +}; + +dojo.data.old.Item.prototype.setValues = function(/* string or dojo.data.old.Attribute */ attributeId, /* Array */ arrayOfValues) { + /** + * summary: + * Used for setting an array of attribute values as a result of a + * user action. + */ + // dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]); + dojo.lang.assertType(arrayOfValues, Array); + this._dataProvider.registerAttribute(attributeId); + var finalArray = []; + this._dictionaryOfAttributeValues[attributeId] = finalArray; + for (var i in arrayOfValues) { + var value = arrayOfValues[i]; + if (!(value instanceof dojo.data.old.Value)) { + value = new dojo.data.old.Value(value); + } + finalArray.push(value); + this._dataProvider.noteChange(this, attributeId, value); + } +}; + +dojo.data.old.Item.prototype.getAttributes = function() { + /** + * summary: + * Returns an array containing all of the attributes for which + * this item has attribute values. + */ + var arrayOfAttributes = []; + for (var key in this._dictionaryOfAttributeValues) { + arrayOfAttributes.push(this._dataProvider.getAttribute(key)); + } + return arrayOfAttributes; // Array +}; + +dojo.data.old.Item.prototype.hasAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) { + /** + * summary: Returns true if the given attribute of the item has been assigned any value. + */ + // dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]); + return (attributeId in this._dictionaryOfAttributeValues); // boolean +}; + +dojo.data.old.Item.prototype.hasAttributeValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) { + /** + * summary: Returns true if the given attribute of the item has been assigned the given value. + */ + var arrayOfValues = this.getValues(attributeId); + for (var i in arrayOfValues) { + var candidateValue = arrayOfValues[i]; + if (candidateValue.isEqual(value)) { + return true; // boolean + } + } + return false; // boolean +}; + + diff --git a/source/web/scripts/ajax/dojo/src/data/old/Kind.js b/source/web/scripts/ajax/dojo/src/data/old/Kind.js new file mode 100644 index 0000000000..d0d33395df --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/Kind.js @@ -0,0 +1,28 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.Kind"); +dojo.require("dojo.data.old.Item"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.Kind = function(/* dojo.data.old.provider.Base */ dataProvider) { + /** + * summary: + * A Kind represents a kind of item. In the dojo data model + * the item Snoopy might belong to the 'kind' Dog, where in + * a Java program the object Snoopy would belong to the 'class' + * Dog, and in MySQL the record for Snoopy would be in the + * table Dog. + */ + dojo.data.old.Item.call(this, dataProvider); +}; +dojo.inherits(dojo.data.old.Kind, dojo.data.old.Item); diff --git a/source/web/scripts/ajax/dojo/src/data/old/Observable.js b/source/web/scripts/ajax/dojo/src/data/old/Observable.js new file mode 100644 index 0000000000..92ed9730f5 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/Observable.js @@ -0,0 +1,59 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.Observable"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.lang.assert"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.Observable = function() { +}; + +// ------------------------------------------------------------------- +// Public instance methods +// ------------------------------------------------------------------- +dojo.data.old.Observable.prototype.addObserver = function(/* object */ observer) { + /** + * summary: Registers an object as an observer of this item, + * so that the object will be notified when the item changes. + */ + dojo.lang.assertType(observer, Object); + dojo.lang.assertType(observer.observedObjectHasChanged, Function); + if (!this._arrayOfObservers) { + this._arrayOfObservers = []; + } + if (!dojo.lang.inArray(this._arrayOfObservers, observer)) { + this._arrayOfObservers.push(observer); + } +}; + +dojo.data.old.Observable.prototype.removeObserver = function(/* object */ observer) { + /** + * summary: Removes the observer registration for a previously + * registered object. + */ + if (!this._arrayOfObservers) { + return; + } + var index = dojo.lang.indexOf(this._arrayOfObservers, observer); + if (index != -1) { + this._arrayOfObservers.splice(index, 1); + } +}; + +dojo.data.old.Observable.prototype.getObservers = function() { + /** + * summary: Returns an array with all the observers of this item. + */ + return this._arrayOfObservers; // Array or undefined +}; + diff --git a/source/web/scripts/ajax/dojo/src/data/old/ResultSet.js b/source/web/scripts/ajax/dojo/src/data/old/ResultSet.js new file mode 100644 index 0000000000..14cee415cd --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/ResultSet.js @@ -0,0 +1,70 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.ResultSet"); +dojo.require("dojo.lang.assert"); +dojo.require("dojo.collections.Collections"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.ResultSet = function(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfItems) { + /** + * summary: + * A ResultSet holds a collection of Items. A data provider + * returns a ResultSet in reponse to a query. + * (The name "Result Set" comes from the MySQL terminology.) + */ + dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true}); + dojo.lang.assertType(arrayOfItems, Array, {optional: true}); + dojo.data.old.Observable.call(this); + this._dataProvider = dataProvider; + this._arrayOfItems = []; + if (arrayOfItems) { + this._arrayOfItems = arrayOfItems; + } +}; +dojo.inherits(dojo.data.old.ResultSet, dojo.data.old.Observable); + +// ------------------------------------------------------------------- +// Public instance methods +// ------------------------------------------------------------------- +dojo.data.old.ResultSet.prototype.toString = function() { + var returnString = this._arrayOfItems.join(', '); + return returnString; // string +}; + +dojo.data.old.ResultSet.prototype.toArray = function() { + return this._arrayOfItems; // Array +}; + +dojo.data.old.ResultSet.prototype.getIterator = function() { + return new dojo.collections.Iterator(this._arrayOfItems); +}; + +dojo.data.old.ResultSet.prototype.getLength = function() { + return this._arrayOfItems.length; // integer +}; + +dojo.data.old.ResultSet.prototype.getItemAt = function(/* numeric */ index) { + return this._arrayOfItems[index]; +}; + +dojo.data.old.ResultSet.prototype.indexOf = function(/* dojo.data.old.Item */ item) { + return dojo.lang.indexOf(this._arrayOfItems, item); // integer +}; + +dojo.data.old.ResultSet.prototype.contains = function(/* dojo.data.old.Item */ item) { + return dojo.lang.inArray(this._arrayOfItems, item); // boolean +}; + +dojo.data.old.ResultSet.prototype.getDataProvider = function() { + return this._dataProvider; // dojo.data.old.provider.Base +}; \ No newline at end of file diff --git a/source/web/scripts/ajax/dojo/src/data/old/Type.js b/source/web/scripts/ajax/dojo/src/data/old/Type.js new file mode 100644 index 0000000000..19f175583c --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/Type.js @@ -0,0 +1,25 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.Type"); +dojo.require("dojo.data.old.Item"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.Type = function(/* dojo.data.old.provider.Base */ dataProvider) { + /** + * summary: + * A Type represents a type of value, like Text, Number, Picture, + * or Varchar. + */ + dojo.data.old.Item.call(this, dataProvider); +}; +dojo.inherits(dojo.data.old.Type, dojo.data.old.Item); diff --git a/source/web/scripts/ajax/dojo/src/data/old/Value.js b/source/web/scripts/ajax/dojo/src/data/old/Value.js new file mode 100644 index 0000000000..7ff1f6fc3c --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/Value.js @@ -0,0 +1,55 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.Value"); +dojo.require("dojo.lang.assert"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.Value = function(/* anything */ value) { + /** + * summary: + * A Value represents a simple literal value (like "foo" or 334), + * or a reference value (a pointer to an Item). + */ + this._value = value; + this._type = null; +}; + +// ------------------------------------------------------------------- +// Public instance methods +// ------------------------------------------------------------------- +dojo.data.old.Value.prototype.toString = function() { + return this._value.toString(); // string +}; + +dojo.data.old.Value.prototype.getValue = function() { + /** + * summary: Returns the value itself. + */ + return this._value; // anything +}; + +dojo.data.old.Value.prototype.getType = function() { + /** + * summary: Returns the data type of the value. + */ + dojo.unimplemented('dojo.data.old.Value.prototype.getType'); + return this._type; // dojo.data.old.Type +}; + +dojo.data.old.Value.prototype.compare = function() { + dojo.unimplemented('dojo.data.old.Value.prototype.compare'); +}; + +dojo.data.old.Value.prototype.isEqual = function() { + dojo.unimplemented('dojo.data.old.Value.prototype.isEqual'); +}; diff --git a/source/web/scripts/ajax/dojo/src/data/old/__package__.js b/source/web/scripts/ajax/dojo/src/data/old/__package__.js new file mode 100644 index 0000000000..673d3e939b --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/__package__.js @@ -0,0 +1,22 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.require("dojo.experimental"); + +dojo.experimental("dojo.data.old.*"); +dojo.kwCompoundRequire({ + common: [ + "dojo.data.old.Item", + "dojo.data.old.ResultSet", + "dojo.data.old.provider.FlatFile" + ] +}); +dojo.provide("dojo.data.old.*"); + diff --git a/source/web/scripts/ajax/dojo/src/data/old/format/Csv.js b/source/web/scripts/ajax/dojo/src/data/old/format/Csv.js new file mode 100644 index 0000000000..44cfc78d38 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/format/Csv.js @@ -0,0 +1,112 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.format.Csv"); +dojo.require("dojo.lang.assert"); + + +dojo.data.old.format.Csv = new function() { + + // ------------------------------------------------------------------- + // Public functions + // ------------------------------------------------------------------- + this.getArrayStructureFromCsvFileContents = function(/* string */ csvFileContents) { + /** + * Given a string containing CSV records, this method parses + * the string and returns a data structure containing the parsed + * content. The data structure we return is an array of length + * R, where R is the number of rows (lines) in the CSV data. The + * return array contains one sub-array for each CSV line, and each + * sub-array contains C string values, where C is the number of + * columns in the CSV data. + * + * For example, given this CSV string as input: + *
+		 *   "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
+		 * 
+ * We will return this data structure: + *
+		 *   [["Title", "Year", "Producer"]
+		 *    ["Alien", "1979", "Ridley Scott"],  
+		 *    ["Blade Runner", "1982", "Ridley Scott"]]
+		 * 
+ */ + dojo.lang.assertType(csvFileContents, String); + + var lineEndingCharacters = new RegExp("\r\n|\n|\r"); + var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g'); + var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g'); + var doubleQuotes = new RegExp('""','g'); + var arrayOfOutputRecords = []; + + var arrayOfInputLines = csvFileContents.split(lineEndingCharacters); + for (var i in arrayOfInputLines) { + var singleLine = arrayOfInputLines[i]; + if (singleLine.length > 0) { + var listOfFields = singleLine.split(','); + var j = 0; + while (j < listOfFields.length) { + var space_field_space = listOfFields[j]; + var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace + var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace + var firstChar = field.charAt(0); + var lastChar = field.charAt(field.length - 1); + var secondToLastChar = field.charAt(field.length - 2); + var thirdToLastChar = field.charAt(field.length - 3); + if ((firstChar == '"') && + ((lastChar != '"') || + ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) { + if (j+1 === listOfFields.length) { + // alert("The last field in record " + i + " is corrupted:\n" + field); + return null; + } + var nextField = listOfFields[j+1]; + listOfFields[j] = field_space + ',' + nextField; + listOfFields.splice(j+1, 1); // delete element [j+1] from the list + } else { + if ((firstChar == '"') && (lastChar == '"')) { + field = field.slice(1, (field.length - 1)); // trim the " characters off the ends + field = field.replace(doubleQuotes, '"'); // replace "" with " + } + listOfFields[j] = field; + j += 1; + } + } + arrayOfOutputRecords.push(listOfFields); + } + } + return arrayOfOutputRecords; // Array + }; + + this.loadDataProviderFromFileContents = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ csvFileContents) { + dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base); + dojo.lang.assertType(csvFileContents, String); + var arrayOfArrays = this.getArrayStructureFromCsvFileContents(csvFileContents); + if (arrayOfArrays) { + var arrayOfKeys = arrayOfArrays[0]; + for (var i = 1; i < arrayOfArrays.length; ++i) { + var row = arrayOfArrays[i]; + var item = dataProvider.getNewItemToLoad(); + for (var j in row) { + var value = row[j]; + var key = arrayOfKeys[j]; + item.load(key, value); + } + } + } + }; + + this.getCsvStringFromResultSet = function(/* dojo.data.old.ResultSet */ resultSet) { + dojo.unimplemented('dojo.data.old.format.Csv.getCsvStringFromResultSet'); + var csvString = null; + return csvString; // String + }; + +}(); diff --git a/source/web/scripts/ajax/dojo/src/data/old/format/Json.js b/source/web/scripts/ajax/dojo/src/data/old/format/Json.js new file mode 100644 index 0000000000..50d54eda16 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/format/Json.js @@ -0,0 +1,103 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.format.Json"); +dojo.require("dojo.lang.assert"); + +dojo.data.old.format.Json = new function() { + + // ------------------------------------------------------------------- + // Public functions + // ------------------------------------------------------------------- + this.loadDataProviderFromFileContents = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ jsonFileContents) { + dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base); + dojo.lang.assertType(jsonFileContents, String); + var arrayOfJsonData = eval("(" + jsonFileContents + ")"); + this.loadDataProviderFromArrayOfJsonData(dataProvider, arrayOfJsonData); + }; + + this.loadDataProviderFromArrayOfJsonData = function(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) { + dojo.lang.assertType(arrayOfJsonData, Array, {optional: true}); + if (arrayOfJsonData && (arrayOfJsonData.length > 0)) { + var firstRow = arrayOfJsonData[0]; + dojo.lang.assertType(firstRow, [Array, "pureobject"]); + if (dojo.lang.isArray(firstRow)) { + _loadDataProviderFromArrayOfArrays(dataProvider, arrayOfJsonData); + } else { + dojo.lang.assertType(firstRow, "pureobject"); + _loadDataProviderFromArrayOfObjects(dataProvider, arrayOfJsonData); + } + } + }; + + this.getJsonStringFromResultSet = function(/* dojo.data.old.ResultSet */ resultSet) { + dojo.unimplemented('dojo.data.old.format.Json.getJsonStringFromResultSet'); + var jsonString = null; + return jsonString; // String + }; + + // ------------------------------------------------------------------- + // Private functions + // ------------------------------------------------------------------- + function _loadDataProviderFromArrayOfArrays(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) { + /** + * Example: + * var arrayOfJsonStates = [ + * [ "abbr", "population", "name" ] + * [ "WA", 5894121, "Washington" ], + * [ "WV", 1808344, "West Virginia" ], + * [ "WI", 5453896, "Wisconsin" ], + * [ "WY", 493782, "Wyoming" ] ]; + * this._loadFromArrayOfArrays(arrayOfJsonStates); + */ + var arrayOfKeys = arrayOfJsonData[0]; + for (var i = 1; i < arrayOfJsonData.length; ++i) { + var row = arrayOfJsonData[i]; + var item = dataProvider.getNewItemToLoad(); + for (var j in row) { + var value = row[j]; + var key = arrayOfKeys[j]; + item.load(key, value); + } + } + } + + function _loadDataProviderFromArrayOfObjects(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) { + /** + * Example: + * var arrayOfJsonStates = [ + * { abbr: "WA", name: "Washington" }, + * { abbr: "WV", name: "West Virginia" }, + * { abbr: "WI", name: "Wisconsin", song: "On, Wisconsin!" }, + * { abbr: "WY", name: "Wyoming", cities: ["Lander", "Cheyenne", "Laramie"] } ]; + * this._loadFromArrayOfArrays(arrayOfJsonStates); + */ + // dojo.debug("_loadDataProviderFromArrayOfObjects"); + for (var i in arrayOfJsonData) { + var row = arrayOfJsonData[i]; + var item = dataProvider.getNewItemToLoad(); + for (var key in row) { + var value = row[key]; + if (dojo.lang.isArray(value)) { + var arrayOfValues = value; + for (var j in arrayOfValues) { + value = arrayOfValues[j]; + item.load(key, value); + // dojo.debug("loaded: " + key + " = " + value); + } + } else { + item.load(key, value); + } + } + } + } + +}(); + diff --git a/source/web/scripts/ajax/dojo/src/data/old/provider/Base.js b/source/web/scripts/ajax/dojo/src/data/old/provider/Base.js new file mode 100644 index 0000000000..67509b0b5e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/provider/Base.js @@ -0,0 +1,183 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.provider.Base"); +dojo.require("dojo.lang.assert"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.provider.Base = function() { + /** + * summary: + * A Data Provider serves as a connection to some data source, + * like a relational database. This data provider Base class + * serves as an abstract superclass for other data provider + * classes. + */ + this._countOfNestedTransactions = 0; + this._changesInCurrentTransaction = null; +}; + +// ------------------------------------------------------------------- +// Public instance methods +// ------------------------------------------------------------------- +dojo.data.old.provider.Base.prototype.beginTransaction = function() { + /** + * Marks the beginning of a transaction. + * + * Each time you call beginTransaction() you open a new transaction, + * which you need to close later using endTransaction(). Transactions + * may be nested, but the beginTransaction and endTransaction calls + * always need to come in pairs. + */ + if (this._countOfNestedTransactions === 0) { + this._changesInCurrentTransaction = []; + } + this._countOfNestedTransactions += 1; +}; + +dojo.data.old.provider.Base.prototype.endTransaction = function() { + /** + * Marks the end of a transaction. + */ + this._countOfNestedTransactions -= 1; + dojo.lang.assert(this._countOfNestedTransactions >= 0); + + if (this._countOfNestedTransactions === 0) { + var listOfChangesMade = this._saveChanges(); + this._changesInCurrentTransaction = null; + if (listOfChangesMade.length > 0) { + // dojo.debug("endTransaction: " + listOfChangesMade.length + " changes made"); + this._notifyObserversOfChanges(listOfChangesMade); + } + } +}; + +dojo.data.old.provider.Base.prototype.getNewItemToLoad = function() { + return this._newItem(); // dojo.data.old.Item +}; + +dojo.data.old.provider.Base.prototype.newItem = function(/* string */ itemName) { + /** + * Creates a new item. + */ + dojo.lang.assertType(itemName, String, {optional: true}); + var item = this._newItem(); + if (itemName) { + item.set('name', itemName); + } + return item; // dojo.data.old.Item +}; + +dojo.data.old.provider.Base.prototype.newAttribute = function(/* string */ attributeId) { + /** + * Creates a new attribute. + */ + dojo.lang.assertType(attributeId, String, {optional: true}); + var attribute = this._newAttribute(attributeId); + return attribute; // dojo.data.old.Attribute +}; + +dojo.data.old.provider.Base.prototype.getAttribute = function(/* string */ attributeId) { + dojo.unimplemented('dojo.data.old.provider.Base'); + var attribute; + return attribute; // dojo.data.old.Attribute +}; + +dojo.data.old.provider.Base.prototype.getAttributes = function() { + dojo.unimplemented('dojo.data.old.provider.Base'); + return this._arrayOfAttributes; // Array +}; + +dojo.data.old.provider.Base.prototype.fetchArray = function() { + dojo.unimplemented('dojo.data.old.provider.Base'); + return []; // Array +}; + +dojo.data.old.provider.Base.prototype.fetchResultSet = function() { + dojo.unimplemented('dojo.data.old.provider.Base'); + var resultSet; + return resultSet; // dojo.data.old.ResultSet +}; + +dojo.data.old.provider.Base.prototype.noteChange = function(/* dojo.data.old.Item */ item, /* string or dojo.data.old.Attribute */ attribute, /* anything */ value) { + var change = {item: item, attribute: attribute, value: value}; + if (this._countOfNestedTransactions === 0) { + this.beginTransaction(); + this._changesInCurrentTransaction.push(change); + this.endTransaction(); + } else { + this._changesInCurrentTransaction.push(change); + } +}; + +dojo.data.old.provider.Base.prototype.addItemObserver = function(/* dojo.data.old.Item */ item, /* object */ observer) { + /** + * summary: Registers an object as an observer of an item, + * so that the object will be notified when the item changes. + */ + dojo.lang.assertType(item, dojo.data.old.Item); + item.addObserver(observer); +}; + +dojo.data.old.provider.Base.prototype.removeItemObserver = function(/* dojo.data.old.Item */ item, /* object */ observer) { + /** + * summary: Removes the observer registration for a previously + * registered object. + */ + dojo.lang.assertType(item, dojo.data.old.Item); + item.removeObserver(observer); +}; + +// ------------------------------------------------------------------- +// Private instance methods +// ------------------------------------------------------------------- +dojo.data.old.provider.Base.prototype._newItem = function() { + var item = new dojo.data.old.Item(this); + return item; // dojo.data.old.Item +}; + +dojo.data.old.provider.Base.prototype._newAttribute = function(/* String */ attributeId) { + var attribute = new dojo.data.old.Attribute(this); + return attribute; // dojo.data.old.Attribute +}; + +dojo.data.old.provider.Base.prototype._saveChanges = function() { + var arrayOfChangesMade = this._changesInCurrentTransaction; + return arrayOfChangesMade; // Array +}; + +dojo.data.old.provider.Base.prototype._notifyObserversOfChanges = function(/* Array */ arrayOfChanges) { + var arrayOfResultSets = this._getResultSets(); + for (var i in arrayOfChanges) { + var change = arrayOfChanges[i]; + var changedItem = change.item; + var arrayOfItemObservers = changedItem.getObservers(); + for (var j in arrayOfItemObservers) { + var observer = arrayOfItemObservers[j]; + observer.observedObjectHasChanged(changedItem, change); + } + for (var k in arrayOfResultSets) { + var resultSet = arrayOfResultSets[k]; + var arrayOfResultSetObservers = resultSet.getObservers(); + for (var m in arrayOfResultSetObservers) { + observer = arrayOfResultSetObservers[m]; + observer.observedObjectHasChanged(resultSet, change); + } + } + } +}; + +dojo.data.old.provider.Base.prototype._getResultSets = function() { + dojo.unimplemented('dojo.data.old.provider.Base'); + return []; // Array +}; + diff --git a/source/web/scripts/ajax/dojo/src/data/old/provider/Delicious.js b/source/web/scripts/ajax/dojo/src/data/old/provider/Delicious.js new file mode 100644 index 0000000000..d5f354b9c9 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/provider/Delicious.js @@ -0,0 +1,85 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.provider.Delicious"); +dojo.require("dojo.data.old.provider.FlatFile"); +dojo.require("dojo.data.old.format.Json"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.provider.Delicious = function() { + /** + * summary: + * The Delicious Data Provider can be used to take data from + * del.icio.us and make it available as dojo.data.old.Items + * In order to use the Delicious Data Provider, you need + * to have loaded a script tag that looks like this: + * + */ + dojo.data.old.provider.FlatFile.call(this); + // Delicious = null; + if (Delicious && Delicious.posts) { + dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, Delicious.posts); + } else { + // document.write(""); + /* + document.write(""); + document.write(""); + document.write(""); + fetchComplete(); + */ + // dojo.debug("Delicious line 29: constructor"); + } + var u = this.registerAttribute('u'); + var d = this.registerAttribute('d'); + var t = this.registerAttribute('t'); + + u.load('name', 'Bookmark'); + d.load('name', 'Description'); + t.load('name', 'Tags'); + + u.load('type', 'String'); + d.load('type', 'String'); + t.load('type', 'String'); +}; +dojo.inherits(dojo.data.old.provider.Delicious, dojo.data.old.provider.FlatFile); + +/******************************************************************** + * FIXME: the rest of this is work in progress + * + +dojo.data.old.provider.Delicious.prototype.getNewItemToLoad = function() { + var newItem = this._newItem(); + this._currentArray.push(newItem); + return newItem; // dojo.data.old.Item +}; + +dojo.data.old.provider.Delicious.prototype.fetchArray = function(query) { + if (!query) { + query = "gumption"; + } + this._currentArray = []; + alert("Delicious line 60: loadDataProviderFromArrayOfJsonData"); + alert("Delicious line 61: " + dojo); + var sourceUrl = "http://del.icio.us/feeds/json/" + query + "?count=8"; + document.write(""); + document.write(""); + document.write(""); + alert("line 66"); + dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, Delicious.posts); + return this._currentArray; // Array +}; + +callMe = function() { + alert("callMe!"); +}; + +*/ diff --git a/source/web/scripts/ajax/dojo/src/data/old/provider/FlatFile.js b/source/web/scripts/ajax/dojo/src/data/old/provider/FlatFile.js new file mode 100644 index 0000000000..fa95a11a18 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/provider/FlatFile.js @@ -0,0 +1,153 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.provider.FlatFile"); +dojo.require("dojo.data.old.provider.Base"); +dojo.require("dojo.data.old.Item"); +dojo.require("dojo.data.old.Attribute"); +dojo.require("dojo.data.old.ResultSet"); +dojo.require("dojo.data.old.format.Json"); +dojo.require("dojo.data.old.format.Csv"); +dojo.require("dojo.lang.assert"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.provider.FlatFile = function(/* keywords */ keywordParameters) { + /** + * summary: + * A Json Data Provider knows how to read in simple JSON data + * tables and make their contents accessable as Items. + */ + dojo.lang.assertType(keywordParameters, "pureobject", {optional: true}); + dojo.data.old.provider.Base.call(this); + this._arrayOfItems = []; + this._resultSet = null; + this._dictionaryOfAttributes = {}; + + if (keywordParameters) { + var jsonObjects = keywordParameters["jsonObjects"]; + var jsonString = keywordParameters["jsonString"]; + var fileUrl = keywordParameters["url"]; + if (jsonObjects) { + dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, jsonObjects); + } + if (jsonString) { + dojo.data.old.format.Json.loadDataProviderFromFileContents(this, jsonString); + } + if (fileUrl) { + var arrayOfParts = fileUrl.split('.'); + var lastPart = arrayOfParts[(arrayOfParts.length - 1)]; + var formatParser = null; + if (lastPart == "json") { + formatParser = dojo.data.old.format.Json; + } + if (lastPart == "csv") { + formatParser = dojo.data.old.format.Csv; + } + if (formatParser) { + var fileContents = dojo.hostenv.getText(fileUrl); + formatParser.loadDataProviderFromFileContents(this, fileContents); + } else { + dojo.lang.assert(false, "new dojo.data.old.provider.FlatFile({url: }) was passed a file without a .csv or .json suffix"); + } + } + } +}; +dojo.inherits(dojo.data.old.provider.FlatFile, dojo.data.old.provider.Base); + +// ------------------------------------------------------------------- +// Public instance methods +// ------------------------------------------------------------------- +dojo.data.old.provider.FlatFile.prototype.getProviderCapabilities = function(/* string */ keyword) { + dojo.lang.assertType(keyword, String, {optional: true}); + if (!this._ourCapabilities) { + this._ourCapabilities = { + transactions: false, + undo: false, + login: false, + versioning: false, + anonymousRead: true, + anonymousWrite: false, + permissions: false, + queries: false, + strongTyping: false, + datatypes: [String, Date, Number] + }; + } + if (keyword) { + return this._ourCapabilities[keyword]; + } else { + return this._ourCapabilities; + } +}; + +dojo.data.old.provider.FlatFile.prototype.registerAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) { + var registeredAttribute = this.getAttribute(attributeId); + if (!registeredAttribute) { + var newAttribute = new dojo.data.old.Attribute(this, attributeId); + this._dictionaryOfAttributes[attributeId] = newAttribute; + registeredAttribute = newAttribute; + } + return registeredAttribute; // dojo.data.old.Attribute +}; + +dojo.data.old.provider.FlatFile.prototype.getAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) { + var attribute = (this._dictionaryOfAttributes[attributeId] || null); + return attribute; // dojo.data.old.Attribute or null +}; + +dojo.data.old.provider.FlatFile.prototype.getAttributes = function() { + var arrayOfAttributes = []; + for (var key in this._dictionaryOfAttributes) { + var attribute = this._dictionaryOfAttributes[key]; + arrayOfAttributes.push(attribute); + } + return arrayOfAttributes; // Array +}; + +dojo.data.old.provider.FlatFile.prototype.fetchArray = function(query) { + /** + * summary: Returns an Array containing all of the Items. + */ + return this._arrayOfItems; // Array +}; + +dojo.data.old.provider.FlatFile.prototype.fetchResultSet = function(query) { + /** + * summary: Returns a ResultSet containing all of the Items. + */ + if (!this._resultSet) { + this._resultSet = new dojo.data.old.ResultSet(this, this.fetchArray(query)); + } + return this._resultSet; // dojo.data.old.ResultSet +}; + +// ------------------------------------------------------------------- +// Private instance methods +// ------------------------------------------------------------------- +dojo.data.old.provider.FlatFile.prototype._newItem = function() { + var item = new dojo.data.old.Item(this); + this._arrayOfItems.push(item); + return item; // dojo.data.old.Item +}; + +dojo.data.old.provider.FlatFile.prototype._newAttribute = function(/* String */ attributeId) { + dojo.lang.assertType(attributeId, String); + dojo.lang.assert(this.getAttribute(attributeId) === null); + var attribute = new dojo.data.old.Attribute(this, attributeId); + this._dictionaryOfAttributes[attributeId] = attribute; + return attribute; // dojo.data.old.Attribute +}; + +dojo.data.old.provider.Base.prototype._getResultSets = function() { + return [this._resultSet]; // Array +}; + diff --git a/source/web/scripts/ajax/dojo/src/data/old/provider/JotSpot.js b/source/web/scripts/ajax/dojo/src/data/old/provider/JotSpot.js new file mode 100644 index 0000000000..47b326b2e9 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/provider/JotSpot.js @@ -0,0 +1,27 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.provider.JotSpot"); +dojo.require("dojo.data.old.provider.Base"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.provider.JotSpot = function() { + /** + * summary: + * A JotSpot Data Provider knows how to read data from a JotSpot data + * store and make the contents accessable as dojo.data.old.Items. + */ + dojo.unimplemented('dojo.data.old.provider.JotSpot'); +}; + +dojo.inherits(dojo.data.old.provider.JotSpot, dojo.data.old.provider.Base); + diff --git a/source/web/scripts/ajax/dojo/src/data/old/provider/MySql.js b/source/web/scripts/ajax/dojo/src/data/old/provider/MySql.js new file mode 100644 index 0000000000..bbf443c2fe --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/provider/MySql.js @@ -0,0 +1,27 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.data.old.provider.MySql"); +dojo.require("dojo.data.old.provider.Base"); + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +dojo.data.old.provider.MySql = function() { + /** + * summary: + * A MySql Data Provider knows how to connect to a MySQL database + * on a server and and make the content records available as + * dojo.data.old.Items. + */ + dojo.unimplemented('dojo.data.old.provider.MySql'); +}; + +dojo.inherits(dojo.data.old.provider.MySql, dojo.data.old.provider.Base); diff --git a/source/web/scripts/ajax/dojo/src/data/old/to_do.txt b/source/web/scripts/ajax/dojo/src/data/old/to_do.txt new file mode 100644 index 0000000000..6e705fc6c3 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/data/old/to_do.txt @@ -0,0 +1,45 @@ +Existing Features + * can import data from .json or .csv format files + * can import data from del.icio.us + * can create and modify data programmatically + * can bind data to dojo.widget.Chart + * can bind data to dojo.widget.SortableTable + * can bind one data set to multiple widgets + * notifications: widgets are notified when data changes + * notification available per-item or per-resultSet + * can create ad-hoc attributes + * attributes can be loosely-typed + * attributes can have meta-data like type and display name + * half-implemented support for sorting + * half-implemented support for export to .json + * API for getting data in simple arrays + * API for getting ResultSets with iterators (precursor to support for something like the openrico.org live grid) + +~~~~~~~~~~~~~~~~~~~~~~~~ +To-Do List + * be able to import data from an html
+ * think about being able to import data from some type of XML + * think about integration with dojo.undo.Manager + * think more about how to represent the notion of different data types + * think about what problems we'll run into when we have a MySQL data provider + * in TableBindingHack, improve support for data types in the SortableTable binding + * deal with ids (including MySQL multi-field keys) + * add support for item-references: employeeItem.set('department', departmentItem); + * deal with Attributes as instances of Items, not just subclasses of Items + * unit tests for compare/sort code + * unit tests for everything + * implement item.toString('json') and item.toString('xml') + * implement dataProvider.newItem({name: 'foo', age: 26}) + * deal better with transactions + * add support for deleting items + * don't send out multiple notifications to the same observer + * deal with item versions + * prototype a Yahoo data provider -- http://developer.yahoo.net/common/json.html + * prototype a data provider that enforces strong typing + * prototype a data provider that prevents ad-hoc attributes + * prototype a data provider that enforces single-kind item + * prototype a data provider that allows for login/authentication + * have loosely typed result sets play nicely with widgets that expect strong typing + * prototype an example of spreadsheet-style formulas or derivation rules + * experiment with some sort of fetch() that returns only a subset of a data provider's items + diff --git a/source/web/scripts/ajax/dojo/src/date.js b/source/web/scripts/ajax/dojo/src/date.js new file mode 100644 index 0000000000..7754095ff4 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/date.js @@ -0,0 +1,13 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.date"); + +dojo.deprecated("dojo.date", "use one of the modules in dojo.date.* instead", "0.5"); diff --git a/source/web/scripts/ajax/dojo/src/date/common.js b/source/web/scripts/ajax/dojo/src/date/common.js new file mode 100644 index 0000000000..43c26eb740 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/date/common.js @@ -0,0 +1,496 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.date.common"); + + +/* Supplementary Date Functions + *******************************/ + +dojo.date.setDayOfYear = function(/*Date*/dateObject, /*Number*/dayOfYear){ + // summary: sets dateObject according to day of the year (1..366) + dateObject.setMonth(0); + dateObject.setDate(dayOfYear); + return dateObject; // Date +} + +dojo.date.getDayOfYear = function(/*Date*/dateObject){ + // summary: gets the day of the year as represented by dateObject + var fullYear = dateObject.getFullYear(); + var lastDayOfPrevYear = new Date(fullYear-1, 11, 31); + return Math.floor((dateObject.getTime() - + lastDayOfPrevYear.getTime()) / 86400000); // Number +} + + +dojo.date.setWeekOfYear = function(/*Date*/dateObject, /*Number*/week, /*Number*/firstDay){ + if(arguments.length == 1){ firstDay = 0; } // Sunday + dojo.unimplemented("dojo.date.setWeekOfYear"); +} + +dojo.date.getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDay){ + if(arguments.length == 1){ firstDay = 0; } // Sunday + + // work out the first day of the year corresponding to the week + var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1); + var day = firstDayOfYear.getDay(); + firstDayOfYear.setDate(firstDayOfYear.getDate() - + day + firstDay - (day > firstDay ? 7 : 0)); + + return Math.floor((dateObject.getTime() - + firstDayOfYear.getTime()) / 604800000); +} + +dojo.date.setIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/week, /*Number*/firstDay){ + // summary: unimplemented + if (arguments.length == 1) { firstDay = 1; } // Monday + dojo.unimplemented("dojo.date.setIsoWeekOfYear"); +} + +dojo.date.getIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDay) { + // summary: unimplemented + if (arguments.length == 1) { firstDay = 1; } // Monday + dojo.unimplemented("dojo.date.getIsoWeekOfYear"); +} + + +/* Informational Functions + **************************/ + +//DEPRECATED: These timezone arrays will be deprecated in 0.5 +dojo.date.shortTimezones = ["IDLW", "BET", "HST", "MART", "AKST", "PST", "MST", + "CST", "EST", "AST", "NFT", "BST", "FST", "AT", "GMT", "CET", "EET", "MSK", + "IRT", "GST", "AFT", "AGTT", "IST", "NPT", "ALMT", "MMT", "JT", "AWST", + "JST", "ACST", "AEST", "LHST", "VUT", "NFT", "NZT", "CHAST", "PHOT", + "LINT"]; +dojo.date.timezoneOffsets = [-720, -660, -600, -570, -540, -480, -420, -360, + -300, -240, -210, -180, -120, -60, 0, 60, 120, 180, 210, 240, 270, 300, + 330, 345, 360, 390, 420, 480, 540, 570, 600, 630, 660, 690, 720, 765, 780, + 840]; +/* +dojo.date.timezones = ["International Date Line West", "Bering Standard Time", + "Hawaiian Standard Time", "Marquesas Time", "Alaska Standard Time", + "Pacific Standard Time (USA)", "Mountain Standard Time", + "Central Standard Time (USA)", "Eastern Standard Time (USA)", + "Atlantic Standard Time", "Newfoundland Time", "Brazil Standard Time", + "Fernando de Noronha Standard Time (Brazil)", "Azores Time", + "Greenwich Mean Time", "Central Europe Time", "Eastern Europe Time", + "Moscow Time", "Iran Standard Time", "Gulf Standard Time", + "Afghanistan Time", "Aqtobe Time", "Indian Standard Time", "Nepal Time", + "Almaty Time", "Myanmar Time", "Java Time", + "Australian Western Standard Time", "Japan Standard Time", + "Australian Central Standard Time", "Lord Hove Standard Time (Australia)", + "Vanuata Time", "Norfolk Time (Australia)", "New Zealand Standard Time", + "Chatham Standard Time (New Zealand)", "Phoenix Islands Time (Kribati)", + "Line Islands Time (Kribati)"]; +*/ + +dojo.date.getDaysInMonth = function(/*Date*/dateObject){ + // summary: returns the number of days in the month used by dateObject + var month = dateObject.getMonth(); + var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + if (month == 1 && dojo.date.isLeapYear(dateObject)) { return 29; } // Number + else { return days[month]; } // Number +} + +dojo.date.isLeapYear = function(/*Date*/dateObject){ +// summary: +// Determines if the year of the dateObject is a leap year +// +// description: +// Leap years are years with an additional day YYYY-02-29, where the year +// number is a multiple of four with the following exception: If a year +// is a multiple of 100, then it is only a leap year if it is also a +// multiple of 400. For example, 1900 was not a leap year, but 2000 is one. + + var year = dateObject.getFullYear(); + return (year%400 == 0) ? true : (year%100 == 0) ? false : (year%4 == 0) ? true : false; // Boolean +} + +// FIXME: This is not localized +dojo.date.getTimezoneName = function(/*Date*/dateObject){ +// summary: +// Get the user's time zone as provided by the browser +// +// dateObject: needed because the timezone may vary with time (daylight savings) +// +// description: +// Try to get time zone info from toString or toLocaleString +// method of the Date object -- UTC offset is not a time zone. +// See http://www.twinsun.com/tz/tz-link.htm +// Note: results may be inconsistent across browsers. + + var str = dateObject.toString(); // Start looking in toString + var tz = ''; // The result -- return empty string if nothing found + var match; + + // First look for something in parentheses -- fast lookup, no regex + var pos = str.indexOf('('); + if (pos > -1) { + pos++; + tz = str.substring(pos, str.indexOf(')')); + } + // If at first you don't succeed ... + else{ + // If IE knows about the TZ, it appears before the year + // Capital letters or slash before a 4-digit year + // at the end of string + var pat = /([A-Z\/]+) \d{4}$/; + if((match = str.match(pat))) { + tz = match[1]; + } + // Some browsers (e.g. Safari) glue the TZ on the end + // of toLocaleString instead of putting it in toString + else{ + str = dateObject.toLocaleString(); + // Capital letters or slash -- end of string, + // after space + pat = / ([A-Z\/]+)$/; + if((match = str.match(pat))) { + tz = match[1]; + } + } + } + + // Make sure it doesn't somehow end up return AM or PM + return tz == 'AM' || tz == 'PM' ? '' : tz; //String +} + + +//FIXME: not localized +dojo.date.getOrdinal = function(dateObject){ + // summary: returns the appropriate suffix (English only) for the day of the month, e.g. 'st' for 1, 'nd' for 2, etc.) + var date = dateObject.getDate(); + + if(date%100 != 11 && date%10 == 1){ return "st"; } // String + else if(date%100 != 12 && date%10 == 2){ return "nd"; } // String + else if(date%100 != 13 && date%10 == 3){ return "rd"; } // String + else{ return "th"; } // String +} + + +/* compare and add + ******************/ +dojo.date.compareTypes={ + // summary + // bitmask for comparison operations. + DATE:1, TIME:2 +}; +dojo.date.compare=function(/* Date */ dateA, /* Date */ dateB, /* dojo.date.compareTypes */ options){ + // summary + // Compare two date objects by date, time, or both. Returns 0 if equal, positive if a > b, else negative. + var dA=dateA; + var dB=dateB||new Date(); + var now=new Date(); + //FIXME: shorten this code + with(dojo.date.compareTypes){ + var opt=options||(DATE|TIME); + var d1=new Date( + (opt&DATE)?dA.getFullYear():now.getFullYear(), + (opt&DATE)?dA.getMonth():now.getMonth(), + (opt&DATE)?dA.getDate():now.getDate(), + (opt&TIME)?dA.getHours():0, + (opt&TIME)?dA.getMinutes():0, + (opt&TIME)?dA.getSeconds():0 + ); + var d2=new Date( + (opt&DATE)?dB.getFullYear():now.getFullYear(), + (opt&DATE)?dB.getMonth():now.getMonth(), + (opt&DATE)?dB.getDate():now.getDate(), + (opt&TIME)?dB.getHours():0, + (opt&TIME)?dB.getMinutes():0, + (opt&TIME)?dB.getSeconds():0 + ); + } + if(d1.valueOf()>d2.valueOf()){ + return 1; // int + } + if(d1.valueOf() 0) ? 5 : -5; + weeks = (incr > 0) ? ((incr-5)/5) : ((incr+5)/5); + } + else { + days = mod; + weeks = parseInt(incr/5); + } + // Get weekday value for orig date param + strt = dt.getDay(); + // Orig date is Sat / positive incrementer + // Jump over Sun + if (strt == 6 && incr > 0) { + adj = 1; + } + // Orig date is Sun / negative incrementer + // Jump back over Sat + else if (strt == 0 && incr < 0) { + adj = -1; + } + // Get weekday val for the new date + trgt = (strt + days); + // New date is on Sat or Sun + if (trgt == 0 || trgt == 6) { + adj = (incr > 0) ? 2 : -2; + } + // Increment by number of weeks plus leftover days plus + // weekend adjustments + sum.setDate(dat + (7*weeks) + days + adj); + break; + case HOUR: + sum.setHours(sum.getHours()+incr); + break; + case MINUTE: + sum.setMinutes(sum.getMinutes()+incr); + break; + case SECOND: + sum.setSeconds(sum.getSeconds()+incr); + break; + case MILLISECOND: + sum.setMilliseconds(sum.getMilliseconds()+incr); + break; + default: + // Do nothing + break; + } + } + + return sum; // Date +}; + +dojo.date.diff = function(/* Date */ dtA, /* Date */ dtB, /* dojo.date.dateParts */ interv){ +// summary: +// Get the difference in a specific unit of time (e.g., number of months, weeks, +// days, etc.) between two dates. +// +// dtA: +// A Javascript Date object +// +// dtB: +// A Javascript Date object +// +// interv: +// A constant representing the interval, e.g. YEAR, MONTH, DAY. See dojo.date.dateParts. + + // Accept timestamp input + if(typeof dtA == 'number'){dtA = new Date(dtA);} + if(typeof dtB == 'number'){dtB = new Date(dtB);} + var yeaDiff = dtB.getFullYear() - dtA.getFullYear(); + var monDiff = (dtB.getMonth() - dtA.getMonth()) + (yeaDiff * 12); + var msDiff = dtB.getTime() - dtA.getTime(); // Millisecs + var secDiff = msDiff/1000; + var minDiff = secDiff/60; + var houDiff = minDiff/60; + var dayDiff = houDiff/24; + var weeDiff = dayDiff/7; + var delta = 0; // Integer return value + + with(dojo.date.dateParts){ + switch(interv){ + case YEAR: + delta = yeaDiff; + break; + case QUARTER: + var mA = dtA.getMonth(); + var mB = dtB.getMonth(); + // Figure out which quarter the months are in + var qA = Math.floor(mA/3) + 1; + var qB = Math.floor(mB/3) + 1; + // Add quarters for any year difference between the dates + qB += (yeaDiff * 4); + delta = qB - qA; + break; + case MONTH: + delta = monDiff; + break; + case WEEK: + // Truncate instead of rounding + // Don't use Math.floor -- value may be negative + delta = parseInt(weeDiff); + break; + case DAY: + delta = dayDiff; + break; + case WEEKDAY: + var days = Math.round(dayDiff); + var weeks = parseInt(days/7); + var mod = days % 7; + + // Even number of weeks + if (mod == 0) { + days = weeks*5; + } + // Weeks plus spare change (< 7 days) + else { + var adj = 0; + var aDay = dtA.getDay(); + var bDay = dtB.getDay(); + + weeks = parseInt(days/7); + mod = days % 7; + // Mark the date advanced by the number of + // round weeks (may be zero) + var dtMark = new Date(dtA); + dtMark.setDate(dtMark.getDate()+(weeks*7)); + var dayMark = dtMark.getDay(); + // Spare change days -- 6 or less + // ---------- + // Positive diff + if (dayDiff > 0) { + switch (true) { + // Range starts on Sat + case aDay == 6: + adj = -1; + break; + // Range starts on Sun + case aDay == 0: + adj = 0; + break; + // Range ends on Sat + case bDay == 6: + adj = -1; + break; + // Range ends on Sun + case bDay == 0: + adj = -2; + break; + // Range contains weekend + case (dayMark + mod) > 5: + adj = -2; + break; + default: + // Do nothing + break; + } + } + // Negative diff + else if (dayDiff < 0) { + switch (true) { + // Range starts on Sat + case aDay == 6: + adj = 0; + break; + // Range starts on Sun + case aDay == 0: + adj = 1; + break; + // Range ends on Sat + case bDay == 6: + adj = 2; + break; + // Range ends on Sun + case bDay == 0: + adj = 1; + break; + // Range contains weekend + case (dayMark + mod) < 0: + adj = 2; + break; + default: + // Do nothing + break; + } + } + days += adj; + days -= (weeks*2); + } + delta = days; + + break; + case HOUR: + delta = houDiff; + break; + case MINUTE: + delta = minDiff; + break; + case SECOND: + delta = secDiff; + break; + case MILLISECOND: + delta = msDiff; + break; + default: + // Do nothing + break; + } + } + + // Round for fractional values and DST leaps + return Math.round(delta); // Number (integer) +}; diff --git a/source/web/scripts/ajax/dojo/src/date/format.js b/source/web/scripts/ajax/dojo/src/date/format.js new file mode 100644 index 0000000000..4318525c83 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/date/format.js @@ -0,0 +1,922 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.date.format"); + +dojo.require("dojo.date.common"); +dojo.require("dojo.date.supplemental"); +dojo.require("dojo.lang.array"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.string.common"); +dojo.require("dojo.i18n.common"); + +// Load the bundles containing localization information for +// names and formats +dojo.requireLocalization("dojo.i18n.calendar", "gregorian", null, "de,en,es,fi,fr,hu,ja,it,ko,nl,pt,sv,zh,pt-br,zh-cn,zh-hk,zh-tw,ROOT"); +dojo.requireLocalization("dojo.i18n.calendar", "gregorianExtras", null, "ja,zh,ROOT"); + +//NOTE: Everything in this module assumes Gregorian calendars. +// Other calendars will be implemented in separate modules. + +(function(){ +dojo.date.format = function(/*Date*/dateObject, /*Object?*/options){ +// +// summary: +// Format a Date object as a String, using locale-specific settings. +// +// description: +// Create a string from a Date object using a known localized pattern. +// By default, this method formats both date and time from dateObject. +// Formatting patterns are chosen appropriate to the locale. Different +// formatting lengths may be chosen, with "full" used by default. +// Custom patterns may be used or registered with translations using +// the addCustomBundle method. +// Formatting patterns are implemented using the syntax described at +// http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns +// +// dateObject: +// the date and/or time to be formatted. If a time only is formatted, +// the values in the year, month, and day fields are irrelevant. The +// opposite is true when formatting only dates. +// +// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string} +// selector- choice of timeOnly,dateOnly (default: date and time) +// formatLength- choice of long, short, medium or full (plus any custom additions). Defaults to 'full' +// datePattern,timePattern- override pattern with this string +// am,pm- override strings for am/pm in times +// locale- override the locale used to determine formatting rules +// + + if(typeof options == "string"){ + dojo.deprecated("dojo.date.format", "To format dates with POSIX-style strings, please use dojo.date.strftime instead", "0.5"); + return dojo.date.strftime(dateObject, options); + } + + // Format a pattern without literals + function formatPattern(dateObject, pattern){ + return pattern.replace(/([a-z])\1*/ig, function(match){ + var s; + var c = match.charAt(0); + var l = match.length; + var pad; + var widthList = ["abbr", "wide", "narrow"]; + switch(c){ + case 'G': + if(l>3){dojo.unimplemented("Era format not implemented");} + s = info.eras[dateObject.getFullYear() < 0 ? 1 : 0]; + break; + case 'y': + s = dateObject.getFullYear(); + switch(l){ + case 1: + break; + case 2: + s = String(s).substr(-2); + break; + default: + pad = true; + } + break; + case 'Q': + case 'q': + s = Math.ceil((dateObject.getMonth()+1)/3); + switch(l){ + case 1: case 2: + pad = true; + break; + case 3: + case 4: + dojo.unimplemented("Quarter format not implemented"); + } + break; + case 'M': + case 'L': + var m = dateObject.getMonth(); + var width; + switch(l){ + case 1: case 2: + s = m+1; pad = true; + break; + case 3: case 4: case 5: + width = widthList[l-3]; + break; + } + if(width){ + var type = (c == "L") ? "standalone" : "format"; + var prop = ["months",type,width].join("-"); + s = info[prop][m]; + } + break; + case 'w': + var firstDay = 0; + s = dojo.date.getWeekOfYear(dateObject, firstDay); pad = true; + break; + case 'd': + s = dateObject.getDate(); pad = true; + break; + case 'D': + s = dojo.date.getDayOfYear(dateObject); pad = true; + break; + case 'E': + case 'e': + case 'c': // REVIEW: don't see this in the spec? + var d = dateObject.getDay(); + var width; + switch(l){ + case 1: case 2: + if(c == 'e'){ + var first = dojo.date.getFirstDayOfWeek(options.locale); + d = (d-first+7)%7; + } + if(c != 'c'){ + s = d+1; pad = true; + break; + } + // else fallthrough... + case 3: case 4: case 5: + width = widthList[l-3]; + break; + } + if(width){ + var type = (c == "c") ? "standalone" : "format"; + var prop = ["days",type,width].join("-"); + s = info[prop][d]; + } + break; + case 'a': + var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm'; + s = info[timePeriod]; + break; + case 'h': + case 'H': + case 'K': + case 'k': + var h = dateObject.getHours(); + // strange choices in the date format make it impossible to write this succinctly + switch (c) { + case 'h': // 1-12 + s = (h % 12) || 12; + break; + case 'H': // 0-23 + s = h; + break; + case 'K': // 0-11 + s = (h % 12); + break; + case 'k': // 1-24 + s = h || 24; + break; + } + pad = true; + break; + case 'm': + s = dateObject.getMinutes(); pad = true; + break; + case 's': + s = dateObject.getSeconds(); pad = true; + break; + case 'S': + s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); + break; + case 'v': // FIXME: don't know what this is. seems to be same as z? + case 'z': + // We only have one timezone to offer; the one from the browser + s = dojo.date.getTimezoneName(dateObject); + if(s){break;} + l=4; + // fallthrough... use GMT if tz not available + case 'Z': + var offset = dateObject.getTimezoneOffset(); + var tz = [ + (offset<=0 ? "+" : "-"), + dojo.string.pad(Math.floor(Math.abs(offset)/60), 2), + dojo.string.pad(Math.abs(offset)% 60, 2) + ]; + if(l==4){ + tz.splice(0, 0, "GMT"); + tz.splice(3, 0, ":"); + } + s = tz.join(""); + break; + case 'Y': + case 'u': + case 'W': + case 'F': + case 'g': + case 'A': + dojo.debug(match+" modifier not yet implemented"); + s = "?"; + break; + default: + dojo.raise("dojo.date.format: invalid pattern char: "+pattern); + } + if(pad){ s = dojo.string.pad(s, l); } + return s; + }); + } + + options = options || {}; + + var locale = dojo.hostenv.normalizeLocale(options.locale); + var formatLength = options.formatLength || 'full'; + var info = dojo.date._getGregorianBundle(locale); + var str = []; + var sauce = dojo.lang.curry(this, formatPattern, dateObject); + if(options.selector != "timeOnly"){ + var datePattern = options.datePattern || info["dateFormat-"+formatLength]; + if(datePattern){str.push(_processPattern(datePattern, sauce));} + } + if(options.selector != "dateOnly"){ + var timePattern = options.timePattern || info["timeFormat-"+formatLength]; + if(timePattern){str.push(_processPattern(timePattern, sauce));} + } + var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time + return result; /*String*/ +}; + +dojo.date.parse = function(/*String*/value, /*Object?*/options){ +// +// summary: +// Convert a properly formatted string to a primitive Date object, +// using locale-specific settings. +// +// description: +// Create a Date object from a string using a known localized pattern. +// By default, this method parses looking for both date and time in the string. +// Formatting patterns are chosen appropriate to the locale. Different +// formatting lengths may be chosen, with "full" used by default. +// Custom patterns may be used or registered with translations using +// the addCustomBundle method. +// Formatting patterns are implemented using the syntax described at +// http://www.unicode.org/reports/tr35/#Date_Format_Patterns +// +// value: +// A string representation of a date +// +// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string, strict: boolean} +// selector- choice of timeOnly, dateOnly, dateTime (default: dateOnly) +// formatLength- choice of long, short, medium or full (plus any custom additions). Defaults to 'full' +// datePattern,timePattern- override pattern with this string +// am,pm- override strings for am/pm in times +// locale- override the locale used to determine formatting rules +// strict- strict parsing, off by default +// + + options = options || {}; + var locale = dojo.hostenv.normalizeLocale(options.locale); + var info = dojo.date._getGregorianBundle(locale); + var formatLength = options.formatLength || 'full'; + if(!options.selector){ options.selector = 'dateOnly'; } + var datePattern = options.datePattern || info["dateFormat-" + formatLength]; + var timePattern = options.timePattern || info["timeFormat-" + formatLength]; + + var pattern; + if(options.selector == 'dateOnly'){ + pattern = datePattern; + } + else if(options.selector == 'timeOnly'){ + pattern = timePattern; + }else if(options.selector == 'dateTime'){ + pattern = datePattern + ' ' + timePattern; //TODO: use locale-specific pattern to assemble date + time + }else{ + var msg = "dojo.date.parse: Unknown selector param passed: '" + options.selector + "'."; + msg += " Defaulting to date pattern."; + dojo.debug(msg); + pattern = datePattern; + } + + var groups = []; + var dateREString = _processPattern(pattern, dojo.lang.curry(this, _buildDateTimeRE, groups, info, options)); + var dateRE = new RegExp("^" + dateREString + "$"); + + var match = dateRE.exec(value); + if(!match){ + return null; + } + + var widthList = ['abbr', 'wide', 'narrow']; + //1972 is a leap year. We want to avoid Feb 29 rolling over into Mar 1, + //in the cases where the year is parsed after the month and day. + var result = new Date(1972, 0); + var expected = {}; + for(var i=1; i2) { + if(!options.strict){ + //Tolerate abbreviating period in month part + v = v.replace(/\./g,''); + //Case-insensitive + v = v.toLowerCase(); + } + var months = info['months-format-' + widthList[l-3]].concat(); + for (var j=0; j 15 + } else if(v == am && hours == 12){ + result.setHours(0); //12am -> 0 + } + break; + case 'K': //hour (1-24) + if(v==24){v=0;} + // fallthrough... + case 'h': //hour (1-12) + case 'H': //hour (0-23) + case 'k': //hour (0-11) + //TODO: strict bounds checking, padding + if(v>23){ + dojo.debug("dojo.date.parse: Illegal hours value"); + return null; + } + + //in the 12-hour case, adjusting for am/pm requires the 'a' part + //which for now we will assume always comes after the 'h' part + result.setHours(v); + break; + case 'm': //minutes + result.setMinutes(v); + break; + case 's': //seconds + result.setSeconds(v); + break; + case 'S': //milliseconds + result.setMilliseconds(v); + break; + default: + dojo.unimplemented("dojo.date.parse: unsupported pattern char=" + grp.charAt(0)); + } + } + + //validate parse date fields versus input date fields + if(expected.year && result.getFullYear() != expected.year){ + dojo.debug("Parsed year: '" + result.getFullYear() + "' did not match input year: '" + expected.year + "'."); + return null; + } + if(expected.month && result.getMonth() != expected.month){ + dojo.debug("Parsed month: '" + result.getMonth() + "' did not match input month: '" + expected.month + "'."); + return null; + } + if(expected.date && result.getDate() != expected.date){ + dojo.debug("Parsed day of month: '" + result.getDate() + "' did not match input day of month: '" + expected.date + "'."); + return null; + } + + //TODO: implement a getWeekday() method in order to test + //validity of input strings containing 'EEE' or 'EEEE'... + + return result; /*Date*/ +}; + +function _processPattern(pattern, applyPattern, applyLiteral, applyAll){ + // Process a pattern with literals in it + // Break up on single quotes, treat every other one as a literal, except '' which becomes ' + var identity = function(x){return x;}; + applyPattern = applyPattern || identity; + applyLiteral = applyLiteral || identity; + applyAll = applyAll || identity; + + //split on single quotes (which escape literals in date format strings) + //but preserve escaped single quotes (e.g., o''clock) + var chunks = pattern.match(/(''|[^'])+/g); + var literal = false; + + for(var i=0; i2) ? '\\S+' : '\\d{1,2}'; + break; + case 'd': + s = '\\d{1,2}'; + break; + case 'E': + s = '\\S+'; + break; + case 'h': + case 'H': + case 'K': + case 'k': + s = '\\d{1,2}'; + break; + case 'm': + case 's': + s = '[0-5]\\d'; + break; + case 'S': + s = '\\d{1,3}'; + break; + case 'a': + var am = options.am || info.am || 'AM'; + var pm = options.pm || info.pm || 'PM'; + if(options.strict){ + s = am + '|' + pm; + }else{ + s = am; + s += (am != am.toLowerCase()) ? '|' + am.toLowerCase() : ''; + s += '|'; + s += (pm != pm.toLowerCase()) ? pm + '|' + pm.toLowerCase() : pm; + } + break; + default: + dojo.unimplemented("parse of date format, pattern=" + pattern); + } + + if(groups){ groups.push(match); } + +//FIXME: replace whitespace within final regexp with more flexible whitespace match instead? + //tolerate whitespace + return '\\s*(' + s + ')\\s*'; + }); +} +})(); + +//TODO: try to common strftime and format code somehow? + +dojo.date.strftime = function(/*Date*/dateObject, /*String*/format, /*String?*/locale){ +// +// summary: +// Formats the date object using the specifications of the POSIX strftime function +// +// description: +// see + + // zero pad + var padChar = null; + function _(s, n){ + return dojo.string.pad(s, n || 2, padChar || "0"); + } + + var info = dojo.date._getGregorianBundle(locale); + + function $(property){ + switch (property){ + case "a": // abbreviated weekday name according to the current locale + return dojo.date.getDayShortName(dateObject, locale); + + case "A": // full weekday name according to the current locale + return dojo.date.getDayName(dateObject, locale); + + case "b": + case "h": // abbreviated month name according to the current locale + return dojo.date.getMonthShortName(dateObject, locale); + + case "B": // full month name according to the current locale + return dojo.date.getMonthName(dateObject, locale); + + case "c": // preferred date and time representation for the current + // locale + return dojo.date.format(dateObject, {locale: locale}); + + case "C": // century number (the year divided by 100 and truncated + // to an integer, range 00 to 99) + return _(Math.floor(dateObject.getFullYear()/100)); + + case "d": // day of the month as a decimal number (range 01 to 31) + return _(dateObject.getDate()); + + case "D": // same as %m/%d/%y + return $("m") + "/" + $("d") + "/" + $("y"); + + case "e": // day of the month as a decimal number, a single digit is + // preceded by a space (range ' 1' to '31') + if(padChar == null){ padChar = " "; } + return _(dateObject.getDate()); + + case "f": // month as a decimal number, a single digit is + // preceded by a space (range ' 1' to '12') + if(padChar == null){ padChar = " "; } + return _(dateObject.getMonth()+1); + + case "g": // like %G, but without the century. + break; + + case "G": // The 4-digit year corresponding to the ISO week number + // (see %V). This has the same format and value as %Y, + // except that if the ISO week number belongs to the + // previous or next year, that year is used instead. + dojo.unimplemented("unimplemented modifier 'G'"); + break; + + case "F": // same as %Y-%m-%d + return $("Y") + "-" + $("m") + "-" + $("d"); + + case "H": // hour as a decimal number using a 24-hour clock (range + // 00 to 23) + return _(dateObject.getHours()); + + case "I": // hour as a decimal number using a 12-hour clock (range + // 01 to 12) + return _(dateObject.getHours() % 12 || 12); + + case "j": // day of the year as a decimal number (range 001 to 366) + return _(dojo.date.getDayOfYear(dateObject), 3); + + case "k": // Hour as a decimal number using a 24-hour clock (range + // 0 to 23 (space-padded)) + if (padChar == null) { padChar = " "; } + return _(dateObject.getHours()); + + case "l": // Hour as a decimal number using a 12-hour clock (range + // 1 to 12 (space-padded)) + if (padChar == null) { padChar = " "; } + return _(dateObject.getHours() % 12 || 12); + + case "m": // month as a decimal number (range 01 to 12) + return _(dateObject.getMonth() + 1); + + case "M": // minute as a decimal number + return _(dateObject.getMinutes()); + + case "n": + return "\n"; + + case "p": // either `am' or `pm' according to the given time value, + // or the corresponding strings for the current locale + return info[dateObject.getHours() < 12 ? "am" : "pm"]; + + case "r": // time in a.m. and p.m. notation + return $("I") + ":" + $("M") + ":" + $("S") + " " + $("p"); + + case "R": // time in 24 hour notation + return $("H") + ":" + $("M"); + + case "S": // second as a decimal number + return _(dateObject.getSeconds()); + + case "t": + return "\t"; + + case "T": // current time, equal to %H:%M:%S + return $("H") + ":" + $("M") + ":" + $("S"); + + case "u": // weekday as a decimal number [1,7], with 1 representing + // Monday + return String(dateObject.getDay() || 7); + + case "U": // week number of the current year as a decimal number, + // starting with the first Sunday as the first day of the + // first week + return _(dojo.date.getWeekOfYear(dateObject)); + + case "V": // week number of the year (Monday as the first day of the + // week) as a decimal number [01,53]. If the week containing + // 1 January has four or more days in the new year, then it + // is considered week 1. Otherwise, it is the last week of + // the previous year, and the next week is week 1. + return _(dojo.date.getIsoWeekOfYear(dateObject)); + + case "W": // week number of the current year as a decimal number, + // starting with the first Monday as the first day of the + // first week + return _(dojo.date.getWeekOfYear(dateObject, 1)); + + case "w": // day of the week as a decimal, Sunday being 0 + return String(dateObject.getDay()); + + case "x": // preferred date representation for the current locale + // without the time + return dojo.date.format(dateObject, {selector:'dateOnly', locale:locale}); + + case "X": // preferred time representation for the current locale + // without the date + return dojo.date.format(dateObject, {selector:'timeOnly', locale:locale}); + + case "y": // year as a decimal number without a century (range 00 to + // 99) + return _(dateObject.getFullYear()%100); + + case "Y": // year as a decimal number including the century + return String(dateObject.getFullYear()); + + case "z": // time zone or name or abbreviation + var timezoneOffset = dateObject.getTimezoneOffset(); + return (timezoneOffset > 0 ? "-" : "+") + + _(Math.floor(Math.abs(timezoneOffset)/60)) + ":" + + _(Math.abs(timezoneOffset)%60); + + case "Z": // time zone or name or abbreviation + return dojo.date.getTimezoneName(dateObject); + + case "%": + return "%"; + } + } + + // parse the formatting string and construct the resulting string + var string = ""; + var i = 0; + var index = 0; + var switchCase = null; + while ((index = format.indexOf("%", i)) != -1){ + string += format.substring(i, index++); + + // inspect modifier flag + switch (format.charAt(index++)) { + case "_": // Pad a numeric result string with spaces. + padChar = " "; break; + case "-": // Do not pad a numeric result string. + padChar = ""; break; + case "0": // Pad a numeric result string with zeros. + padChar = "0"; break; + case "^": // Convert characters in result string to uppercase. + switchCase = "upper"; break; + case "*": // Convert characters in result string to lowercase + switchCase = "lower"; break; + case "#": // Swap the case of the result string. + switchCase = "swap"; break; + default: // no modifier flag so decrement the index + padChar = null; index--; break; + } + + // toggle case if a flag is set + var property = $(format.charAt(index++)); + switch (switchCase){ + case "upper": + property = property.toUpperCase(); + break; + case "lower": + property = property.toLowerCase(); + break; + case "swap": // Upper to lower, and versey-vicea + var compareString = property.toLowerCase(); + var swapString = ''; + var j = 0; + var ch = ''; + while (j < property.length){ + ch = property.charAt(j); + swapString += (ch == compareString.charAt(j)) ? + ch.toUpperCase() : ch.toLowerCase(); + j++; + } + property = swapString; + break; + default: + break; + } + switchCase = null; + + string += property; + i = index; + } + string += format.substring(i); + + return string; // String +}; + +(function(){ +var _customFormats = []; +dojo.date.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){ +// +// summary: +// Add a reference to a bundle containing localized custom formats to be +// used by date/time formatting and parsing routines. +// +// description: +// The user may add custom localized formats where the bundle has properties following the +// same naming convention used by dojo for the CLDR data: dateFormat-xxxx / timeFormat-xxxx +// The pattern string should match the format used by the CLDR. +// See dojo.date.format for details. +// The resources must be loaded by dojo.requireLocalization() prior to use + + _customFormats.push({pkg:packageName,name:bundleName}); +}; + +dojo.date._getGregorianBundle = function(/*String*/locale){ + var gregorian = {}; + dojo.lang.forEach(_customFormats, function(desc){ + var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale); + gregorian = dojo.lang.mixin(gregorian, bundle); + }, this); + return gregorian; /*Object*/ +}; +})(); + +dojo.date.addCustomFormats("dojo.i18n.calendar","gregorian"); +dojo.date.addCustomFormats("dojo.i18n.calendar","gregorianExtras"); + +dojo.date.getNames = function(/*String*/item, /*String*/type, /*String?*/use, /*String?*/locale){ +// +// summary: +// Used to get localized strings for day or month names. +// +// item: 'months' || 'days' +// type: 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English) +// use: 'standAlone' || 'format' (default) +// locale: override locale used to find the names + + var label; + var lookup = dojo.date._getGregorianBundle(locale); + var props = [item, use, type]; + if(use == 'standAlone'){ + label = lookup[props.join('-')]; + } + props[1] = 'format'; + + // return by copy so changes won't be made accidentally to the in-memory model + return (label || lookup[props.join('-')]).concat(); /*Array*/ +}; + +// Convenience methods + +dojo.date.getDayName = function(/*Date*/dateObject, /*String?*/locale){ +// summary: gets the full localized day of the week corresponding to the date object + return dojo.date.getNames('days', 'wide', 'format', locale)[dateObject.getDay()]; /*String*/ +}; + +dojo.date.getDayShortName = function(/*Date*/dateObject, /*String?*/locale){ +// summary: gets the abbreviated localized day of the week corresponding to the date object + return dojo.date.getNames('days', 'abbr', 'format', locale)[dateObject.getDay()]; /*String*/ +}; + +dojo.date.getMonthName = function(/*Date*/dateObject, /*String?*/locale){ +// summary: gets the full localized month name corresponding to the date object + return dojo.date.getNames('months', 'wide', 'format', locale)[dateObject.getMonth()]; /*String*/ +}; + +dojo.date.getMonthShortName = function(/*Date*/dateObject, /*String?*/locale){ +// summary: gets the abbreviated localized month name corresponding to the date object + return dojo.date.getNames('months', 'abbr', 'format', locale)[dateObject.getMonth()]; /*String*/ +}; + +//FIXME: not localized +dojo.date.toRelativeString = function(/*Date*/dateObject){ +// summary: +// Returns an description in English of the date relative to the current date. Note: this is not localized yet. English only. +// +// description: Example returns: +// - "1 minute ago" +// - "4 minutes ago" +// - "Yesterday" +// - "2 days ago" + + var now = new Date(); + var diff = (now - dateObject) / 1000; + var end = " ago"; + var future = false; + if(diff < 0){ + future = true; + end = " from now"; + diff = -diff; + } + + if(diff < 60){ + diff = Math.round(diff); + return diff + " second" + (diff == 1 ? "" : "s") + end; + } + if(diff < 60*60){ + diff = Math.round(diff/60); + return diff + " minute" + (diff == 1 ? "" : "s") + end; + } + if(diff < 60*60*24){ + diff = Math.round(diff/3600); + return diff + " hour" + (diff == 1 ? "" : "s") + end; + } + if(diff < 60*60*24*7){ + diff = Math.round(diff/(3600*24)); + if(diff == 1){ + return future ? "Tomorrow" : "Yesterday"; + }else{ + return diff + " days" + end; + } + } + return dojo.date.format(dateObject); // String +}; + +//FIXME: SQL methods can probably be moved to a different module without i18n deps + +dojo.date.toSql = function(/*Date*/dateObject, /*Boolean?*/noTime){ +// summary: +// Convert a Date to a SQL string +// noTime: whether to ignore the time portion of the Date. Defaults to false. + + return dojo.date.strftime(dateObject, "%F" + !noTime ? " %T" : ""); // String +}; + +dojo.date.fromSql = function(/*String*/sqlDate){ +// summary: +// Convert a SQL date string to a JavaScript Date object + + var parts = sqlDate.split(/[\- :]/g); + while(parts.length < 6){ + parts.push(0); + } + return new Date(parts[0], (parseInt(parts[1],10)-1), parts[2], parts[3], parts[4], parts[5]); // Date +}; diff --git a/source/web/scripts/ajax/dojo/src/date/serialize.js b/source/web/scripts/ajax/dojo/src/date/serialize.js new file mode 100644 index 0000000000..6a43f98634 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/date/serialize.js @@ -0,0 +1,175 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.date.serialize"); + +dojo.require("dojo.string.common"); + +/* ISO 8601 Functions + *********************/ + +dojo.date.setIso8601 = function(/*Date*/dateObject, /*String*/formattedString){ + // summary: sets a Date object based on an ISO 8601 formatted string (uses date and time) + var comps = (formattedString.indexOf("T") == -1) ? formattedString.split(" ") : formattedString.split("T"); + dateObject = dojo.date.setIso8601Date(dateObject, comps[0]); + if(comps.length == 2){ dateObject = dojo.date.setIso8601Time(dateObject, comps[1]); } + return dateObject; /* Date or null */ +}; + +dojo.date.fromIso8601 = function(/*String*/formattedString){ + // summary: returns a Date object based on an ISO 8601 formatted string (uses date and time) + return dojo.date.setIso8601(new Date(0, 0), formattedString); +}; + +dojo.date.setIso8601Date = function(/*String*/dateObject, /*String*/formattedString){ + // summary: sets a Date object based on an ISO 8601 formatted string (date only) + var regexp = "^([0-9]{4})((-?([0-9]{2})(-?([0-9]{2}))?)|" + + "(-?([0-9]{3}))|(-?W([0-9]{2})(-?([1-7]))?))?$"; + var d = formattedString.match(new RegExp(regexp)); + if(!d){ + dojo.debug("invalid date string: " + formattedString); + return null; // null + } + var year = d[1]; + var month = d[4]; + var date = d[6]; + var dayofyear = d[8]; + var week = d[10]; + var dayofweek = d[12] ? d[12] : 1; + + dateObject.setFullYear(year); + + if(dayofyear){ + dateObject.setMonth(0); + dateObject.setDate(Number(dayofyear)); + } + else if(week){ + dateObject.setMonth(0); + dateObject.setDate(1); + var gd = dateObject.getDay(); + var day = gd ? gd : 7; + var offset = Number(dayofweek) + (7 * Number(week)); + + if(day <= 4){ dateObject.setDate(offset + 1 - day); } + else{ dateObject.setDate(offset + 8 - day); } + } else{ + if(month){ + dateObject.setDate(1); + dateObject.setMonth(month - 1); + } + if(date){ dateObject.setDate(date); } + } + + return dateObject; // Date +}; + +dojo.date.fromIso8601Date = function(/*String*/formattedString){ + // summary: returns a Date object based on an ISO 8601 formatted string (date only) + return dojo.date.setIso8601Date(new Date(0, 0), formattedString); +}; + +dojo.date.setIso8601Time = function(/*Date*/dateObject, /*String*/formattedString){ + // summary: sets a Date object based on an ISO 8601 formatted string (time only) + + // first strip timezone info from the end + var timezone = "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$"; + var d = formattedString.match(new RegExp(timezone)); + + var offset = 0; // local time if no tz info + if(d){ + if(d[0] != 'Z'){ + offset = (Number(d[3]) * 60) + Number(d[5]); + offset *= ((d[2] == '-') ? 1 : -1); + } + offset -= dateObject.getTimezoneOffset(); + formattedString = formattedString.substr(0, formattedString.length - d[0].length); + } + + // then work out the time + var regexp = "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$"; + d = formattedString.match(new RegExp(regexp)); + if(!d){ + dojo.debug("invalid time string: " + formattedString); + return null; // null + } + var hours = d[1]; + var mins = Number((d[3]) ? d[3] : 0); + var secs = (d[5]) ? d[5] : 0; + var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0; + + dateObject.setHours(hours); + dateObject.setMinutes(mins); + dateObject.setSeconds(secs); + dateObject.setMilliseconds(ms); + + if(offset !== 0){ + dateObject.setTime(dateObject.getTime() + offset * 60000); + } + return dateObject; // Date +}; + +dojo.date.fromIso8601Time = function(/*String*/formattedString){ + // summary: returns a Date object based on an ISO 8601 formatted string (date only) + return dojo.date.setIso8601Time(new Date(0, 0), formattedString); +}; + + +/* RFC-3339 Date Functions + *************************/ + +dojo.date.toRfc3339 = function(/*Date?*/dateObject, /*String?*/selector){ +// summary: +// Format a JavaScript Date object as a string according to RFC 3339 +// +// dateObject: +// A JavaScript date, or the current date and time, by default +// +// selector: +// "dateOnly" or "timeOnly" to format selected portions of the Date object. +// Date and time will be formatted by default. + +//FIXME: tolerate Number, string input? + if(!dateObject){ + dateObject = new Date(); + } + + var _ = dojo.string.pad; + var formattedDate = []; + if(selector != "timeOnly"){ + var date = [_(dateObject.getFullYear(),4), _(dateObject.getMonth()+1,2), _(dateObject.getDate(),2)].join('-'); + formattedDate.push(date); + } + if(selector != "dateOnly"){ + var time = [_(dateObject.getHours(),2), _(dateObject.getMinutes(),2), _(dateObject.getSeconds(),2)].join(':'); + var timezoneOffset = dateObject.getTimezoneOffset(); + time += (timezoneOffset > 0 ? "-" : "+") + + _(Math.floor(Math.abs(timezoneOffset)/60),2) + ":" + + _(Math.abs(timezoneOffset)%60,2); + formattedDate.push(time); + } + return formattedDate.join('T'); // String +}; + +dojo.date.fromRfc3339 = function(/*String*/rfcDate){ +// summary: +// Create a JavaScript Date object from a string formatted according to RFC 3339 +// +// rfcDate: +// A string such as 2005-06-30T08:05:00-07:00 +// "any" is also supported in place of a time. + + // backwards compatible support for use of "any" instead of just not + // including the time + if(rfcDate.indexOf("Tany")!=-1){ + rfcDate = rfcDate.replace("Tany",""); + } + var dateObject = new Date(); + return dojo.date.setIso8601(dateObject, rfcDate); // Date or null +}; diff --git a/source/web/scripts/ajax/dojo/src/date/supplemental.js b/source/web/scripts/ajax/dojo/src/date/supplemental.js new file mode 100644 index 0000000000..898c7f3dff --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/date/supplemental.js @@ -0,0 +1,76 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.date.supplemental"); + +dojo.date.getFirstDayOfWeek = function(/*String?*/locale){ +// summary: Returns a zero-based index for first day of the week +// description: +// Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar. +// e.g. Sunday (returns 0), or Monday (returns 1) + + // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay + var firstDay = {/*default is 1=Monday*/ + mv:5, + ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,lb:6,ly:6,ma:6,om:6,qa:6,sa:6, + sd:6,so:6,tn:6,ye:6, + as:0,au:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,il:0,is:0,jm:0,jp:0,kg:0,kr:0,la:0, + mh:0,mo:0,mp:0,mt:0,nz:0,ph:0,pk:0,sg:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,vi:0,za:0,zw:0, + et:0,mw:0,ng:0,tj:0, + gb:0, + sy:4 + }; + + locale = dojo.hostenv.normalizeLocale(locale); + var country = locale.split("-")[1]; + var dow = firstDay[country]; + return (typeof dow == 'undefined') ? 1 : dow; /*Number*/ +}; + +dojo.date.getWeekend = function(/*String?*/locale){ +// summary: Returns a hash containing the start and end days of the weekend +// description: +// Returns a hash containing the start and end days of the weekend according to local custom using locale, +// or by default in the user's locale. +// e.g. {start:6, end:0} + + // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End} + var weekendStart = {/*default is 6=Saturday*/ + eg:5,il:5,sy:5, + 'in':0, + ae:4,bh:4,dz:4,iq:4,jo:4,kw:4,lb:4,ly:4,ma:4,om:4,qa:4,sa:4,sd:4,tn:4,ye:4 + }; + + var weekendEnd = {/*default is 0=Sunday*/ + ae:5,bh:5,dz:5,iq:5,jo:5,kw:5,lb:5,ly:5,ma:5,om:5,qa:5,sa:5,sd:5,tn:5,ye:5,af:5,ir:5, + eg:6,il:6,sy:6 + }; + + locale = dojo.hostenv.normalizeLocale(locale); + var country = locale.split("-")[1]; + var start = weekendStart[country]; + var end = weekendEnd[country]; + if(typeof start == 'undefined'){start=6;} + if(typeof end == 'undefined'){end=0;} + return {start:start, end:end}; /*Object {start,end}*/ +}; + +dojo.date.isWeekend = function(/*Date?*/dateObj, /*String?*/locale){ +// summary: +// Determines if the date falls on a weekend, according to local custom. + + var weekend = dojo.date.getWeekend(locale); + var day = (dateObj || new Date()).getDay(); + if(weekend.end= weekend.start && day <= weekend.end; // Boolean +}; diff --git a/source/web/scripts/ajax/dojo/src/debug.js b/source/web/scripts/ajax/dojo/src/debug.js new file mode 100644 index 0000000000..337aaddc00 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/debug.js @@ -0,0 +1,91 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.debug = function(/*...*/){ + // summary: + // Produce a line of debug output. Does nothing unless + // djConfig.isDebug is true. Accepts any nubmer of args, joined with + // ' ' to produce a single line of debugging output. Caller should not + // supply a trailing "\n". + if (!djConfig.isDebug) { return; } + var args = arguments; + if(dj_undef("println", dojo.hostenv)){ + dojo.raise("dojo.debug not available (yet?)"); + } + var isJUM = dj_global["jum"] && !dj_global["jum"].isBrowser; + var s = [(isJUM ? "": "DEBUG: ")]; + for(var i=0;i 0.4"); + } +} diff --git a/source/web/scripts/ajax/dojo/src/debug/arrow_hide.gif b/source/web/scripts/ajax/dojo/src/debug/arrow_hide.gif new file mode 100644 index 0000000000..8bd6b346ca Binary files /dev/null and b/source/web/scripts/ajax/dojo/src/debug/arrow_hide.gif differ diff --git a/source/web/scripts/ajax/dojo/src/debug/arrow_show.gif b/source/web/scripts/ajax/dojo/src/debug/arrow_show.gif new file mode 100644 index 0000000000..4246b506fb Binary files /dev/null and b/source/web/scripts/ajax/dojo/src/debug/arrow_show.gif differ diff --git a/source/web/scripts/ajax/dojo/src/debug/console.js b/source/web/scripts/ajax/dojo/src/debug/console.js new file mode 100644 index 0000000000..99bf32b3df --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/debug/console.js @@ -0,0 +1,115 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.debug.console"); +dojo.require("dojo.logging.ConsoleLogger"); + +// summary: +// Console logger, for use with FireFox Firebug, Safari and Opera's consoles. +// description: +// This package redirects the normal dojo debugging output to the console log in modern browsers. +// When using Firebug, it does this by sending the entire object to the console, +// rather than just overriding dojo.hostenv.println, so that Firebug's interactive +// object inspector is available. +// see: http://www.joehewitt.com/software/firebug/docs.php + +if (window.console) { + if (console.info != null) { + // using a later version of Firebug -- lots of fun stuff! + + dojo.hostenv.println = function() { + // summary: Write all of the arguments to the Firebug console + // description: Uses console.info() so that the (i) icon prints next to the debug line + // rather than munging the arguments by adding "DEBUG:" in front of them. + // This allows us to use Firebug's string handling to do interesting things + if (!djConfig.isDebug) { return; } + console.info.apply(console, arguments); + } + dojo.debug=dojo.hostenv.println; + dojo.debugDeep = dojo.debug; + + dojo.debugShallow = function(/*Object*/ obj, /*Boolean?*/showMethods, /*Boolean?*/sort) { + // summary: Write first-level properties of obj to the console. + // obj: Object or Array to debug + // showMethods: Pass false to skip outputing methods of object, any other value will output them. + // sort: Pass false to skip sorting properties, any other value will sort. + if (!djConfig.isDebug) { return; } + + showMethods = (showMethods != false); + sort = (sort != false); + + // handle null or something without a constructor (in which case we don't know the type) + if (obj == null || obj.constructor == null) { + return dojo.debug(obj); + } + + // figure out type via a standard constructor (Object, String, Date, etc) + var type = obj.declaredClass; + if (type == null) { + type = obj.constructor.toString().match(/function\s*(.*)\(/); + if (type) { type = type[1] }; + } + // if we got a viable type, use Firebug's interactive property dump feature + if (type) { + if (type == "String" || type == "Number") { + return dojo.debug(type+": ", obj); + } + if (showMethods && !sort) { + var sortedObj = obj; + } else { + var propNames = []; + if (showMethods) { + for (var prop in obj) { + propNames.push(prop); + } + } else { + for (var prop in obj) { + if (typeof obj[prop] != "function") { propNames.push(prop); } + else dojo.debug(prop); + } + } + if (sort) propNames.sort(); + var sortedObj = {}; + dojo.lang.forEach(propNames, function(prop) { + sortedObj[prop] = obj[prop]; + }); + } + + return dojo.debug(type+": %o\n%2.o",obj,sortedObj); + } + + // otherwise just output the constructor + object, + // which is nice for a DOM element, etc + return dojo.debug(obj.constructor + ": ", obj); + } + + } else if (console.log != null) { + // using Safari or an old version of Firebug + dojo.hostenv.println=function() { + if (!djConfig.isDebug) { return ; } + // make sure we're only writing a single string to Safari's console + var args = dojo.lang.toArray(arguments); + console.log("DEBUG: " + args.join(" ")); + } + dojo.debug=dojo.hostenv.println; + } else { + // not supported + dojo.debug("dojo.debug.console requires Firebug > 0.4"); + } +} else if (dojo.render.html.opera) { + // using Opera 8.0 or later + if (opera && opera.postError) { + dojo.hostenv.println=opera.postError; + // summary: hook debugging up to Opera's postError routine + } else { + dojo.debug("dojo.debug.Opera requires Opera > 8.0"); + } +} + diff --git a/source/web/scripts/ajax/dojo/src/debug/deep.html b/source/web/scripts/ajax/dojo/src/debug/deep.html new file mode 100644 index 0000000000..1a22fbfc45 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/debug/deep.html @@ -0,0 +1,362 @@ + + +Deep Debugger + + + + + +

Javascript Object Browser

+ +
+ + + \ No newline at end of file diff --git a/source/web/scripts/ajax/dojo/src/debug/spacer.gif b/source/web/scripts/ajax/dojo/src/debug/spacer.gif new file mode 100644 index 0000000000..2ce50b5867 Binary files /dev/null and b/source/web/scripts/ajax/dojo/src/debug/spacer.gif differ diff --git a/source/web/scripts/ajax/dojo/src/dnd/DragAndDrop.js b/source/web/scripts/ajax/dojo/src/dnd/DragAndDrop.js new file mode 100644 index 0000000000..f8ac37212c --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/dnd/DragAndDrop.js @@ -0,0 +1,264 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.require("dojo.lang.common"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.lang.declare"); +dojo.provide("dojo.dnd.DragAndDrop"); + +// summary: +// Core "interfaces" for the participants in all DnD operations. +// Subclasses implement all of the actions outlined by these APIs, with +// most of the ones you probably care about being defined in +// HtmlDragAndDrop.js, which will be automatically included should you +// dojo.require("dojo.dnd.*");. +// +// In addition to the various actor classes, a global manager will be +// created/installed at dojo.dnd.dragManager. This manager object is of +// type dojo.dnd.DragManager and will be replaced by environment-specific +// managers. +// +// The 3 object types involved in any Drag and Drop operation are: +// * DragSource +// This is the item that can be selected for dragging. Drag +// sources can have "types" to help mediate whether or not various +// DropTargets will accept (or reject them). Most dragging actions +// are handled by the DragObject which the DragSource generates +// from its onDragStart method. +// * DragObject +// This, along with the manger, does most of the hard work of DnD. +// Implementations may rely on DragObject instances to implement +// "shadowing", "movement", or other kinds of DnD variations that +// affect the visual representation of the drag operation. +// * DropTarget +// Represents some section of the screen that can accept drag +// and drop events. DropTargets keep a list of accepted types +// which is checked agains the types of the respective DragSource +// objects that pass over it. DropTargets may implement behaviors +// that respond to drop events to take application-level actions. + +dojo.declare("dojo.dnd.DragSource", null, { + // String: + // what kind of drag source are we? Used to determine if we can be + // dropped on a given DropTarget + type: "", + + onDragEnd: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // stub handler that is called when dragging finishes. + }, + + onDragStart: function(/*dojo.dnd.DragEvent*/evt){ // dojo.dnd.DragObject + // summary: + // stub handler that is called when dragging starts. Subclasses + // should ensure that onDragStart *always* returns a + // dojo.dnd.DragObject instance. + }, + + onSelected: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // This function gets called when the DOM element was selected for + // dragging by the HtmlDragAndDropManager. + }, + + unregister: function(){ + // summary: remove this drag source from the manager + dojo.dnd.dragManager.unregisterDragSource(this); + }, + + reregister: function(){ + // summary: add this drag source to the manager + dojo.dnd.dragManager.registerDragSource(this); + } +}); + +dojo.declare("dojo.dnd.DragObject", null, { + // String: + // what kind of drag object are we? Used to determine if we can be + // dropped on a given DropTarget + type: "", + + register: function(){ + // summary: register this DragObject with the manager + var dm = dojo.dnd.dragManager; + if(dm["registerDragObject"]){ // side-effect prevention + dm.registerDragObject(this); + } + }, + + onDragStart: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // over-ridden by subclasses. Gets called directly after being + // created by the DragSource default action is to clone self as + // icon + }, + + onDragMove: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // Implemented by subclasses. Should change the UI for the drag + // icon i.e., "it moves itself" + }, + + onDragOver: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // stub handler that is called when the DragObject instance is + // "over" a DropTarget. + }, + + onDragOut: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // stub handler that is called when the DragObject instance leaves + // a DropTarget. + }, + + onDragEnd: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // stub handler that is called when dragging ends, either through + // dropping or cancelation. + }, + + // normal aliases + onDragLeave: dojo.lang.forward("onDragOut"), + onDragEnter: dojo.lang.forward("onDragOver"), + + // non-camel aliases + ondragout: dojo.lang.forward("onDragOut"), + ondragover: dojo.lang.forward("onDragOver") +}); + +dojo.declare("dojo.dnd.DropTarget", null, { + + acceptsType: function(/*String*/type){ + // summary: + // determines whether or not this DropTarget will accept the given + // type. The default behavior is to consult this.acceptedTypes and + // if "*" is a member, to always accept the type. + if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard + if(!dojo.lang.inArray(this.acceptedTypes, type)) { return false; } // Boolean + } + return true; // Boolean + }, + + accepts: function(/*Array*/dragObjects){ + // summary: + // determines if we'll accept all members of the passed array of + // dojo.dnd.DragObject instances + if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard + for (var i = 0; i < dragObjects.length; i++) { + if (!dojo.lang.inArray(this.acceptedTypes, + dragObjects[i].type)) { return false; } // Boolean + } + } + return true; // Boolean + }, + + unregister: function(){ + // summary: remove from the drag manager + dojo.dnd.dragManager.unregisterDropTarget(this); + }, + + onDragOver: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // stub handler that is called when DragObject instances are + // "over" this DropTarget. + }, + + onDragOut: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // stub handler that is called when DragObject instances are + // "leave" this DropTarget. + }, + + onDragMove: function(/*dojo.dnd.DragEvent*/evt){ + // summary: + // stub handler that is called when DragObject instances are + // moved across this DropTarget. May fire many times in the course + // of the drag operation but will end after onDragOut + }, + + onDropStart: function(/*dojo.dnd.DragEvent*/evt){ // Boolean + // summary: + // stub handler that is called when DragObject instances are + // dropped on this target. If true is returned from onDropStart, + // dropping proceeds, otherwise it's cancled. + }, + + onDrop: function(/*dojo.dnd.DragEvent*/evt){ + // summary: we're getting dropped on! + }, + + onDropEnd: function(){ + // summary: dropping is over + } +}, function(){ + this.acceptedTypes = []; +}); + +// NOTE: this interface is defined here for the convenience of the DragManager +// implementor. It is expected that in most cases it will be satisfied by +// extending a native event (DOM event in HTML and SVG). +dojo.dnd.DragEvent = function(){ + this.dragSource = null; + this.dragObject = null; + this.target = null; + this.eventStatus = "success"; + // + // can be one of: + // [ "dropSuccess", "dropFailure", "dragMove", + // "dragStart", "dragEnter", "dragLeave"] + // +} +/* + * The DragManager handles listening for low-level events and dispatching + * them to higher-level primitives like drag sources and drop targets. In + * order to do this, it must keep a list of the items. + */ +dojo.declare("dojo.dnd.DragManager", null, { + // Array: an array of currently selected DragSource objects + selectedSources: [], + // Array: all DragObjects we know about + dragObjects: [], + // Array: all DragSources we know about + dragSources: [], + registerDragSource: function(/*dojo.dnd.DragSource*/ source){ + // summary: called by DragSource class constructor + }, + // Array: all DropTargets we know about + dropTargets: [], + registerDropTarget: function(/*dojo.dnd.DropTarget*/ target){ + // summary: called by DropTarget class constructor + }, + // dojo.dnd.DropTarget: + // what was the last DropTarget instance we left in the drag phase? + lastDragTarget: null, + // dojo.dnd.DropTarget: + // the DropTarget the mouse is currently over + currentDragTarget: null, + onKeyDown: function(){ + // summary: generic handler called by low-level events + }, + onMouseOut: function(){ + // summary: generic handler called by low-level events + }, + onMouseMove: function(){ + // summary: generic handler called by low-level events + }, + onMouseUp: function(){ + // summary: generic handler called by low-level events + } +}); + +// NOTE: despite the existance of the DragManager class, there will be a +// singleton drag manager provided by the renderer-specific D&D support code. +// It is therefore sane for us to assign instance variables to the DragManager +// prototype + +// The renderer-specific file will define the following object: +// dojo.dnd.dragManager = null; diff --git a/source/web/scripts/ajax/dojo/src/dnd/HtmlDragAndDrop.js b/source/web/scripts/ajax/dojo/src/dnd/HtmlDragAndDrop.js new file mode 100644 index 0000000000..a916532d99 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/dnd/HtmlDragAndDrop.js @@ -0,0 +1,519 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.dnd.HtmlDragAndDrop"); + +dojo.require("dojo.dnd.HtmlDragManager"); +dojo.require("dojo.dnd.DragAndDrop"); + +dojo.require("dojo.html.*"); +dojo.require("dojo.html.display"); +dojo.require("dojo.html.util"); +dojo.require("dojo.html.selection"); +dojo.require("dojo.html.iframe"); +dojo.require("dojo.lang.extras"); +dojo.require("dojo.lfx.*"); +dojo.require("dojo.event.*"); + +dojo.declare("dojo.dnd.HtmlDragSource", dojo.dnd.DragSource, { + dragClass: "", // CSS classname(s) applied to node when it is being dragged + + onDragStart: function(){ + var dragObj = new dojo.dnd.HtmlDragObject(this.dragObject, this.type); + if(this.dragClass){ + dragObj.dragClass = this.dragClass; + } + + if(this.constrainToContainer){ + dragObj.constrainTo(this.constrainingContainer || this.domNode.parentNode); + } + + return dragObj; + }, + + setDragHandle: function(node){ + node = dojo.byId(node); + dojo.dnd.dragManager.unregisterDragSource(this); + this.domNode = node; + dojo.dnd.dragManager.registerDragSource(this); + }, + + setDragTarget: function(node){ + this.dragObject = node; + }, + + constrainTo: function(container){ + this.constrainToContainer = true; + if(container){ + this.constrainingContainer = container; + } + }, + + /* + * + * see dojo.dnd.DragSource.onSelected + */ + onSelected: function(){ + for(var i=0; i this.constraints.maxX) { x = this.constraints.maxX; } + if (y > this.constraints.maxY) { y = this.constraints.maxY; } + } + + this.setAbsolutePosition(x, y); + + dojo.event.topic.publish('dragMove', { source: this } ); + }, + + /** + * Set the position of the drag clone. (x,y) is relative to . + */ + setAbsolutePosition: function(x, y){ + // The drag clone is attached to document.body so this is trivial + if(!this.disableY) { this.dragClone.style.top = y + "px"; } + if(!this.disableX) { this.dragClone.style.left = x + "px"; } + }, + + + /** + * If the drag operation returned a success we remove the clone of + * ourself from the original position. If the drag operation returned + * failure we slide back over to where we came from and end the operation + * with a little grace. + */ + onDragEnd: function(e){ + switch(e.dragStatus){ + + case "dropSuccess": + dojo.html.removeNode(this.dragClone); + this.dragClone = null; + break; + + case "dropFailure": // slide back to the start + var startCoords = dojo.html.getAbsolutePosition(this.dragClone, true); + // offset the end so the effect can be seen + var endCoords = { left: this.dragStartPosition.x + 1, + top: this.dragStartPosition.y + 1}; + + // animate + var anim = dojo.lfx.slideTo(this.dragClone, endCoords, 300); + var dragObject = this; + dojo.event.connect(anim, "onEnd", function(e){ + // pause for a second (not literally) and disappear + // dojo.lang.setTimeout(function() { + dojo.html.removeNode(dragObject.dragClone); + // Allow drag clone to be gc'ed + dragObject.dragClone = null; + // }, + // 50); + }); + anim.play(); + break; + } + + dojo.event.topic.publish('dragEnd', { source: this } ); + }, + + constrainTo: function(container){ + this.constrainToContainer=true; + if(container){ + this.constrainingContainer = container; + }else{ + this.constrainingContainer = this.domNode.parentNode; + } + } + }, + function(node, type){ + this.domNode = dojo.byId(node); + this.type = type; + this.constrainToContainer = false; + this.dragSource = null; + // this.register(); + dojo.dnd.DragObject.prototype.register.call(this); + } +); + +dojo.declare("dojo.dnd.HtmlDropTarget", + dojo.dnd.DropTarget, + { + vertical: false, + onDragOver: function(e){ + if(!this.accepts(e.dragObjects)){ return false; } + + // cache the positions of the child nodes + this.childBoxes = []; + for(var i = 0, child; i < this.domNode.childNodes.length; i++){ + child = this.domNode.childNodes[i]; + if(child.nodeType != dojo.html.ELEMENT_NODE){ continue; } + var pos = dojo.html.getAbsolutePosition(child, true); + var inner = dojo.html.getBorderBox(child); + this.childBoxes.push({top: pos.y, bottom: pos.y+inner.height, + left: pos.x, right: pos.x+inner.width, height: inner.height, + width: inner.width, node: child}); + } + + // TODO: use dummy node + + return true; + }, + + _getNodeUnderMouse: function(e){ + // find the child + for(var i = 0, child; i < this.childBoxes.length; i++){ + with(this.childBoxes[i]){ + if (e.pageX >= left && e.pageX <= right && + e.pageY >= top && e.pageY <= bottom){ return i; } + } + } + + return -1; + }, + + createDropIndicator: function(){ + this.dropIndicator = document.createElement("div"); + with(this.dropIndicator.style){ + position = "absolute"; + zIndex = 999; + if(this.vertical){ + borderLeftWidth = "1px"; + borderLeftColor = "black"; + borderLeftStyle = "solid"; + height = dojo.html.getBorderBox(this.domNode).height + "px"; + top = dojo.html.getAbsolutePosition(this.domNode, true).y + "px"; + }else{ + borderTopWidth = "1px"; + borderTopColor = "black"; + borderTopStyle = "solid"; + width = dojo.html.getBorderBox(this.domNode).width + "px"; + left = dojo.html.getAbsolutePosition(this.domNode, true).x + "px"; + } + } + }, + + onDragMove: function(e, dragObjects){ + var i = this._getNodeUnderMouse(e); + + if(!this.dropIndicator){ + this.createDropIndicator(); + } + + var gravity = this.vertical ? dojo.html.gravity.WEST : dojo.html.gravity.NORTH; + var hide = false; + if(i < 0){ + if(this.childBoxes.length){ + var before = (dojo.html.gravity(this.childBoxes[0].node, e) & gravity); + if(before){ hide = true; } + }else{ + var before = true; + } + }else{ + var child = this.childBoxes[i]; + var before = (dojo.html.gravity(child.node, e) & gravity); + if(child.node === dragObjects[0].dragSource.domNode){ + hide = true; + }else{ + var currentPosChild = before ? + (i>0?this.childBoxes[i-1]:child) : + (i + * (draggable selection) + * (dragObject generation) + * mouse-move -> + * (draggable movement) + * (droppable detection) + * (inform droppable) + * (inform dragObject) + * mouse-up + * (inform/destroy dragObject) + * (inform draggable) + * (inform droppable) + * 2.) mouse-down -> mouse-down + * (click-hold context menu) + * 3.) mouse-click -> + * (draggable selection) + * shift-mouse-click -> + * (augment draggable selection) + * mouse-down -> + * (dragObject generation) + * mouse-move -> + * (draggable movement) + * (droppable detection) + * (inform droppable) + * (inform dragObject) + * mouse-up + * (inform draggable) + * (inform droppable) + * 4.) mouse-up + * (clobber draggable selection) + */ + disabled: false, // to kill all dragging! + nestedTargets: false, + mouseDownTimer: null, // used for click-hold operations + dsCounter: 0, + dsPrefix: "dojoDragSource", + + // dimension calculation cache for use durring drag + dropTargetDimensions: [], + + currentDropTarget: null, + // currentDropTargetPoints: null, + previousDropTarget: null, + _dragTriggered: false, + + selectedSources: [], + dragObjects: [], + dragSources: [], + + // mouse position properties + currentX: null, + currentY: null, + lastX: null, + lastY: null, + mouseDownX: null, + mouseDownY: null, + threshold: 7, + + dropAcceptable: false, + + cancelEvent: function(e){ e.stopPropagation(); e.preventDefault();}, + + // method over-rides + registerDragSource: function(ds){ + //dojo.profile.start("register DragSource"); + + if(ds["domNode"]){ + // FIXME: dragSource objects SHOULD have some sort of property that + // references their DOM node, we shouldn't just be passing nodes and + // expecting it to work. + //dojo.profile.start("register DragSource 1"); + var dp = this.dsPrefix; + var dpIdx = dp+"Idx_"+(this.dsCounter++); + ds.dragSourceId = dpIdx; + this.dragSources[dpIdx] = ds; + ds.domNode.setAttribute(dp, dpIdx); + //dojo.profile.end("register DragSource 1"); + + //dojo.profile.start("register DragSource 2"); + + // so we can drag links + if(dojo.render.html.ie){ + //dojo.profile.start("register DragSource IE"); + + dojo.event.browser.addListener(ds.domNode, "ondragstart", this.cancelEvent); + // terribly slow + //dojo.event.connect(ds.domNode, "ondragstart", this.cancelEvent); + //dojo.profile.end("register DragSource IE"); + + } + //dojo.profile.end("register DragSource 2"); + + } + //dojo.profile.end("register DragSource"); + }, + + unregisterDragSource: function(ds){ + if (ds["domNode"]){ + var dp = this.dsPrefix; + var dpIdx = ds.dragSourceId; + delete ds.dragSourceId; + delete this.dragSources[dpIdx]; + ds.domNode.setAttribute(dp, null); + if(dojo.render.html.ie){ + dojo.event.browser.removeListener(ds.domNode, "ondragstart", this.cancelEvent); + } + } + }, + + registerDropTarget: function(dt){ + this.dropTargets.push(dt); + }, + + unregisterDropTarget: function(dt){ + var index = dojo.lang.find(this.dropTargets, dt, true); + if (index>=0) { + this.dropTargets.splice(index, 1); + } + }, + + /** + * Get the DOM element that is meant to drag. + * Loop through the parent nodes of the event target until + * the element is found that was created as a DragSource and + * return it. + * + * @param event object The event for which to get the drag source. + */ + getDragSource: function(e){ + var tn = e.target; + if(tn === dojo.body()){ return; } + var ta = dojo.html.getAttribute(tn, this.dsPrefix); + while((!ta)&&(tn)){ + tn = tn.parentNode; + if((!tn)||(tn === dojo.body())){ return; } + ta = dojo.html.getAttribute(tn, this.dsPrefix); + } + return this.dragSources[ta]; + }, + + onKeyDown: function(e){ + }, + + onMouseDown: function(e){ + if(this.disabled) { return; } + + // only begin on left click + if(dojo.render.html.ie) { + if(e.button != 1) { return; } + } else if(e.which != 1) { + return; + } + + var target = e.target.nodeType == dojo.html.TEXT_NODE ? + e.target.parentNode : e.target; + + // do not start drag involvement if the user is interacting with + // a form element. + if(dojo.html.isTag(target, "button", "textarea", "input", "select", "option")) { + return; + } + + // find a selection object, if one is a parent of the source node + var ds = this.getDragSource(e); + + // this line is important. if we aren't selecting anything then + // we need to return now, so preventDefault() isn't called, and thus + // the event is propogated to other handling code + if(!ds){ return; } + + if(!dojo.lang.inArray(this.selectedSources, ds)){ + this.selectedSources.push(ds); + ds.onSelected(); + } + + this.mouseDownX = e.pageX; + this.mouseDownY = e.pageY; + + // Must stop the mouse down from being propogated, or otherwise can't + // drag links in firefox. + // WARNING: preventing the default action on all mousedown events + // prevents user interaction with the contents. + e.preventDefault(); + + dojo.event.connect(document, "onmousemove", this, "onMouseMove"); + }, + + onMouseUp: function(e, cancel){ + // if we aren't dragging then ignore the mouse-up + // (in particular, don't call preventDefault(), because other + // code may need to process this event) + if(this.selectedSources.length==0){ + return; + } + + this.mouseDownX = null; + this.mouseDownY = null; + this._dragTriggered = false; + // e.preventDefault(); + e.dragSource = this.dragSource; + // let ctrl be used for multiselect or another action + // if I use same key to trigger treeV3 node selection and here, + // I have bugs with drag'n'drop. why ?? no idea.. + if((!e.shiftKey)&&(!e.ctrlKey)){ + //if(!e.shiftKey){ + if(this.currentDropTarget) { + this.currentDropTarget.onDropStart(); + } + dojo.lang.forEach(this.dragObjects, function(tempDragObj){ + var ret = null; + if(!tempDragObj){ return; } + if(this.currentDropTarget) { + e.dragObject = tempDragObj; + + // NOTE: we can't get anything but the current drop target + // here since the drag shadow blocks mouse-over events. + // This is probelematic for dropping "in" something + var ce = this.currentDropTarget.domNode.childNodes; + if(ce.length > 0){ + e.dropTarget = ce[0]; + while(e.dropTarget == tempDragObj.domNode){ + e.dropTarget = e.dropTarget.nextSibling; + } + }else{ + e.dropTarget = this.currentDropTarget.domNode; + } + if(this.dropAcceptable){ + ret = this.currentDropTarget.onDrop(e); + }else{ + this.currentDropTarget.onDragOut(e); + } + } + + e.dragStatus = this.dropAcceptable && ret ? "dropSuccess" : "dropFailure"; + // decouple the calls for onDragEnd, so they don't block the execution here + // ie. if the onDragEnd would call an alert, the execution here is blocked until the + // user has confirmed the alert box and then the rest of the dnd code is executed + // while the mouse doesnt "hold" the dragged object anymore ... and so on + dojo.lang.delayThese([ + function() { + // in FF1.5 this throws an exception, see + // http://dojotoolkit.org/pipermail/dojo-interest/2006-April/006751.html + try{ + tempDragObj.dragSource.onDragEnd(e) + } catch(err) { + // since the problem seems passing e, we just copy all + // properties and try the copy ... + var ecopy = {}; + for (var i in e) { + if (i=="type") { // the type property contains the exception, no idea why... + ecopy.type = "mouseup"; + continue; + } + ecopy[i] = e[i]; + } + tempDragObj.dragSource.onDragEnd(ecopy); + } + } + , function() {tempDragObj.onDragEnd(e)}]); + }, this); + + this.selectedSources = []; + this.dragObjects = []; + this.dragSource = null; + if(this.currentDropTarget) { + this.currentDropTarget.onDropEnd(); + } + } else { + //dojo.debug("special click"); + } + + dojo.event.disconnect(document, "onmousemove", this, "onMouseMove"); + this.currentDropTarget = null; + }, + + onScroll: function(){ + //dojo.profile.start("DNDManager updateoffset"); + for(var i = 0; i < this.dragObjects.length; i++) { + if(this.dragObjects[i].updateDragOffset) { + this.dragObjects[i].updateDragOffset(); + } + } + //dojo.profile.end("DNDManager updateoffset"); + + // TODO: do not recalculate, only adjust coordinates + if (this.dragObjects.length) { + this.cacheTargetLocations(); + } + }, + + _dragStartDistance: function(x, y){ + if((!this.mouseDownX)||(!this.mouseDownX)){ + return; + } + var dx = Math.abs(x-this.mouseDownX); + var dx2 = dx*dx; + var dy = Math.abs(y-this.mouseDownY); + var dy2 = dy*dy; + return parseInt(Math.sqrt(dx2+dy2), 10); + }, + + cacheTargetLocations: function(){ + dojo.profile.start("cacheTargetLocations"); + + this.dropTargetDimensions = []; + dojo.lang.forEach(this.dropTargets, function(tempTarget){ + var tn = tempTarget.domNode; + //only cache dropTarget which can accept current dragSource + if(!tn || !tempTarget.accepts([this.dragSource])){ return; } + var abs = dojo.html.getAbsolutePosition(tn, true); + var bb = dojo.html.getBorderBox(tn); + this.dropTargetDimensions.push([ + [abs.x, abs.y], // upper-left + // lower-right + [ abs.x+bb.width, abs.y+bb.height ], + tempTarget + ]); + //dojo.debug("Cached for "+tempTarget) + }, this); + + dojo.profile.end("cacheTargetLocations"); + + //dojo.debug("Cache locations") + }, + + onMouseMove: function(e){ + if((dojo.render.html.ie)&&(e.button != 1)){ + // Oooops - mouse up occurred - e.g. when mouse was not over the + // window. I don't think we can detect this for FF - but at least + // we can be nice in IE. + this.currentDropTarget = null; + this.onMouseUp(e, true); + return; + } + + // if we've got some sources, but no drag objects, we need to send + // onDragStart to all the right parties and get things lined up for + // drop target detection + + if( (this.selectedSources.length)&& + (!this.dragObjects.length) ){ + var dx; + var dy; + if(!this._dragTriggered){ + this._dragTriggered = (this._dragStartDistance(e.pageX, e.pageY) > this.threshold); + if(!this._dragTriggered){ return; } + dx = e.pageX - this.mouseDownX; + dy = e.pageY - this.mouseDownY; + } + + // the first element is always our dragSource, if there are multiple + // selectedSources (elements that move along) then the first one is the master + // and for it the events will be fired etc. + this.dragSource = this.selectedSources[0]; + + dojo.lang.forEach(this.selectedSources, function(tempSource){ + if(!tempSource){ return; } + var tdo = tempSource.onDragStart(e); + if(tdo){ + tdo.onDragStart(e); + + // "bump" the drag object to account for the drag threshold + tdo.dragOffset.y += dy; + tdo.dragOffset.x += dx; + tdo.dragSource = tempSource; + + this.dragObjects.push(tdo); + } + }, this); + + /* clean previous drop target in dragStart */ + this.previousDropTarget = null; + + this.cacheTargetLocations(); + } + + // FIXME: we need to add dragSources and dragObjects to e + dojo.lang.forEach(this.dragObjects, function(dragObj){ + if(dragObj){ dragObj.onDragMove(e); } + }); + + // if we have a current drop target, check to see if we're outside of + // it. If so, do all the actions that need doing. + if(this.currentDropTarget){ + //dojo.debug(dojo.html.hasParent(this.currentDropTarget.domNode)) + var c = dojo.html.toCoordinateObject(this.currentDropTarget.domNode, true); + // var dtp = this.currentDropTargetPoints; + var dtp = [ + [c.x,c.y], [c.x+c.width, c.y+c.height] + ]; + } + + if((!this.nestedTargets)&&(dtp)&&(this.isInsideBox(e, dtp))){ + if(this.dropAcceptable){ + this.currentDropTarget.onDragMove(e, this.dragObjects); + } + }else{ + // FIXME: need to fix the event object! + // see if we can find a better drop target + var bestBox = this.findBestTarget(e); + + if(bestBox.target === null){ + if(this.currentDropTarget){ + this.currentDropTarget.onDragOut(e); + this.previousDropTarget = this.currentDropTarget; + this.currentDropTarget = null; + // this.currentDropTargetPoints = null; + } + this.dropAcceptable = false; + return; + } + + if(this.currentDropTarget !== bestBox.target){ + if(this.currentDropTarget){ + this.previousDropTarget = this.currentDropTarget; + this.currentDropTarget.onDragOut(e); + } + this.currentDropTarget = bestBox.target; + // this.currentDropTargetPoints = bestBox.points; + e.dragObjects = this.dragObjects; + this.dropAcceptable = this.currentDropTarget.onDragOver(e); + + }else{ + if(this.dropAcceptable){ + this.currentDropTarget.onDragMove(e, this.dragObjects); + } + } + } + }, + + findBestTarget: function(e) { + var _this = this; + var bestBox = new Object(); + bestBox.target = null; + bestBox.points = null; + dojo.lang.every(this.dropTargetDimensions, function(tmpDA) { + if(!_this.isInsideBox(e, tmpDA)){ + return true; + } + + bestBox.target = tmpDA[2]; + bestBox.points = tmpDA; + // continue iterating only if _this.nestedTargets == true + return Boolean(_this.nestedTargets); + }); + + return bestBox; + }, + + isInsideBox: function(e, coords){ + if( (e.pageX > coords[0][0])&& + (e.pageX < coords[1][0])&& + (e.pageY > coords[0][1])&& + (e.pageY < coords[1][1]) ){ + return true; + } + return false; + }, + + onMouseOver: function(e){ + }, + + onMouseOut: function(e){ + } +}); + +dojo.dnd.dragManager = new dojo.dnd.HtmlDragManager(); + +// global namespace protection closure +(function(){ + var d = document; + var dm = dojo.dnd.dragManager; + //TODO: when focus manager is ready, dragManager should be rewritten to use it + // set up event handlers on the document (or no?) + dojo.event.connect(d, "onkeydown", dm, "onKeyDown"); + dojo.event.connect(d, "onmouseover", dm, "onMouseOver"); + dojo.event.connect(d, "onmouseout", dm, "onMouseOut"); + dojo.event.connect(d, "onmousedown", dm, "onMouseDown"); + dojo.event.connect(d, "onmouseup", dm, "onMouseUp"); + // TODO: process scrolling of elements, not only window (focus manager would + // probably come to rescue here as well) + dojo.event.connect(window, "onscroll", dm, "onScroll"); +})(); diff --git a/source/web/scripts/ajax/dojo/src/dnd/HtmlDragMove.js b/source/web/scripts/ajax/dojo/src/dnd/HtmlDragMove.js new file mode 100644 index 0000000000..f1529f868d --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/dnd/HtmlDragMove.js @@ -0,0 +1,89 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.dnd.HtmlDragMove"); +dojo.require("dojo.dnd.*"); + +dojo.declare("dojo.dnd.HtmlDragMoveSource", dojo.dnd.HtmlDragSource, { + onDragStart: function(){ + var dragObj = new dojo.dnd.HtmlDragMoveObject(this.dragObject, this.type); + if (this.constrainToContainer) { + dragObj.constrainTo(this.constrainingContainer); + } + return dragObj; + }, + /* + * see dojo.dnd.HtmlDragSource.onSelected + */ + onSelected: function() { + for (var i=0; i it was allowed before, no accept check is needed + if (position=="onto" || + (!this.isAdjacentNode(sourceTreeNode, position) + && this.controller.canMove(sourceTreeNode, this.treeNode.parent) + ) + ) { + return position; + } else { + return false; + } + + }, + + onDragOut: function(e) { + this.clearAutoExpandTimer(); + + this.hideIndicator(); + }, + + + clearAutoExpandTimer: function() { + if (this.autoExpandTimer) { + clearTimeout(this.autoExpandTimer); + this.autoExpandTimer = null; + } + }, + + + + onDragMove: function(e, dragObjects){ + + var sourceTreeNode = dragObjects[0].treeNode; + + var position = this.getAcceptPosition(e, sourceTreeNode); + + if (position) { + this.showIndicator(position); + } + + }, + + isAdjacentNode: function(sourceNode, position) { + + if (sourceNode === this.treeNode) return true; + if (sourceNode.getNextSibling() === this.treeNode && position=="before") return true; + if (sourceNode.getPreviousSibling() === this.treeNode && position=="after") return true; + + return false; + }, + + + /* get DNDMode and see which position e fits */ + getPosition: function(e, DNDMode) { + var node = dojo.byId(this.treeNode.labelNode); + var mousey = e.pageY || e.clientY + dojo.body().scrollTop; + var nodey = dojo.html.getAbsolutePosition(node).y; + var height = dojo.html.getBorderBox(node).height; + + var relY = mousey - nodey; + var p = relY / height; + + var position = ""; // "" <=> forbidden + if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO + && DNDMode & dojo.widget.Tree.prototype.DNDModes.BETWEEN) { + if (p<=0.3) { + position = "before"; + } else if (p<=0.7) { + position = "onto"; + } else { + position = "after"; + } + } else if (DNDMode & dojo.widget.Tree.prototype.DNDModes.BETWEEN) { + if (p<=0.5) { + position = "before"; + } else { + position = "after"; + } + } + else if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO) { + position = "onto"; + } + + + return position; + }, + + + + getTargetParentIndex: function(sourceTreeNode, position) { + + var index = position == "before" ? this.treeNode.getParentIndex() : this.treeNode.getParentIndex()+1; + if (this.treeNode.parent === sourceTreeNode.parent + && this.treeNode.getParentIndex() > sourceTreeNode.getParentIndex()) { + index--; // dragging a node is different for simple move bacause of before-after issues + } + + return index; + }, + + + onDrop: function(e){ + // onDragOut will clean position + + + var position = this.position; + +//dojo.debug(position); + + this.onDragOut(e); + + var sourceTreeNode = e.dragObject.treeNode; + + if (!dojo.lang.isObject(sourceTreeNode)) { + dojo.raise("TreeNode not found in dragObject") + } + + if (position == "onto") { + return this.controller.move(sourceTreeNode, this.treeNode, 0); + } else { + var index = this.getTargetParentIndex(sourceTreeNode, position); + return this.controller.move(sourceTreeNode, this.treeNode.parent, index); + } + + //dojo.debug('drop2'); + + + + } + + +}); + + + +dojo.dnd.TreeDNDController = function(treeController) { + + // I use this controller to perform actions + this.treeController = treeController; + + this.dragSources = {}; + + this.dropTargets = {}; + +} + +dojo.lang.extend(dojo.dnd.TreeDNDController, { + + + listenTree: function(tree) { + //dojo.debug("Listen tree "+tree); + dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode"); + dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom"); + dojo.event.topic.subscribe(tree.eventNames.moveTo, this, "onMoveTo"); + dojo.event.topic.subscribe(tree.eventNames.addChild, this, "onAddChild"); + dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode"); + dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy"); + }, + + + unlistenTree: function(tree) { + //dojo.debug("Listen tree "+tree); + dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode"); + dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom"); + dojo.event.topic.unsubscribe(tree.eventNames.moveTo, this, "onMoveTo"); + dojo.event.topic.unsubscribe(tree.eventNames.addChild, this, "onAddChild"); + dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode"); + dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy"); + }, + + onTreeDestroy: function(message) { + this.unlistenTree(message.source); + // I'm not widget so don't use destroy() call and dieWithTree + }, + + onCreateDOMNode: function(message) { + this.registerDNDNode(message.source); + }, + + onAddChild: function(message) { + this.registerDNDNode(message.child); + }, + + onMoveFrom: function(message) { + var _this = this; + dojo.lang.forEach( + message.child.getDescendants(), + function(node) { _this.unregisterDNDNode(node); } + ); + }, + + onMoveTo: function(message) { + var _this = this; + dojo.lang.forEach( + message.child.getDescendants(), + function(node) { _this.registerDNDNode(node); } + ); + }, + + /** + * Controller(node model) creates DNDNodes because it passes itself to node for synchroneous drops processing + * I can't process DnD with events cause an event can't return result success/false + */ + registerDNDNode: function(node) { + if (!node.tree.DNDMode) return; + +//dojo.debug("registerDNDNode "+node); + + /* I drag label, not domNode, because large domNodes are very slow to copy and large to drag */ + + var source = null; + var target = null; + + if (!node.actionIsDisabled(node.actions.MOVE)) { + //dojo.debug("reg source") + var source = new dojo.dnd.TreeDragSource(node.labelNode, this, node.tree.widgetId, node); + this.dragSources[node.widgetId] = source; + } + + var target = new dojo.dnd.TreeDropTarget(node.labelNode, this.treeController, node.tree.DNDAcceptTypes, node); + + this.dropTargets[node.widgetId] = target; + + }, + + + unregisterDNDNode: function(node) { + + if (this.dragSources[node.widgetId]) { + dojo.dnd.dragManager.unregisterDragSource(this.dragSources[node.widgetId]); + delete this.dragSources[node.widgetId]; + } + + if (this.dropTargets[node.widgetId]) { + dojo.dnd.dragManager.unregisterDropTarget(this.dropTargets[node.widgetId]); + delete this.dropTargets[node.widgetId]; + } + } + + + + + +}); diff --git a/source/web/scripts/ajax/dojo/src/dnd/TreeDragAndDropV3.js b/source/web/scripts/ajax/dojo/src/dnd/TreeDragAndDropV3.js new file mode 100644 index 0000000000..d2e4a1dcde --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/dnd/TreeDragAndDropV3.js @@ -0,0 +1,403 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +/** + * TreeDrag* specialized on managing subtree drags + * It selects nodes and visualises what's going on, + * but delegates real actions upon tree to the controller + * + * This code is considered a part of controller +*/ + +dojo.provide("dojo.dnd.TreeDragAndDropV3"); + +dojo.require("dojo.dnd.HtmlDragAndDrop"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.lang.array"); +dojo.require("dojo.lang.extras"); +dojo.require("dojo.Deferred"); +dojo.require("dojo.html.layout"); + +// FIXME: if controller can't move then skip node on move start +dojo.dnd.TreeDragSourceV3 = function(node, syncController, type, treeNode){ + //dojo.profile.start("TreeDragSourceV3 "+treeNode); + this.controller = syncController; + this.treeNode = treeNode; + + dojo.dnd.HtmlDragSource.call(this, node, type); + //dojo.profile.end("TreeDragSourceV3 "+treeNode); +} + +dojo.inherits(dojo.dnd.TreeDragSourceV3, dojo.dnd.HtmlDragSource); + + +// ....................................... + +dojo.dnd.TreeDropTargetV3 = function(domNode, controller, type, treeNode){ + + this.treeNode = treeNode; + this.controller = controller; // I will sync-ly process drops + + dojo.dnd.HtmlDropTarget.call(this, domNode, type); +} + +dojo.inherits(dojo.dnd.TreeDropTargetV3, dojo.dnd.HtmlDropTarget); + +dojo.lang.extend(dojo.dnd.TreeDropTargetV3, { + + autoExpandDelay: 1500, + autoExpandTimer: null, + + + position: null, + + indicatorStyle: "2px black groove", + + showIndicator: function(position) { + + // do not change style too often, cause of blinking possible + if (this.position == position) { + return; + } + + //dojo.debug("set position for "+this.treeNode) + + this.hideIndicator(); + + this.position = position; + + var node = this.treeNode; + + + node.contentNode.style.width = dojo.html.getBorderBox(node.labelNode).width + "px"; + + if (position == "onto") { + node.contentNode.style.border = this.indicatorStyle; + } else { + // FIXME: bottom-top or highlight should cover ONLY top/bottom or div itself, + // not span whole line (try Dnd) + // FAILURE: Can't put span inside div: multiline bottom-top will span multiple lines + if (position == "before") { + node.contentNode.style.borderTop = this.indicatorStyle; + } else if (position == "after") { + node.contentNode.style.borderBottom = this.indicatorStyle; + } + } + }, + + hideIndicator: function() { + this.treeNode.contentNode.style.borderBottom = ""; + this.treeNode.contentNode.style.borderTop = ""; + this.treeNode.contentNode.style.border = ""; + this.treeNode.contentNode.style.width="" + this.position = null; + }, + + + + // is the target possibly ok ? + // This function is run on dragOver, but drop possibility is also determined by position over node + // that's why acceptsWithPosition is called + // doesnt take index into account ( can change while moving mouse w/o changing target ) + /** + * Coarse (tree-level) access check. + * We can't determine real accepts status w/o position + */ + onDragOver: function(e){ + //dojo.debug("onDragOver for "+e); + + var accepts = dojo.dnd.HtmlDropTarget.prototype.onDragOver.apply(this, arguments); + + //dojo.debug("TreeDropTarget.onDragOver accepts:"+accepts) + + if (accepts && this.treeNode.isFolder && !this.treeNode.isExpanded) { + this.setAutoExpandTimer(); + } + + if (accepts) { + this.cacheNodeCoords(); + } + + + return accepts; + }, + + /* Parent.onDragOver calls this function to get accepts status */ + accepts: function(dragObjects) { + + var accepts = dojo.dnd.HtmlDropTarget.prototype.accepts.apply(this, arguments); + + //dojo.debug("accepts "+accepts); + + if (!accepts) return false; + + for(var i=0; i it was allowed before, no accept check is needed + if (position=="onto") { + return position; + } + + for(var i=0; i forbidden + if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO + && DndMode & dojo.widget.TreeV3.prototype.DndModes.BETWEEN) { + //dojo.debug("BOTH"); + if (p<=0.33) { + position = "before"; + // if children are expanded then I ignore understrike, cause it is confusing with firstChild + // but for last nodes I put understrike there + } else if (p<=0.66 || this.treeNode.isExpanded && this.treeNode.children.length && !this.treeNode.isLastChild()) { + position = "onto"; + } else { + position = "after"; + } + } else if (DndMode & dojo.widget.TreeV3.prototype.DndModes.BETWEEN) { + //dojo.debug("BETWEEN"); + if (p<=0.5 || this.treeNode.isExpanded && this.treeNode.children.length && !this.treeNode.isLastChild()) { + position = "before"; + } else { + position = "after"; + } + } + else if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO) { + //dojo.debug("ONTO"); + position = "onto"; + } + + //dojo.debug(position); + + return position; + }, + + + + getTargetParentIndex: function(source, position) { + + var index = position == "before" ? this.treeNode.getParentIndex() : this.treeNode.getParentIndex()+1; + if (source.treeNode + && this.treeNode.parent === source.treeNode.parent + && this.treeNode.getParentIndex() > source.treeNode.getParentIndex()) { + index--; // dragging a node is different for simple move bacause of before-after issues + } + + return index; + }, + + + onDrop: function(e) { + // onDropEnd will clean position + + + var position = this.position; + +//dojo.debug(position); + var source = e.dragObject.dragSource; + + //dojo.debug("onDrop "+source.treeNode+" " + position + " "+this.treeNode); + + + var targetParent, targetIndex; + if (position == "onto") { + targetParent = this.treeNode; + targetIndex = 0; + } else { + targetIndex = this.getTargetParentIndex(source, position); + targetParent = this.treeNode.parent; + } + + //dojo.profile.start("onDrop "+sourceTreeNode); + var r = this.getDropHandler(e, source, targetParent, targetIndex)(); + + //dojo.profile.end("onDrop "+sourceTreeNode); + + return r; + + }, + + /** + * determine, which action I should perform with nodes + * e.g move, clone.. + */ + getDropHandler: function(e, source, targetParent, targetIndex) { + var handler; + var _this = this; + handler = function () { + var result; + + //dojo.debug("Move "+source.treeNode+" to parent "+targetParent+":"+targetIndex); + if (source.treeNode) { + result = _this.controller.move(source.treeNode, targetParent, targetIndex, true); + //dojo.debug("moved "+result); + } else { + if (dojo.lang.isFunction(source.onDrop)) { + source.onDrop(targetParent, targetIndex); + } + + var treeNode = source.getTreeNode(); + if (treeNode) { + result = _this.controller.createChild(targetParent, targetIndex, treeNode, true); + } else { + result = true; + } + } + + if (result instanceof dojo.Deferred) { + // this Deferred is always sync + var isSuccess = result.fired == 0; + if (!isSuccess) { + _this.handleDropError(source, targetParent, targetIndex, result); + } + + return isSuccess; + + } else { + return result; + } + } + + return handler; + }, + + + handleDropError: function(source, parent, index, result) { + dojo.debug("TreeDropTargetV3.handleDropError: DND error occured"); + dojo.debugShallow(result); + } + + +}); + diff --git a/source/web/scripts/ajax/dojo/src/dnd/__package__.js b/source/web/scripts/ajax/dojo/src/dnd/__package__.js new file mode 100644 index 0000000000..0a93fd2bb1 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/dnd/__package__.js @@ -0,0 +1,16 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: ["dojo.dnd.DragAndDrop"], + browser: ["dojo.dnd.HtmlDragAndDrop"], + dashboard: ["dojo.dnd.HtmlDragAndDrop"] +}); +dojo.provide("dojo.dnd.*"); diff --git a/source/web/scripts/ajax/dojo/src/docs.js b/source/web/scripts/ajax/dojo/src/docs.js new file mode 100644 index 0000000000..ec7657cf4f --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/docs.js @@ -0,0 +1,671 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.docs"); +dojo.require("dojo.io.*"); +dojo.require("dojo.event.topic"); +dojo.require("dojo.rpc.JotService"); +dojo.require("dojo.dom"); +dojo.require("dojo.uri.Uri"); +dojo.require("dojo.Deferred"); +dojo.require("dojo.DeferredList"); + +/* + * TODO: + * + * Package summary needs to compensate for "is" + * Handle host environments + * Deal with dojo.widget weirdness + * Parse parameters + * Limit function parameters to only the valid ones (Involves packing parameters onto meta during rewriting) + * + */ + +dojo.docs = new function() { + this._url = dojo.uri.dojoUri("docscripts"); + this._rpc = new dojo.rpc.JotService; + this._rpc.serviceUrl = dojo.uri.dojoUri("docscripts/jsonrpc.php"); +}; +dojo.lang.mixin(dojo.docs, { + _count: 0, + _callbacks: {function_names: []}, + _cache: {}, // Saves the JSON objects in cache + require: function(/*String*/ require, /*bool*/ sync) { + dojo.debug("require(): " + require); + var parts = require.split("/"); + + var size = parts.length; + var deferred = new dojo.Deferred; + var args = { + mimetype: "text/json", + load: function(type, data){ + dojo.debug("require(): loaded for " + require); + + if(parts[0] != "function_names") { + for(var i = 0, part; part = parts[i]; i++){ + data = data[part]; + } + } + deferred.callback(data); + }, + error: function(){ + deferred.errback(); + } + }; + + if(location.protocol == "file:"){ + if(size){ + if(parts[parts.length - 1] == "documentation"){ + parts[parts.length - 1] = "meta"; + } + + if(parts[0] == "function_names"){ + args.url = [this._url, "local_json", "function_names"].join("/"); + }else{ + var dirs = parts[0].split("."); + args.url = [this._url, "local_json", dirs[0]].join("/"); + if(dirs.length > 1){ + args.url = [args.url, dirs[1]].join("."); + } + } + } + } + + dojo.io.bind(args); + return deferred; + }, + getFunctionNames: function(){ + return this.require("function_names"); // dojo.Deferred + }, + unFormat: function(/*String*/ string){ + var fString = string; + if(string.charAt(string.length - 1) == "_"){ + fString = [string.substring(0, string.length - 1), "*"].join(""); + } + return fString; + }, + getMeta: function(/*String*/ pkg, /*String*/ name, /*Function*/ callback, /*String?*/ id){ + // summary: Gets information about a function in regards to its meta data + if(typeof name == "function"){ + // pId: a + // pkg: ignore + id = callback; + callback = name; + name = pkg; + pkg = null; + dojo.debug("getMeta(" + name + ")"); + }else{ + dojo.debug("getMeta(" + pkg + "/" + name + ")"); + } + + if(!id){ + id = "_"; + } + }, + _withPkg: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input, /*String*/ newType){ + dojo.debug("_withPkg(" + evt.name + ") has package: " + data[0]); + evt.pkg = data[0]; + if("load" == type && evt.pkg){ + evt.type = newType; + }else{ + if(evt.callbacks && evt.callbacks.length){ + evt.callbacks.shift()("error", {}, evt, evt.input); + } + } + }, + _gotMeta: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ + dojo.debug("_gotMeta(" + evt.name + ")"); + + var cached = dojo.docs._getCache(evt.pkg, evt.name, "meta", "functions", evt.id); + if(cached.summary){ + data.summary = cached.summary; + } + if(evt.callbacks && evt.callbacks.length){ + evt.callbacks.shift()(type, data, evt, evt.input); + } + }, + getSrc: function(/*String*/ name, /*Function*/ callback, /*String?*/ id){ + // summary: Gets src file (created by the doc parser) + dojo.debug("getSrc(" + name + ")"); + if(!id){ + id = "_"; + } + }, + getDoc: function(/*String*/ name, /*Function*/ callback, /*String?*/ id){ + // summary: Gets external documentation stored on Jot for a given function + dojo.debug("getDoc(" + name + ")"); + + if(!id){ + id = "_"; + } + + var input = {}; + + input.type = "doc"; + input.name = name; + input.callbacks = [callback]; + }, + _gotDoc: function(/*String*/ type, /*Array*/ data, /*Object*/ evt, /*Object*/ input){ + dojo.debug("_gotDoc(" + evt.type + ")"); + + evt[evt.type] = data; + if(evt.expects && evt.expects.doc){ + for(var i = 0, expect; expect = evt.expects.doc[i]; i++){ + if(!(expect in evt)){ + dojo.debug("_gotDoc() waiting for more data"); + return; + } + } + } + + var cache = dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta"); + + var description = evt.fn.description; + cache.description = description; + data = { + returns: evt.fn.returns, + id: evt.id, + variables: [] + } + if(!cache.parameters){ + cache.parameters = {}; + } + for(var i = 0, param; param = evt.param[i]; i++){ + var fName = param["DocParamForm/name"]; + if(!cache.parameters[fName]){ + cache.parameters[fName] = {}; + } + cache.parameters[fName].description = param["DocParamForm/desc"] + } + + data.description = cache.description; + data.parameters = cache.parameters; + + evt.type = "doc"; + + if(evt.callbacks && evt.callbacks.length){ + evt.callbacks.shift()("load", data, evt, input); + } + }, + getPkgDoc: function(/*String*/ name, /*Function*/ callback){ + // summary: Gets external documentation stored on Jot for a given package + dojo.debug("getPkgDoc(" + name + ")"); + var input = {}; + }, + getPkgInfo: function(/*String*/ name, /*Function*/ callback){ + // summary: Gets a combination of the metadata and external documentation for a given package + dojo.debug("getPkgInfo(" + name + ")"); + + var input = { + expects: { + pkginfo: ["pkgmeta", "pkgdoc"] + }, + callback: callback + }; + dojo.docs.getPkgMeta(input, name, dojo.docs._getPkgInfo); + dojo.docs.getPkgDoc(input, name, dojo.docs._getPkgInfo); + }, + _getPkgInfo: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ + dojo.debug("_getPkgInfo() for " + evt.type); + var input = {}; + var results = {}; + if(typeof key == "object"){ + input = key; + input[evt.type] = data; + if(input.expects && input.expects.pkginfo){ + for(var i = 0, expect; expect = input.expects.pkginfo[i]; i++){ + if(!(expect in input)){ + dojo.debug("_getPkgInfo() waiting for more data"); + return; + } + } + } + results = input.pkgmeta; + results.description = input.pkgdoc; + } + + if(input.callback){ + input.callback("load", results, evt); + } + }, + getInfo: function(/*String*/ name, /*Function*/ callback){ + dojo.debug("getInfo(" + name + ")"); + var input = { + expects: { + "info": ["meta", "doc"] + }, + callback: callback + } + dojo.docs.getMeta(input, name, dojo.docs._getInfo); + dojo.docs.getDoc(input, name, dojo.docs._getInfo); + }, + _getInfo: function(/*String*/ type, /*String*/ data, /*Object*/ evt, /*Object*/ input){ + dojo.debug("_getInfo(" + evt.type + ")"); + if(input && input.expects && input.expects.info){ + input[evt.type] = data; + for(var i = 0, expect; expect = input.expects.info[i]; i++){ + if(!(expect in input)){ + dojo.debug("_getInfo() waiting for more data"); + return; + } + } + } + + if(input.callback){ + input.callback("load", dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta"), evt, input); + } + }, + _getMainText: function(/*String*/ text){ + // summary: Grabs the innerHTML from a Jot Rech Text node + dojo.debug("_getMainText()"); + return text.replace(/^/, "").replace(/<\/html>$/, "").replace(/<\w+\s*\/>/g, ""); + }, + getPackageMeta: function(/*Object*/ input){ + dojo.debug("getPackageMeta(): " + input.package); + return this.require(input.package + "/meta", input.sync); + }, + getFunctionMeta: function(/*Object*/ input){ + var package = input.package || ""; + var name = input.name; + var id = input.id || "_"; + dojo.debug("getFunctionMeta(): " + name); + + if(!name) return; + + if(package){ + return this.require(package + "/meta/functions/" + name + "/" + id + "/meta"); + }else{ + this.getFunctionNames(); + } + }, + getFunctionDocumentation: function(/*Object*/ input){ + var package = input.package || ""; + var name = input.name; + var id = input.id || "_"; + dojo.debug("getFunctionDocumentation(): " + name); + + if(!name) return; + + if(package){ + return this.require(package + "/meta/functions/" + name + "/" + id + "/documentation"); + } + }, + _onDocSearch: function(/*Object*/ input){ + var _this = this; + var name = input.name.toLowerCase(); + if(!name) return; + + this.getFunctionNames().addCallback(function(data){ + dojo.debug("_onDocSearch(): function names loaded for " + name); + + var output = []; + var list = []; + var closure = function(pkg, fn) { + return function(data){ + dojo.debug("_onDocSearch(): package meta loaded for: " + pkg); + if(data.functions){ + var functions = data.functions; + for(var key in functions){ + if(fn == key){ + var ids = functions[key]; + for(var id in ids){ + var fnMeta = ids[id]; + output.push({ + package: pkg, + name: fn, + id: id, + summary: fnMeta.summary + }); + } + } + } + } + return output; + } + } + + pkgLoop: + for(var pkg in data){ + if(pkg.toLowerCase() == name){ + name = pkg; + dojo.debug("_onDocSearch found a package"); + //dojo.docs._onDocSelectPackage(input); + return; + } + for(var i = 0, fn; fn = data[pkg][i]; i++){ + if(fn.toLowerCase().indexOf(name) != -1){ + dojo.debug("_onDocSearch(): Search matched " + fn); + var meta = _this.getPackageMeta({package: pkg}); + meta.addCallback(closure(pkg, fn)); + list.push(meta); + + // Build a list of all packages that need to be loaded and their loaded state. + continue pkgLoop; + } + } + } + + list = new dojo.DeferredList(list); + list.addCallback(function(results){ + dojo.debug("_onDocSearch(): All packages loaded"); + _this._printFunctionResults(results[0][1]); + }); + }); + }, + _onDocSearchFn: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ + dojo.debug("_onDocSearchFn(" + evt.name + ")"); + + var name = evt.name || evt.pkg; + + dojo.debug("_onDocSearchFn found a function"); + + evt.pkgs = packages; + evt.pkg = name; + evt.loaded = 0; + for(var i = 0, pkg; pkg = packages[i]; i++){ + dojo.docs.getPkgMeta(evt, pkg, dojo.docs._onDocResults); + } + }, + _onPkgResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){ + dojo.debug("_onPkgResults(" + evt.type + ")"); + var description = ""; + var path = ""; + var methods = {}; + var requires = {}; + if(input){ + input[evt.type] = data; + if(input.expects && input.expects.pkgresults){ + for(var i = 0, expect; expect = input.expects.pkgresults[i]; i++){ + if(!(expect in input)){ + dojo.debug("_onPkgResults() waiting for more data"); + return; + } + } + } + path = input.pkgdoc.path; + description = input.pkgdoc.description; + methods = input.pkgmeta.methods; + requires = input.pkgmeta.requires; + } + var pkg = evt.name.replace("_", "*"); + var results = { + path: path, + description: description, + size: 0, + methods: [], + pkg: pkg, + requires: requires + } + var rePrivate = /_[^.]+$/; + for(var method in methods){ + if(!rePrivate.test(method)){ + for(var pId in methods[method]){ + results.methods.push({ + pkg: pkg, + name: method, + id: pId, + summary: methods[method][pId].summary + }) + } + } + } + results.size = results.methods.length; + dojo.docs._printPkgResult(results); + }, + _onDocResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){ + dojo.debug("_onDocResults(" + evt.name + "/" + input.pkg + ") " + type); + ++input.loaded; + + if(input.loaded == input.pkgs.length){ + var pkgs = input.pkgs; + var name = input.pkg; + var results = {methods: []}; + var rePrivate = /_[^.]+$/; + data = dojo.docs._cache; + + for(var i = 0, pkg; pkg = pkgs[i]; i++){ + var methods = dojo.docs._getCache(pkg, "meta", "methods"); + for(var fn in methods){ + if(fn.toLowerCase().indexOf(name) == -1){ + continue; + } + if(fn != "requires" && !rePrivate.test(fn)){ + for(var pId in methods[fn]){ + var result = { + pkg: pkg, + name: fn, + id: "_", + summary: "" + } + if(methods[fn][pId].summary){ + result.summary = methods[fn][pId].summary; + } + results.methods.push(result); + } + } + } + } + + dojo.debug("Publishing docResults"); + dojo.docs._printFnResults(results); + } + }, + _printFunctionResults: function(results){ + dojo.debug("_printFnResults(): called"); + // summary: Call this function to send the /docs/function/results topic + }, + _printPkgResult: function(results){ + dojo.debug("_printPkgResult(): called"); + }, + _onDocSelectFunction: function(/*Object*/ input){ + // summary: Get doc, meta, and src + var name = input.name; + var package = input.package || ""; + var id = input.id || "_"; + dojo.debug("_onDocSelectFunction(" + name + ")"); + if(!name || !package) return false; + + var pkgMeta = this.getPackageMeta({package: package}); + var meta = this.getFunctionMeta({package: package, name: name, id: id}); + var doc = this.getFunctionDocumentation({package: package, name: name, id: id}); + + var list = new dojo.DeferredList([pkgMeta, meta, doc]); + list.addCallback(function(results){ + dojo.debug("_onDocSelectFunction() loaded"); + for(var i = 0, result; result = results[i]; i++){ + dojo.debugShallow(result[1]); + } + }); + + return list; + }, + _onDocSelectPackage: function(/*Object*/ input){ + dojo.debug("_onDocSelectPackage(" + input.name + ")") + input.expects = { + "pkgresults": ["pkgmeta", "pkgdoc"] + }; + dojo.docs.getPkgMeta(input, input.name, dojo.docs._onPkgResults); + dojo.docs.getPkgDoc(input, input.name, dojo.docs._onPkgResults); + }, + _onDocSelectResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){ + dojo.debug("_onDocSelectResults(" + evt.type + ", " + evt.name + ")"); + if(evt.type == "meta"){ + dojo.docs.getPkgMeta(input, evt.pkg, dojo.docs._onDocSelectResults); + } + if(input){ + input[evt.type] = data; + if(input.expects && input.expects.docresults){ + for(var i = 0, expect; expect = input.expects.docresults[i]; i++){ + if(!(expect in input)){ + dojo.debug("_onDocSelectResults() waiting for more data"); + return; + } + } + } + } + + dojo.docs._printFunctionDetail(input); + }, + + _printFunctionDetail: function(results) { + // summary: Call this function to send the /docs/function/detail topic event + }, + + selectFunction: function(/*String*/ name, /*String?*/ id){ + // summary: The combined information + }, + savePackage: function(/*Object*/ callbackObject, /*String*/ callback, /*Object*/ parameters){ + dojo.event.kwConnect({ + srcObj: dojo.docs, + srcFunc: "_savedPkgRpc", + targetObj: callbackObject, + targetFunc: callback, + once: true + }); + + var props = {}; + var cache = dojo.docs._getCache(parameters.pkg, "meta"); + + var i = 1; + + if(!cache.path){ + var path = "id"; + props[["pname", i].join("")] = "DocPkgForm/require"; + props[["pvalue", i++].join("")] = parameters.pkg; + }else{ + var path = cache.path; + } + + props.form = "//DocPkgForm"; + props.path = ["/WikiHome/DojoDotDoc/", path].join(""); + + if(parameters.description){ + props[["pname", i].join("")] = "main/text"; + props[["pvalue", i++].join("")] = parameters.description; + } + + dojo.docs._rpc.callRemote("saveForm", props).addCallbacks(dojo.docs._pkgRpc, dojo.docs._pkgRpc); + }, + _pkgRpc: function(data){ + if(data.name){ + dojo.docs._getCache(data["DocPkgForm/require"], "meta").path = data.name; + dojo.docs._savedPkgRpc("load"); + }else{ + dojo.docs._savedPkgRpc("error"); + } + }, + _savedPkgRpc: function(type){ + }, + functionPackages: function(/*String*/ name, /*Function*/ callback, /*Object*/ input){ + // summary: Gets the package associated with a function and stores it in the .pkg value of input + dojo.debug("functionPackages() name: " + name); + + if(!input){ + input = {}; + } + if(!input.callbacks){ + input.callbacks = []; + } + + input.type = "function_names"; + input.name = name; + input.callbacks.unshift(callback); + input.callbacks.unshift(dojo.docs._functionPackages); + }, + _functionPackages: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ + dojo.debug("_functionPackages() name: " + evt.name); + evt.pkg = ''; + + var results = []; + var data = dojo.docs._cache['function_names']; + for(var key in data){ + if(dojo.lang.inArray(data[key], evt.name)){ + dojo.debug("_functionPackages() package: " + key); + results.push(key); + } + } + + if(evt.callbacks && evt.callbacks.length){ + evt.callbacks.shift()(type, results, evt, evt.input); + } + }, + setUserName: function(/*String*/ name){ + dojo.docs._userName = name; + if(name && dojo.docs._password){ + dojo.docs._logIn(); + } + }, + setPassword: function(/*String*/ password){ + dojo.docs._password = password; + if(password && dojo.docs._userName){ + dojo.docs._logIn(); + } + }, + _logIn: function(){ + dojo.io.bind({ + url: dojo.docs._rpc.serviceUrl.toString(), + method: "post", + mimetype: "text/json", + content: { + username: dojo.docs._userName, + password: dojo.docs._password + }, + load: function(type, data){ + if(data.error){ + dojo.docs.logInSuccess(); + }else{ + dojo.docs.logInFailure(); + } + }, + error: function(){ + dojo.docs.logInFailure(); + } + }); + }, + logInSuccess: function(){}, + logInFailure: function(){}, + _set: function(/*Object*/ base, /*String...*/ keys, /*String*/ value){ + var args = []; + for(var i = 0, arg; arg = arguments[i]; i++){ + args.push(arg); + } + + if(args.length < 3) return; + base = args.shift(); + value = args.pop(); + var key = args.pop(); + for(var i = 0, arg; arg = args[i]; i++){ + if(typeof base[arg] != "object"){ + base[arg] = {}; + } + base = base[arg]; + } + base[key] = value; + }, + _getCache: function(/*String...*/ keys){ + var obj = dojo.docs._cache; + for(var i = 0; i < arguments.length; i++){ + var arg = arguments[i]; + if(!obj[arg]){ + obj[arg] = {}; + } + obj = obj[arg]; + } + return obj; + } +}); + +dojo.event.topic.subscribe("/docs/search", dojo.docs, "_onDocSearch"); +dojo.event.topic.subscribe("/docs/function/select", dojo.docs, "_onDocSelectFunction"); +dojo.event.topic.subscribe("/docs/package/select", dojo.docs, "_onDocSelectPackage"); + +dojo.event.topic.registerPublisher("/docs/function/results", dojo.docs, "_printFunctionResults"); +dojo.event.topic.registerPublisher("/docs/function/detail", dojo.docs, "_printFunctionDetail"); +dojo.event.topic.registerPublisher("/docs/package/detail", dojo.docs, "_printPkgResult"); \ No newline at end of file diff --git a/source/web/scripts/ajax/dojo/src/dom.js b/source/web/scripts/ajax/dojo/src/dom.js new file mode 100644 index 0000000000..15c707999d --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/dom.js @@ -0,0 +1,560 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +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 = { + // summary + // aliases for various common XML namespaces + 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(/* object */wh){ + // summary: + // checks to see if wh is actually a node. + if(typeof Element == "function") { + try { + return wh instanceof Element; // boolean + } catch(e) {} + } else { + // best-guess + return wh && !isNaN(wh.nodeType); // boolean + } +} + +dojo.dom.getUniqueId = function(){ + // summary: + // returns a unique string for use with any DOM element + var _document = dojo.doc(); + do { + var id = "dj_unique_" + (++arguments.callee._idIncrement); + }while(_document.getElementById(id)); + return id; // string +} +dojo.dom.getUniqueId._idIncrement = 0; + +dojo.dom.firstElement = dojo.dom.getFirstChildElement = function(/* Element */parentNode, /* string? */tagName){ + // summary: + // returns the first child element matching 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; // Element +} + +dojo.dom.lastElement = dojo.dom.getLastChildElement = function(/* Element */parentNode, /* string? */tagName){ + // summary: + // returns the last child element matching 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; // Element +} + +dojo.dom.nextElement = dojo.dom.getNextSiblingElement = function(/* Node */node, /* string? */tagName){ + // summary: + // returns the next sibling element matching 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; // Element +} + +dojo.dom.prevElement = dojo.dom.getPreviousSiblingElement = function(/* Node */node, /* string? */tagName){ + // summary: + // returns the previous sibling element matching 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; // Element +} + +// 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(/*Element*/srcNode, /*Element*/destNode, /*boolean?*/trim){ + // summary: + // Moves children from srcNode to destNode and returns the count of + // children moved; will trim off text nodes if trim == true + 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; // number +} + +dojo.dom.copyChildren = function(/*Element*/srcNode, /*Element*/destNode, /*boolean?*/trim){ + // summary: + // Copies children from srcNde to destNode and returns the count of + // children copied; will trim off text nodes if trim == true + var clonedNode = srcNode.cloneNode(true); + return this.moveChildren(clonedNode, destNode, trim); // number +} + +dojo.dom.replaceChildren = function(/*Element*/node, /*Node*/newChild){ + // summary: + // Removes all children of node and appends newChild. All the existing + // children will be destroyed. + // FIXME: what if newChild is an array-like object? + var nodes = []; + if(dojo.render.html.ie){ + for(var i=0;i 0){ + return ancestors[0]; // Node + } + + node = node.parentNode; + } + if(returnFirstHit){ return null; } + return ancestors; // array +} + +dojo.dom.getAncestorsByTag = function(/*Node*/node, /*String*/tag, /*boolean?*/returnFirstHit){ + // summary: + // returns all ancestors matching tag (as tagName), will only return + // first one if returnFirstHit + tag = tag.toLowerCase(); + return dojo.dom.getAncestors(node, function(el){ + return ((el.tagName)&&(el.tagName.toLowerCase() == tag)); + }, returnFirstHit); // Node || array +} + +dojo.dom.getFirstAncestorByTag = function(/*Node*/node, /*string*/tag){ + // summary: + // Returns first ancestor of node with tag tagName + return dojo.dom.getAncestorsByTag(node, tag, true); // Node +} + +dojo.dom.isDescendantOf = function(/* Node */node, /* Node */ancestor, /* boolean? */guaranteeDescendant){ + // summary + // Returns boolean if node is a descendant of ancestor + // guaranteeDescendant allows us to be a "true" isDescendantOf function + if(guaranteeDescendant && node) { node = node.parentNode; } + while(node) { + if(node == ancestor){ + return true; // boolean + } + node = node.parentNode; + } + return false; // boolean +} + +dojo.dom.innerXML = function(/*Node*/node){ + // summary: + // Implementation of MS's innerXML function. + if(node.innerXML){ + return node.innerXML; // string + }else if (node.xml){ + return node.xml; // string + }else if(typeof XMLSerializer != "undefined"){ + return (new XMLSerializer()).serializeToString(node); // string + } +} + +dojo.dom.createDocument = function(){ + // summary: + // cross-browser implementation of creating an XML document object. + var doc = null; + var _document = dojo.doc(); + + if(!dj_undef("ActiveXObject")){ + var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ]; + for(var i = 0; i1) { + var _document = dojo.doc(); + dojo.dom.replaceChildren(node, _document.createTextNode(text)); + return text; // string + } else { + if(node.textContent != undefined){ //FF 1.5 + return node.textContent; // string + } + 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; // string + } +} + +dojo.dom.hasParent = function(/*Node*/node){ + // summary: + // returns whether or not node is a child of another node. + return Boolean(node && node.parentNode && dojo.dom.isNode(node.parentNode)); // boolean +} + +/** + * Examples: + * + * myFooNode = + * 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 */node /* ... */){ + // summary: + // determines if node has any of the provided tag names and returns + // the tag name that matches, empty string otherwise. + if(node && node.tagName) { + for(var i=1; i=0; i=i-1){ + var el = na[i]; + try{ + if(el && el["__clobberAttrs__"]){ + for(var j=0; j= 65 && unifiedCharCode <= 90 && evt.shiftKey == false){ + unifiedCharCode += 32; + } + if(unifiedCharCode >= 1 && unifiedCharCode <= 26 && evt.ctrlKey){ + unifiedCharCode += 96; // 001-032 = ctrl+[a-z] + } + evt.key = String.fromCharCode(unifiedCharCode); + } + } + } else if(evt["type"] == "keypress"){ + if(dojo.render.html.opera){ + if(evt.which == 0){ + evt.key = evt.keyCode; + }else if(evt.which > 0){ + switch(evt.which){ + case evt.KEY_SHIFT: + case evt.KEY_CTRL: + case evt.KEY_ALT: + case evt.KEY_CAPS_LOCK: + case evt.KEY_NUM_LOCK: + case evt.KEY_SCROLL_LOCK: + break; + case evt.KEY_PAUSE: + case evt.KEY_TAB: + case evt.KEY_BACKSPACE: + case evt.KEY_ENTER: + case evt.KEY_ESCAPE: + evt.key = evt.which; + break; + default: + var unifiedCharCode = evt.which; + if((evt.ctrlKey || evt.altKey || evt.metaKey) && (evt.which >= 65 && evt.which <= 90 && evt.shiftKey == false)){ + unifiedCharCode += 32; + } + evt.key = String.fromCharCode(unifiedCharCode); + } + } + }else if(dojo.render.html.ie){ // catch some IE keys that are hard to get in keyDown + // key combinations were handled in onKeyDown + if(!evt.ctrlKey && !evt.altKey && evt.keyCode >= evt.KEY_SPACE){ + evt.key = String.fromCharCode(evt.keyCode); + } + }else if(dojo.render.html.safari){ + switch(evt.keyCode){ + case 25: evt.key = evt.KEY_TAB; evt.shift = true;break; + case 63232: evt.key = evt.KEY_UP_ARROW; break; + case 63233: evt.key = evt.KEY_DOWN_ARROW; break; + case 63234: evt.key = evt.KEY_LEFT_ARROW; break; + case 63235: evt.key = evt.KEY_RIGHT_ARROW; break; + case 63236: evt.key = evt.KEY_F1; break; + case 63237: evt.key = evt.KEY_F2; break; + case 63238: evt.key = evt.KEY_F3; break; + case 63239: evt.key = evt.KEY_F4; break; + case 63240: evt.key = evt.KEY_F5; break; + case 63241: evt.key = evt.KEY_F6; break; + case 63242: evt.key = evt.KEY_F7; break; + case 63243: evt.key = evt.KEY_F8; break; + case 63244: evt.key = evt.KEY_F9; break; + case 63245: evt.key = evt.KEY_F10; break; + case 63246: evt.key = evt.KEY_F11; break; + case 63247: evt.key = evt.KEY_F12; break; + case 63250: evt.key = evt.KEY_PAUSE; break; + case 63272: evt.key = evt.KEY_DELETE; break; + case 63273: evt.key = evt.KEY_HOME; break; + case 63275: evt.key = evt.KEY_END; break; + case 63276: evt.key = evt.KEY_PAGE_UP; break; + case 63277: evt.key = evt.KEY_PAGE_DOWN; break; + case 63302: evt.key = evt.KEY_INSERT; break; + case 63248://prtscr + case 63249://scrolllock + case 63289://numlock + break; + default: + evt.key = evt.charCode >= evt.KEY_SPACE ? String.fromCharCode(evt.charCode) : evt.keyCode; + } + }else{ + evt.key = evt.charCode > 0 ? String.fromCharCode(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; // Event + } + + this.stopEvent = function(/*Event*/evt){ + // summary: + // prevents propigation and clobbers the default action of the + // passed event + // evt: Optional for IE. The native event object. + if(window.event){ + evt.cancelBubble = true; + evt.returnValue = false; + }else{ + evt.preventDefault(); + evt.stopPropagation(); + } + } +} diff --git a/source/web/scripts/ajax/dojo/src/event/common.js b/source/web/scripts/ajax/dojo/src/event/common.js new file mode 100644 index 0000000000..0756265f4e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/event/common.js @@ -0,0 +1,885 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.event.common"); + +dojo.require("dojo.lang.array"); +dojo.require("dojo.lang.extras"); +dojo.require("dojo.lang.func"); + +// 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(/*...*/){ + // summary: + // dojo.event.connect is the glue that holds most Dojo-based + // applications together. Most combinations of arguments are + // supported, with the connect() method attempting to disambiguate + // the implied types of positional parameters. The following will + // all work: + // dojo.event.connect("globalFunctionName1", "globalFunctionName2"); + // dojo.event.connect(functionReference1, functionReference2); + // dojo.event.connect("globalFunctionName1", functionReference2); + // dojo.event.connect(functionReference1, "globalFunctionName2"); + // dojo.event.connect(scope1, "functionName1", "globalFunctionName2"); + // dojo.event.connect("globalFunctionName1", scope2, "functionName2"); + // dojo.event.connect(scope1, "functionName1", scope2, "functionName2"); + // dojo.event.connect("after", scope1, "functionName1", scope2, "functionName2"); + // dojo.event.connect("before", scope1, "functionName1", scope2, "functionName2"); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // aroundFunctionReference); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName"); + // dojo.event.connect("before-around", scope1, "functionName1", + // scope2, "functionName2", + // aroundFunctionReference); + // dojo.event.connect("after-around", scope1, "functionName1", + // scope2, "functionName2", + // aroundFunctionReference); + // dojo.event.connect("after-around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName"); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName", true, 30); + // dojo.event.connect("around", scope1, "functionName1", + // scope2, "functionName2", + // scope3, "aroundFunctionName", null, null, 10); + // adviceType: + // Optional. String. One of "before", "after", "around", + // "before-around", or "after-around". FIXME + // srcObj: + // the scope in which to locate/execute the named srcFunc. Along + // with srcFunc, this creates a way to dereference the function to + // call. So if the function in question is "foo.bar", the + // srcObj/srcFunc pair would be foo and "bar", where "bar" is a + // string and foo is an object reference. + // srcFunc: + // the name of the function to connect to. When it is executed, + // the listener being registered with this call will be called. + // The adviceType defines the call order between the source and + // the target functions. + // adviceObj: + // the scope in which to locate/execute the named adviceFunc. + // adviceFunc: + // the name of the function being conected to srcObj.srcFunc + // aroundObj: + // the scope in which to locate/execute the named aroundFunc. + // aroundFunc: + // the name of, or a reference to, the function that will be used + // to mediate the advice call. Around advice requires a special + // unary function that will be passed a "MethodInvocation" object. + // These objects have several important properties, namely: + // - args + // a mutable array of arguments to be passed into the + // wrapped function + // - proceed + // a function that "continues" the invocation. The result + // of this function is the return of the wrapped function. + // You can then manipulate this return before passing it + // back out (or take further action based on it). + // once: + // boolean that determines whether or not this connect() will + // create a new connection if an identical connect() has already + // been made. Defaults to "false". + // delay: + // an optional delay (in ms), as an integer, for dispatch of a + // listener after the source has been fired. + // rate: + // an optional rate throttling parameter (integer, in ms). When + // specified, this particular connection will not fire more than + // once in the interval specified by the rate + // adviceMsg: + // boolean. Should the listener have all the parameters passed in + // as a single argument? + + /* + ao.adviceType = args[0]; + 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]; + */ + if(arguments.length == 1){ + var ao = arguments[0]; + }else{ + var ao = interpolateArgs(arguments, true); + } + if(dojo.lang.isString(ao.srcFunc) && (ao.srcFunc.toLowerCase() == "onkey") ){ + if(dojo.render.html.ie){ + ao.srcFunc = "onkeydown"; + this.connect(ao); + } + ao.srcFunc = "onkeypress"; + } + + + 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); + + // advanced users might want to fsck w/ the join point manually + return mjp; // a MethodJoinPoint object + } + + this.log = function(/*object or funcName*/ a1, /*funcName*/ a2){ + // summary: + // a function that will wrap and log all calls to the specified + // a1.a2() function. If only a1 is passed, it'll be used as a + // function or function name on the global context. Logging will + // be sent to dojo.debug + // a1: + // if a2 is passed, this should be an object. If not, it can be a + // function or function name. + // a2: + // a function name + 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= 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(/*Object*/obj, /*String*/funcName){ + this.object = obj||dj_global; + this.methodname = funcName; + this.methodfunc = this.object[funcName]; + this.squelch = false; + // this.before = []; + // this.after = []; + // this.around = []; +} + +dojo.event.MethodJoinPoint.getForMethod = function(/*Object*/obj, /*String*/funcName){ + // summary: + // "static" class function for returning a MethodJoinPoint from a + // scoped function. If one doesn't exist, one is created. + // obj: + // the scope to search for the function in + // funcName: + // the name of the function to return a MethodJoinPoint for + if(!obj){ obj = dj_global; } + if(!obj[funcName]){ + // supply a do-nothing method implementation + obj[funcName] = function(){}; + if(!obj[funcName]){ + // e.g. cannot add to inbuilt objects in IE6 + dojo.raise("Cannot set do-nothing method on that object "+funcName); + } + }else if((!dojo.lang.isFunction(obj[funcName]))&&(!dojo.lang.isAlien(obj[funcName]))){ + // FIXME: should we throw an exception here instead? + return null; + } + // we hide our joinpoint instance in obj[funcName + '$joinpoint'] + var jpname = funcName + "$joinpoint"; + var jpfuncname = funcName + "$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, funcName]); + } + } + var origArity = obj[funcName].length; + obj[jpfuncname] = obj[funcName]; + // joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, funcName); + joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, jpfuncname); + obj[funcName] = 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; x0)){ + // pass a cloned array, if this event disconnects this event forEach on this.before wont work + dojo.lang.forEach(this.before.concat(new Array()), unRollSquelch); + } + + var result; + try{ + if((this["around"])&&(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); + } + }catch(e){ + if(!this.squelch){ + dojo.debug(e,"when calling",this.methodname,"on",this.object,"with arguments",args); + dojo.raise(e); + } + } + + if((this["after"])&&(this.after.length>0)){ + // see comment on this.before above + dojo.lang.forEach(this.after.concat(new Array()), unRollSquelch); + } + + return (this.methodfunc) ? result : null; + }, + + getArr: function(/*String*/kind){ + // summary: return a list of listeners of the past "kind" + // kind: + // can be one of: "before", "after", "around", "before-around", or + // "after-around" + var type = "after"; + // FIXME: we should be able to do this through props or Array.in() + if((typeof kind == "string")&&(kind.indexOf("before")!=-1)){ + type = "before"; + }else if(kind=="around"){ + type = "around"; + } + if(!this[type]){ this[type] = []; } + return this[type]; // Array + }, + + kwAddAdvice: function(/*Object*/args){ + // summary: + // adds advice to the joinpoint with arguments in a map + // args: + // An object that can have the following properties: + // - adviceType + // - adviceObj + // - adviceFunc + // - aroundObj + // - aroundFunc + // - once + // - delay + // - rate + // - adviceMsg + 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, + adviceType, precedence, + once, delay, rate, asMessage){ + // summary: + // add advice to this joinpoint using positional parameters + // thisAdviceObj: + // the scope in which to locate/execute the named adviceFunc. + // thisAdviceFunc: + // the name of the function being conected + // thisAroundObj: + // the scope in which to locate/execute the named aroundFunc. + // thisAroundFunc: + // the name of the function that will be used to mediate the + // advice call. + // adviceType: + // Optional. String. One of "before", "after", "around", + // "before-around", or "after-around". FIXME + // once: + // boolean that determines whether or not this advice will create + // a new connection if an identical advice set has already been + // provided. Defaults to "false". + // delay: + // an optional delay (in ms), as an integer, for dispatch of a + // listener after the source has been fired. + // rate: + // an optional rate throttling parameter (integer, in ms). When + // specified, this particular connection will not fire more than + // once in the interval specified by the rate + // adviceMsg: + // boolean. Should the listener have all the parameters passed in + // as a single argument? + var arr = this.getArr(adviceType); + if(!arr){ + dojo.raise("bad this: " + this); + } + + var ao = [thisAdviceObj, thisAdvice, thisAroundObj, thisAround, delay, rate, asMessage]; + + if(once){ + if(this.hasAdvice(thisAdviceObj, thisAdvice, adviceType, arr) >= 0){ + return; + } + } + + if(precedence == "first"){ + arr.unshift(ao); + }else{ + arr.push(ao); + } + }, + + hasAdvice: function(thisAdviceObj, thisAdvice, adviceType, arr){ + // summary: + // returns the array index of the first existing connection + // betweened the passed advice and this joinpoint. Will be -1 if + // none exists. + // thisAdviceObj: + // the scope in which to locate/execute the named adviceFunc. + // thisAdviceFunc: + // the name of the function being conected + // adviceType: + // Optional. String. One of "before", "after", "around", + // "before-around", or "after-around". FIXME + // arr: + // Optional. The list of advices to search. Will be found via + // adviceType if not passed + if(!arr){ arr = this.getArr(adviceType); } + var ind = -1; + for(var x=0; x 0){ + for(var i = 0;i < dojo.flash._loadedListeners.length; i++){ + dojo.flash._loadedListeners[i].call(null); + } + } + }, + + installing: function(){ + // summary: Called if Flash is being installed. + // description: + // A callback to know if Flash is currently being installed or + // having its version revved. To be notified if Flash is installing, connect + // your callback to this method using the following: + // + // dojo.event.connect(dojo.flash, "installing", myInstance, "myCallback"); + + //dojo.debug("installing"); + if(dojo.flash._installingListeners.length > 0){ + for(var i = 0; i < dojo.flash._installingListeners.length; i++){ + dojo.flash._installingListeners[i].call(null); + } + } + }, + + // Initializes dojo.flash. + _initialize: function(){ + //dojo.debug("dojo.flash._initialize"); + // see if we need to rev or install Flash on this platform + var installer = new dojo.flash.Install(); + dojo.flash.installer = installer; + + if(installer.needed() == true){ + installer.install(); + }else{ + //dojo.debug("Writing object out"); + // write the flash object into the page + dojo.flash.obj = new dojo.flash.Embed(this._visible); + dojo.flash.obj.write(dojo.flash.info.commVersion); + + // initialize the way we do Flash/JavaScript communication + dojo.flash.comm = new dojo.flash.Communicator(); + } + } +}; + + +dojo.flash.Info = function(){ + // summary: A class that helps us determine whether Flash is available. + // description: + // A class that helps us determine whether Flash is available, + // it's major and minor versions, and what Flash version features should + // be used for Flash/JavaScript communication. Parts of this code + // are adapted from the automatic Flash plugin detection code autogenerated + // by the Macromedia Flash 8 authoring environment. + // + // An instance of this class can be accessed on dojo.flash.info after + // the page is finished loading. + // + // This constructor must be called before the page is finished loading. + + // Visual basic helper required to detect Flash Player ActiveX control + // version information on Internet Explorer + if(dojo.render.html.ie){ + document.writeln(''); + + // hook for Internet Explorer to receive FSCommands from Flash + if(dojo.render.html.ie){ + document.writeln(', + //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(/* HTMLDocument */doc, /* string */tag){ + // summary + // Creates an element in the HTML document, here for ActiveX activation workaround. + return doc.createElement(tag); // HTMLElement + } +} + +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"); +} diff --git a/source/web/scripts/ajax/dojo/src/html/display.js b/source/web/scripts/ajax/dojo/src/html/display.js new file mode 100644 index 0000000000..92cc49a4cd --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/html/display.js @@ -0,0 +1,196 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.html.display"); +dojo.require("dojo.html.style"); + +dojo.html._toggle = function(node, tester, setter){ + node = dojo.byId(node); + setter(node, !tester(node)); + return tester(node); +} + +dojo.html.show = function(/* HTMLElement */node){ + // summary + // Show the passed element by reverting display property set by dojo.html.hide + 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 + } +} + +dojo.html.hide = function(/* HTMLElement */node){ + // summary + // Hide the passed element by setting display:none + 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'); +} + +dojo.html.setShowing = function(/* HTMLElement */node, /* boolean? */showing){ + // summary + // Calls show() if showing is true, hide() otherwise + dojo.html[(showing ? 'show' : 'hide')](node); +} + +dojo.html.isShowing = function(/* HTMLElement */node){ + // summary + // Returns whether the element is displayed or not. + // FIXME: returns true if node is bad, isHidden would be easier to make correct + return (dojo.html.getStyleProperty(node, 'display') != 'none'); // boolean +} + +dojo.html.toggleShowing = function(/* HTMLElement */node){ + // summary + // Call setShowing() on node with the complement of isShowing(), then return the new value of isShowing() + return dojo.html._toggle(node, dojo.html.isShowing, dojo.html.setShowing); // boolean +} + +// Simple mapping of tag names to display values +// FIXME: simplistic +dojo.html.displayMap = { tr: '', td: '', th: '', img: 'inline', span: 'inline', input: 'inline', button: 'inline' }; + +dojo.html.suggestDisplayByTagName = function(/* HTMLElement */node){ + // summary + // Suggest a value for the display property that will show 'node' based on it's tag + node = dojo.byId(node); + if(node && node.tagName){ + var tag = node.tagName.toLowerCase(); + return (tag in dojo.html.displayMap ? dojo.html.displayMap[tag] : 'block'); // string + } +} + +dojo.html.setDisplay = function(/* HTMLElement */node, /* string */display){ + // summary + // 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.setStyle(node, 'display', ((display instanceof String || typeof display == "string") ? display : (display ? dojo.html.suggestDisplayByTagName(node) : 'none'))); +} + +dojo.html.isDisplayed = function(/* HTMLElement */node){ + // summary + // 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 + return (dojo.html.getComputedStyle(node, 'display') != 'none'); // boolean +} + +dojo.html.toggleDisplay = function(/* HTMLElement */node){ + // summary + // Call setDisplay() on node with the complement of isDisplayed(), then + // return the new value of isDisplayed() + return dojo.html._toggle(node, dojo.html.isDisplayed, dojo.html.setDisplay); // boolean +} + +dojo.html.setVisibility = function(/* HTMLElement */node, /* string */visibility){ + // summary + // 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.setStyle(node, 'visibility', ((visibility instanceof String || typeof visibility == "string") ? visibility : (visibility ? 'visible' : 'hidden'))); +} + +dojo.html.isVisible = function(/* HTMLElement */node){ + // summary + // Returns 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 + return (dojo.html.getComputedStyle(node, 'visibility') != 'hidden'); // boolean +} + +dojo.html.toggleVisibility = function(node){ + // summary + // Call setVisibility() on node with the complement of isVisible(), then return the new value of isVisible() + return dojo.html._toggle(node, dojo.html.isVisible, dojo.html.setVisibility); // boolean +} + +dojo.html.setOpacity = function(/* HTMLElement */node, /* float */opacity, /* boolean? */dontFixOpacity){ + // summary + // Sets the opacity of node in a cross-browser way. + // float between 0.0 (transparent) and 1.0 (opaque) + 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= 0.999999 ? 1.0 : Number(opac); // float +} diff --git a/source/web/scripts/ajax/dojo/src/html/iframe.js b/source/web/scripts/ajax/dojo/src/html/iframe.js new file mode 100644 index 0000000000..716cefb3e6 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/html/iframe.js @@ -0,0 +1,128 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.html.iframe"); +dojo.require("dojo.html.util"); + +// thanks burstlib! +dojo.html.iframeContentWindow = function(/* HTMLIFrameElement */iframe_el) { + // summary + // returns the window reference of the passed iframe + var win = dojo.html.getDocumentWindow(dojo.html.iframeContentDocument(iframe_el)) || + // Moz. TODO: is this available when defaultView isn't? + dojo.html.iframeContentDocument(iframe_el).__parent__ || + (iframe_el.name && document.frames[iframe_el.name]) || null; + return win; // Window +} + +dojo.html.iframeContentDocument = function(/* HTMLIFrameElement */iframe_el){ + // summary + // returns a reference to the document object inside iframe_el + var doc = iframe_el.contentDocument // W3 + || ((iframe_el.contentWindow)&&(iframe_el.contentWindow.document)) // IE + || ((iframe_el.name)&&(document.frames[iframe_el.name])&&(document.frames[iframe_el.name].document)) + || null; + return doc; // HTMLDocument +} + +dojo.html.BackgroundIframe = function(/* HTMLElement */node) { + // summary + // For IE z-index schenanigans + // Two possible uses: + // 1. new dojo.html.BackgroundIframe(node) + // Makes a background iframe as a child of node, that fills area (and position) of node + // 2. new dojo.html.BackgroundIframe() + // Attaches frame to dojo.body(). User must call size() to set size. + if(dojo.render.html.ie55 || dojo.render.html.ie60) { + var html="" + }else{ + this.rcvNode = dojo.io.createIFrame(this.rcvNodeName, "", initUrl); + // dojo.io.setIFrameSrc(this.rcvNode, initUrl); + // we're still waiting on the iframe to call back up to use and + // advertise that it's been initialized via tunnelInit + } + } +} + +cometd.mimeReplaceTransport = new function(){ + this.connected = false; + this.connectionId = null; + this.xhr = null; + + this.authToken = null; + this.lastTimestamp = null; + this.lastId = null; + this.backlog = []; + + this.check = function(types, version, xdomain){ + return ((!xdomain)&& + (dojo.render.html.mozilla)&& // seems only Moz really supports this right now = ( + (dojo.lang.inArray(types, "mime-message-block"))); + } + + this.tunnelInit = function(){ + if(this.connected){ return; } + // FIXME: open up the connection here + this.openTunnelWith({ + message: dojo.json.serialize([ + { + channel: "/meta/connect", + clientId: cometd.clientId, + connectionType: "mime-message-block" + // FIXME: auth not passed here! + // "authToken": this.authToken + } + ]) + }); + this.connected = true; + } + + this.tunnelCollapse = function(){ + if(this.connected){ + // try to restart the tunnel + this.connected = false; + this.openTunnelWith({ + message: dojo.json.serialize([ + { + channel: "/meta/reconnect", + clientId: cometd.clientId, + connectionId: this.connectionId, + timestamp: this.lastTimestamp, + id: this.lastId + // FIXME: no authToken provision! + } + ]) + }); + } + } + + this.deliver = cometd.iframeTransport.deliver; + // the logic appears to be the same + + this.handleOnLoad = function(resp){ + cometd.deliver(dojo.json.evalJson(this.xhr.responseText)); + } + + this.openTunnelWith = function(content, url){ + // set up the XHR object and register the multipart callbacks + this.xhr = dojo.hostenv.getXmlhttpObject(); + this.xhr.multipart = true; // FIXME: do Opera and Safari support this flag? + if(dojo.render.html.mozilla){ + this.xhr.addEventListener("load", dojo.lang.hitch(this, "handleOnLoad"), false); + }else if(dojo.render.html.safari){ + // Blah. WebKit doesn't actually populate responseText and/or responseXML. Useless. + dojo.debug("Webkit is broken with multipart responses over XHR = ("); + this.xhr.onreadystatechange = dojo.lang.hitch(this, "handleOnLoad"); + }else{ + this.xhr.onload = dojo.lang.hitch(this, "handleOnLoad"); + } + this.xhr.open("POST", (url||cometd.url), true); // async post + this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + dojo.debug(dojo.json.serialize(content)); + this.xhr.send(dojo.io.argsFromMap(content, "utf8")); + } + + this.processBacklog = function(){ + while(this.backlog.length > 0){ + this.sendMessage(this.backlog.shift(), true); + } + } + + this.sendMessage = function(message, bypassBacklog){ + // FIXME: what about auth fields? + if((bypassBacklog)||(this.connected)){ + message.connectionId = this.connectionId; + message.clientId = cometd.clientId; + var bindArgs = { + url: cometd.url||djConfig["cometdRoot"], + method: "POST", + mimetype: "text/json", + content: { message: dojo.json.serialize([ message ]) } + }; + return dojo.io.bind(bindArgs); + }else{ + this.backlog.push(message); + } + } + + this.startup = function(handshakeData){ + dojo.debugShallow(handshakeData); + if(this.connected){ return; } + this.tunnelInit(); + } +} + +cometd.longPollTransport = new function(){ + this.connected = false; + this.connectionId = null; + + this.authToken = null; + this.lastTimestamp = null; + this.lastId = null; + this.backlog = []; + + this.check = function(types, version, xdomain){ + return ((!xdomain)&&(dojo.lang.inArray(types, "long-polling"))); + } + + this.tunnelInit = function(){ + if(this.connected){ return; } + // FIXME: open up the connection here + this.openTunnelWith({ + message: dojo.json.serialize([ + { + channel: "/meta/connect", + clientId: cometd.clientId, + connectionType: "long-polling" + // FIXME: auth not passed here! + // "authToken": this.authToken + } + ]) + }); + this.connected = true; + } + + this.tunnelCollapse = function(){ + if(!this.connected){ + // try to restart the tunnel + this.connected = false; + dojo.debug("clientId:", cometd.clientId); + this.openTunnelWith({ + message: dojo.json.serialize([ + { + channel: "/meta/reconnect", + connectionType: "long-polling", + clientId: cometd.clientId, + connectionId: this.connectionId, + timestamp: this.lastTimestamp, + id: this.lastId + // FIXME: no authToken provision! + } + ]) + }); + } + } + + this.deliver = cometd.iframeTransport.deliver; + // the logic appears to be the same + + this.openTunnelWith = function(content, url){ + dojo.io.bind({ + url: (url||cometd.url), + method: "post", + content: content, + mimetype: "text/json", + load: dojo.lang.hitch(this, function(type, data, evt, args){ + // dojo.debug(evt.responseText); + cometd.deliver(data); + this.connected = false; + this.tunnelCollapse(); + }), + error: function(){ dojo.debug("tunnel opening failed"); } + }); + this.connected = true; + } + + this.processBacklog = function(){ + while(this.backlog.length > 0){ + this.sendMessage(this.backlog.shift(), true); + } + } + + this.sendMessage = function(message, bypassBacklog){ + // FIXME: what about auth fields? + if((bypassBacklog)||(this.connected)){ + message.connectionId = this.connectionId; + message.clientId = cometd.clientId; + var bindArgs = { + url: cometd.url||djConfig["cometdRoot"], + method: "post", + mimetype: "text/json", + content: { message: dojo.json.serialize([ message ]) } + }; + return dojo.io.bind(bindArgs); + }else{ + this.backlog.push(message); + } + } + + this.startup = function(handshakeData){ + if(this.connected){ return; } + this.tunnelInit(); + } +} + +cometd.callbackPollTransport = new function(){ + this.connected = false; + this.connectionId = null; + + this.authToken = null; + this.lastTimestamp = null; + this.lastId = null; + this.backlog = []; + + this.check = function(types, version, xdomain){ + // we handle x-domain! + return dojo.lang.inArray(types, "callback-polling"); + } + + this.tunnelInit = function(){ + if(this.connected){ return; } + // FIXME: open up the connection here + this.openTunnelWith({ + message: dojo.json.serialize([ + { + channel: "/meta/connect", + clientId: cometd.clientId, + connectionType: "callback-polling" + // FIXME: auth not passed here! + // "authToken": this.authToken + } + ]) + }); + this.connected = true; + } + + this.tunnelCollapse = function(){ + if(!this.connected){ + // try to restart the tunnel + this.connected = false; + this.openTunnelWith({ + message: dojo.json.serialize([ + { + channel: "/meta/reconnect", + connectionType: "long-polling", + clientId: cometd.clientId, + connectionId: this.connectionId, + timestamp: this.lastTimestamp, + id: this.lastId + // FIXME: no authToken provision! + } + ]) + }); + } + } + + this.deliver = cometd.iframeTransport.deliver; + // the logic appears to be the same + + this.openTunnelWith = function(content, url){ + // create a + + +

The Dojo Toolkit -- xip_client.html

+ +

This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used + internally by dojo.io.XhrIframeProxy.

+ + + + diff --git a/source/web/scripts/ajax/dojo/src/io/xip_server.html b/source/web/scripts/ajax/dojo/src/io/xip_server.html new file mode 100644 index 0000000000..6e25f95a74 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/io/xip_server.html @@ -0,0 +1,371 @@ + + + + + + + + + + + +

The Dojo Toolkit -- xip_server.html

+ +

This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the the file + that should go on the server that will actually be doing the XHR request.

+
+ + diff --git a/source/web/scripts/ajax/dojo/src/json.js b/source/web/scripts/ajax/dojo/src/json.js new file mode 100644 index 0000000000..caa1474aeb --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/json.js @@ -0,0 +1,156 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.json"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.string.extras"); +dojo.require("dojo.AdapterRegistry"); + +dojo.json = { + // jsonRegistry: AdapterRegistry a registry of type-based serializers + jsonRegistry: new dojo.AdapterRegistry(), + + register: function( /*String*/ name, + /*function*/ check, + /*function*/ wrap, + /*optional, boolean*/ override){ + // summary: + // Register a JSON serialization function. JSON serialization + // functions should take one argument and return an object + // suitable for JSON serialization: + // - string + // - number + // - boolean + // - undefined + // - object + // - null + // - Array-like (length property that is a number) + // - Objects with a "json" method will have this method called + // - Any other object will be used as {key:value, ...} pairs + // + // If override is given, it is used as the highest priority JSON + // serialization, otherwise it will be used as the lowest. + // name: + // a descriptive type for this serializer + // check: + // a unary function that will be passed an object to determine + // whether or not wrap will be used to serialize the object + // wrap: + // the serialization function + // override: + // optional, determines if the this serialization function will be + // given priority in the test order + + dojo.json.jsonRegistry.register(name, check, wrap, override); + }, + + evalJson: function(/*String*/ json){ + // summary: + // evaluates the passed string-form of a JSON object + // json: + // a string literal of a JSON item, for instance: + // '{ "foo": [ "bar", 1, { "baz": "thud" } ] }' + // return: + // the result of the evaluation + + // FIXME: should this accept mozilla's optional second arg? + try { + return eval("(" + json + ")"); + }catch(e){ + dojo.debug(e); + return json; + } + }, + + serialize: function(/*Object*/ o){ + // summary: + // Create a JSON serialization of an object, note that this + // doesn't check for infinite recursion, so don't do that! + // o: + // an object to be serialized. Objects may define their own + // serialization via a special "__json__" or "json" function + // property. If a specialized serializer has been defined, it will + // be used as a fallback. + // return: + // a String representing the serialized version of the passed + // object + + var objtype = typeof(o); + if(objtype == "undefined"){ + return "undefined"; + }else if((objtype == "number")||(objtype == "boolean")){ + return o + ""; + }else if(o === null){ + return "null"; + } + if (objtype == "string") { return dojo.string.escapeString(o); } + // recurse + var me = arguments.callee; + // short-circuit for objects that support "json" serialization + // if they return "self" then just pass-through... + var newObj; + if(typeof(o.__json__) == "function"){ + newObj = o.__json__(); + if(o !== newObj){ + return me(newObj); + } + } + if(typeof(o.json) == "function"){ + newObj = o.json(); + if (o !== newObj) { + return me(newObj); + } + } + // array + if(objtype != "function" && typeof(o.length) == "number"){ + var res = []; + for(var i = 0; i < o.length; i++){ + var val = me(o[i]); + if(typeof(val) != "string"){ + val = "undefined"; + } + res.push(val); + } + return "[" + res.join(",") + "]"; + } + // look in the registry + try { + window.o = o; + newObj = dojo.json.jsonRegistry.match(o); + return me(newObj); + }catch(e){ + // dojo.debug(e); + } + // it's a function with no adapter, bad + if(objtype == "function"){ + return null; + } + // generic object code path + res = []; + for (var k in o){ + var useKey; + if (typeof(k) == "number"){ + useKey = '"' + k + '"'; + }else if (typeof(k) == "string"){ + useKey = dojo.string.escapeString(k); + }else{ + // skip non-string or number keys + continue; + } + val = me(o[k]); + if(typeof(val) != "string"){ + // skip non-serializable values + continue; + } + res.push(useKey + ":" + val); + } + return "{" + res.join(",") + "}"; + } +}; diff --git a/source/web/scripts/ajax/dojo/src/lang.js b/source/web/scripts/ajax/dojo/src/lang.js new file mode 100644 index 0000000000..7f8cfad602 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang.js @@ -0,0 +1,14 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang"); +dojo.require("dojo.lang.common"); + +dojo.deprecated("dojo.lang", "replaced by dojo.lang.common", "0.5"); diff --git a/source/web/scripts/ajax/dojo/src/lang/__package__.js b/source/web/scripts/ajax/dojo/src/lang/__package__.js new file mode 100644 index 0000000000..7f51006e7c --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/__package__.js @@ -0,0 +1,23 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: [ + "dojo.lang.common", + "dojo.lang.assert", + "dojo.lang.array", + "dojo.lang.type", + "dojo.lang.func", + "dojo.lang.extras", + "dojo.lang.repr", + "dojo.lang.declare" + ] +}); +dojo.provide("dojo.lang.*"); diff --git a/source/web/scripts/ajax/dojo/src/lang/array.js b/source/web/scripts/ajax/dojo/src/lang/array.js new file mode 100644 index 0000000000..7ac14ec1d1 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/array.js @@ -0,0 +1,284 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang.array"); + +dojo.require("dojo.lang.common"); + +// FIXME: Is this worthless since you can do: if(name in obj) +// is this the right place for this? + +dojo.lang.mixin(dojo.lang, { + has: function(/*Object*/obj, /*String*/name){ + // summary: is there a property with the passed name in obj? + try{ + return typeof obj[name] != "undefined"; // Boolean + }catch(e){ return false; } // Boolean + }, + + isEmpty: function(/*Object*/obj){ + // summary: + // can be used to determine if the passed object is "empty". In + // the case of array-like objects, the length, property is + // examined, but for other types of objects iteration is used to + // examine the iterable "surface area" to determine if any + // non-prototypal properties have been assigned. This iteration is + // prototype-extension safe. + 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; // boolean + }else if(dojo.lang.isArrayLike(obj) || dojo.lang.isString(obj)){ + return obj.length == 0; // boolean + } + }, + + map: function(/*Array*/arr, /*Object|Function*/obj, /*Function?*/unary_func){ + // summary: + // returns a new array constituded from the return values of + // passing each element of arr into unary_func. The obj parameter + // may be passed to enable the passed function to be called in + // that scope. In environments that support JavaScript 1.6, this + // function is a passthrough to the built-in map() function + // provided by Array instances. For details on this, see: + // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map + // examples: + // dojo.lang.map([1, 2, 3, 4], function(item){ return item+1 }); + // // returns [2, 3, 4, 5] + var isString = dojo.lang.isString(arr); + if(isString){ + // arr: String + 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;i1; }); + // // returns false + // dojo.lang.every([1, 2, 3, 4], function(item){ return item>0; }); + // // returns true + return this._everyOrSome(true, arr, callback, thisObject); // Boolean + }, + + some: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){ + // summary: + // determines whether or not any item in the array satisfies the + // condition implemented by callback. thisObject may be used to + // scope the call to callback. The function signature is derived + // from the JavaScript 1.6 Array.some() function. More + // information on this can be found here: + // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some + // examples: + // dojo.lang.some([1, 2, 3, 4], function(item){ return item>1; }); + // // returns true + // dojo.lang.some([1, 2, 3, 4], function(item){ return item<1; }); + // // returns false + return this._everyOrSome(false, arr, callback, thisObject); // Boolean + }, + + filter: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){ + // summary: + // returns a new Array with those items from arr that match the + // condition implemented by callback.thisObject may be used to + // scope the call to callback. The function signature is derived + // from the JavaScript 1.6 Array.filter() function, although + // special accomidation is made in our implementation for strings. + // More information on the JS 1.6 API can be found here: + // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter + // examples: + // dojo.lang.some([1, 2, 3, 4], function(item){ return item>1; }); + // // returns [2, 3, 4] + var isString = dojo.lang.isString(arr); + if(isString){ /*arr: String*/arr = arr.split(""); } + var outArr; + if(Array.filter){ + outArr = Array.filter(arr, callback, thisObject); + }else{ + if(!thisObject){ + if(arguments.length >= 3){ dojo.raise("thisObject doesn't exist!"); } + thisObject = dj_global; + } + + 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(""); // String + } else { + return outArr; // Array + } + }, + + unnest: function(/* ... */){ + // summary: + // Creates a 1-D array out of all the arguments passed, + // unravelling any array-like objects in the process + // usage: + // unnest(1, 2, 3) ==> [1, 2, 3] + // unnest(1, [2, [3], [[[4]]]]) ==> [1, 2, 3, 4] + + 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; // Array + }, + + toArray: function(/*Object*/arrayLike, /*Number*/startOffset){ + // summary: + // Converts an array-like object (i.e. arguments, DOMCollection) + // to an array. Returns a new Array object. + var array = []; + for(var i = startOffset||0; i < arrayLike.length; i++){ + array.push(arrayLike[i]); + } + return array; // Array + } +}); diff --git a/source/web/scripts/ajax/dojo/src/lang/assert.js b/source/web/scripts/ajax/dojo/src/lang/assert.js new file mode 100644 index 0000000000..78311dc0c1 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/assert.js @@ -0,0 +1,116 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang.assert"); + +dojo.require("dojo.lang.common"); +dojo.require("dojo.lang.array"); +dojo.require("dojo.lang.type"); + +dojo.lang.assert = function(/* boolean */ booleanValue, /* string? */ message){ + /* summary: + * Throws an exception if the assertion fails. + * description: + * If the asserted condition is true, this method does nothing. If the + * condition is false, we throw an error with a error message. + * booleanValue: Must be true for the assertion to succeed. + * message: A string describing the assertion. + */ + + // throws: Throws an Error if 'booleanValue' is false. + if(!booleanValue){ + var errorMessage = "An assert statement failed.\n" + + "The method dojo.lang.assert() was called with a 'false' value.\n"; + if(message){ + errorMessage += "Here's the assert message:\n" + message + "\n"; + } + // Use throw instead of dojo.raise, until bug #264 is fixed: + // dojo.raise(errorMessage); + throw new Error(errorMessage); + } +} + +dojo.lang.assertType = function(/* anything */ value, /* misc. */ type, /* object? */ keywordParameters){ + /* summary: + * Throws an exception if 'value' is not of type 'type' + * description: + * Given a value and a data type, this method checks the type of the value + * to make sure it matches the data type, and throws an exception if there + * is a mismatch. + * value: Any literal value or object instance. + * type: A class of object, or a literal type, or the string name of a type, or an array with a list of types. + * keywordParameters: {optional: boolean} + */ + + /* examples: + * dojo.lang.assertType("foo", String); + * dojo.lang.assertType(12345, Number); + * dojo.lang.assertType(false, Boolean); + * dojo.lang.assertType([6, 8], Array); + * dojo.lang.assertType(dojo.lang.assertType, Function); + * dojo.lang.assertType({foo: "bar"}, Object); + * dojo.lang.assertType(new Date(), Date); + * dojo.lang.assertType(null, Array, {optional: true}); + * throws: Throws an Error if 'value' is not of type 'type'. + */ + if (dojo.lang.isString(keywordParameters)) { + dojo.deprecated('dojo.lang.assertType(value, type, "message")', 'use dojo.lang.assertType(value, type) instead', "0.5"); + } + if(!dojo.lang.isOfType(value, type, keywordParameters)){ + if(!dojo.lang.assertType._errorMessage){ + dojo.lang.assertType._errorMessage = "Type mismatch: dojo.lang.assertType() failed."; + } + dojo.lang.assert(false, dojo.lang.assertType._errorMessage); + } +} + +dojo.lang.assertValidKeywords = function(/* object */ object, /* array */ expectedProperties, /* string? */ message){ + /* summary: + * Throws an exception 'object' has any properties other than the 'expectedProperties'. + * description: + * Given an anonymous object and a list of expected property names, this + * method check to make sure the object does not have any properties + * that aren't on the list of expected properties, and throws an Error + * if there are unexpected properties. This is useful for doing error + * checking on keyword arguments, to make sure there aren't typos. + * object: An anonymous object. + * expectedProperties: An array of strings (or an object with all the expected properties). + * message: A message describing the assertion. + */ + + /* examples: + * dojo.lang.assertValidKeywords({a: 1, b: 2}, ["a", "b"]); + * dojo.lang.assertValidKeywords({a: 1, b: 2}, ["a", "b", "c"]); + * dojo.lang.assertValidKeywords({foo: "iggy"}, ["foo"]); + * dojo.lang.assertValidKeywords({foo: "iggy"}, ["foo", "bar"]); + * dojo.lang.assertValidKeywords({foo: "iggy"}, {foo: null, bar: null}); + * throws: Throws an Error if 'object' has unexpected properties. + */ + var key; + if(!message){ + if(!dojo.lang.assertValidKeywords._errorMessage){ + dojo.lang.assertValidKeywords._errorMessage = "In dojo.lang.assertValidKeywords(), found invalid keyword:"; + } + message = dojo.lang.assertValidKeywords._errorMessage; + } + if(dojo.lang.isArray(expectedProperties)){ + for(key in object){ + if(!dojo.lang.inArray(expectedProperties, key)){ + dojo.lang.assert(false, message + " " + key); + } + } + }else{ + for(key in object){ + if(!(key in expectedProperties)){ + dojo.lang.assert(false, message + " " + key); + } + } + } +} diff --git a/source/web/scripts/ajax/dojo/src/lang/common.js b/source/web/scripts/ajax/dojo/src/lang/common.js new file mode 100644 index 0000000000..ed7a898b39 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/common.js @@ -0,0 +1,253 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang.common"); + +dojo.lang.inherits = function(/*Function*/subclass, /*Function*/superclass){ + // summary: Set up inheritance between two classes. + if(!dojo.lang.isFunction(superclass)){ + 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; + // DEPRECATED: super is a reserved word, use 'superclass' + subclass['super'] = superclass.prototype; +} + +dojo.lang._mixin = function(/*Object*/ obj, /*Object*/ props){ + // summary: + // Adds all properties and methods of props to obj. This addition is + // "prototype extension safe", so that instances of objects will not + // pass along prototype defaults. + var tobj = {}; + for(var x in props){ + // the "tobj" condition avoid copying properties in "props" + // inherited from Object.prototype. For example, if obj has a custom + // toString() method, don't overwrite it with the toString() method + // that props inherited from Object.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 + && (typeof(props["toString"]) == "function") + && (props["toString"] != obj["toString"]) + && (props["toString"] != tobj["toString"])) + { + obj.toString = props.toString; + } + return obj; // Object +} + +dojo.lang.mixin = function(/*Object*/obj, /*Object...*/props){ + // summary: Adds all properties and methods of props to obj. + for(var i=1, l=arguments.length; i -1; // 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(/*anything*/ 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)); // Boolean +} + +dojo.lang.isArray = function(/*anything*/ it){ + // summary: Return true if it is an Array. + return (it && it instanceof Array || typeof it == "array"); // Boolean +} + +dojo.lang.isArrayLike = function(/*anything*/ 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; // Boolean +} + +dojo.lang.isFunction = function(/*anything*/ it){ + // summary: Return true if it is a Function. + return (it instanceof Function || typeof it == "function"); // Boolean +}; + +(function(){ + // webkit treats NodeList as a function, which is bad + if((dojo.render.html.capable)&&(dojo.render.html["safari"])){ + dojo.lang.isFunction = function(/*anything*/ it){ + if((typeof(it) == "function") && (it == "[object NodeList]")) { return false; } + return (it instanceof Function || typeof it == "function"); // Boolean + } + } +})(); + +dojo.lang.isString = function(/*anything*/ it){ + // summary: Return true if it is a String. + return (typeof it == "string" || it instanceof String); +} + +dojo.lang.isAlien = function(/*anything*/ it){ + // summary: Return true if it is not a built-in function. False if not. + if(!it){ return false; } + return !dojo.lang.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean +} + +dojo.lang.isBoolean = function(/*anything*/ it){ + // summary: Return true if it is a Boolean. + return (it instanceof Boolean || typeof it == "boolean"); // 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(/*anything*/ it){ + // summary: Return true if it is a number. + // description: + // 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"); // Boolean +} + +/* + * FIXME: Should isUndefined go away since it is error prone? + */ +dojo.lang.isUndefined = function(/*anything*/ it){ + // summary: Return true if it is not defined. + // description: + // 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 ((typeof(it) == "undefined")&&(it == undefined)); // Boolean +} + +// end Crockford functions diff --git a/source/web/scripts/ajax/dojo/src/lang/declare.js b/source/web/scripts/ajax/dojo/src/lang/declare.js new file mode 100644 index 0000000000..88a8c44983 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/declare.js @@ -0,0 +1,168 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang.declare"); + +dojo.require("dojo.lang.common"); +dojo.require("dojo.lang.extras"); + +dojo.lang.declare = function( /*String*/ className, + /*Function|Array*/ superclass, + /*Function?*/ init, + /*Object|Array*/ props){ + /* + * summary: Create a feature-rich constructor with a compact notation + * className: the name of the constructor (loosely, a "class") + * superclass: + * 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. + * init: an initializer function + * props: + * an object (or array of objects) whose properties are copied to the + * created prototype + * description: + * Create a constructor using a compact notation for inheritance and + * prototype extension. "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. + * + * Properties of object "props" are copied to the constructor + * prototype. If "props" is an array, properties of each object in the + * array are copied to the constructor prototype. + * + * name of the class ("className" argument) is stored in + * "declaredClass" property + * + * Initializer functions are called when an object is instantiated + * from this constructor. + * + * Aliased as "dojo.declare" + * + * Usage: + * + * dojo.declare("my.classes.bar", my.classes.foo, + * function(){ + * // initialization function + * this.myComplicatedObject = new ReallyComplicatedObject(); + * }, + * { // properties to be added to the class prototype + * someValue: 2, + * someMethod: function(){ + * doStuff(); + * } + * } + * ); + * + */ + if((dojo.lang.isFunction(props))||((!props)&&(!dojo.lang.isFunction(init)))){ + // parameter juggling to support omitting init param (also allows + // reordering init and props arguments) + 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 0){ + obj = queue.shift(); + } + + // check to see if the input function needs to be fired + // stop before firing the output function + // TODO: relegate this to the output function? + if(typeof(obj) == "undefined"){ + self.stop(); + return; + } + + // call the output function. + self.outputFunction(obj); + }; + + this.setInterval = function(/* int */ms){ + // summary + // sets the interval in milliseconds of the internal timer + this.interval = ms; + timer.setInterval(ms); + }; + + this.onTick = function(/* dojo.lang.timing.Streamer */obj){ }; + // wrap the timer functions so that we can connect to them if needed. + this.start = function(){ + // summary + // starts the Streamer + if(typeof(this.inputFunction) == "function" && typeof(this.outputFunction) == "function"){ + timer.start(); + return; + } + dojo.raise("You cannot start a Streamer without an input and an output function."); + }; + this.onStart = function(){ }; + this.stop = function(){ + // summary + // stops the Streamer + timer.stop(); + }; + this.onStop = function(){ }; + + // finish initialization + timer.onTick = this.tick; + timer.onStart = this.onStart; + timer.onStop = this.onStop; + if(initialData){ + queue.concat(initialData); + } +}; diff --git a/source/web/scripts/ajax/dojo/src/lang/timing/Timer.js b/source/web/scripts/ajax/dojo/src/lang/timing/Timer.js new file mode 100644 index 0000000000..888e403811 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/timing/Timer.js @@ -0,0 +1,64 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang.timing.Timer"); +dojo.require("dojo.lang.func"); + +dojo.lang.timing.Timer = function(/*int*/ interval){ + // summary: Timer object executes an "onTick()" method repeatedly at a specified interval. + // repeatedly at a given interval. + // interval: Interval between function calls, in milliseconds. + this.timer = null; + this.isRunning = false; + this.interval = interval; + + this.onStart = null; + this.onStop = null; +}; + +dojo.extend(dojo.lang.timing.Timer, { + onTick : function(){ + // summary: Method called every time the interval passes. Override to do something useful. + }, + + setInterval : function(interval){ + // summary: Reset the interval of a timer, whether running or not. + // interval: New interval, in milliseconds. + if (this.isRunning){ + dj_global.clearInterval(this.timer); + } + this.interval = interval; + if (this.isRunning){ + this.timer = dj_global.setInterval(dojo.lang.hitch(this, "onTick"), this.interval); + } + }, + + start : function(){ + // summary: Start the timer ticking. + // description: Calls the "onStart()" handler, if defined. + // Note that the onTick() function is not called right away, + // only after first interval passes. + if (typeof this.onStart == "function"){ + this.onStart(); + } + this.isRunning = true; + this.timer = dj_global.setInterval(dojo.lang.hitch(this, "onTick"), this.interval); + }, + + stop : function(){ + // summary: Stop the timer. + // description: Calls the "onStop()" handler, if defined. + if (typeof this.onStop == "function"){ + this.onStop(); + } + this.isRunning = false; + dj_global.clearInterval(this.timer); + } +}); diff --git a/source/web/scripts/ajax/dojo/src/lang/timing/__package__.js b/source/web/scripts/ajax/dojo/src/lang/timing/__package__.js new file mode 100644 index 0000000000..cbfeb7e4e2 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/timing/__package__.js @@ -0,0 +1,11 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang.timing.*"); diff --git a/source/web/scripts/ajax/dojo/src/lang/type.js b/source/web/scripts/ajax/dojo/src/lang/type.js new file mode 100644 index 0000000000..fb8d1250db --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lang/type.js @@ -0,0 +1,245 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lang.type"); +dojo.require("dojo.lang.common"); + +dojo.lang.whatAmI = function(value) { + dojo.deprecated("dojo.lang.whatAmI", "use dojo.lang.getType instead", "0.5"); + return dojo.lang.getType(value); +} +dojo.lang.whatAmI.custom = {}; + +dojo.lang.getType = function(/* anything */ value){ + // summary: Attempts to determine what type value is. + // value: Any literal value or object instance. + try{ + if(dojo.lang.isArray(value)){ + return "array"; // string + } + if(dojo.lang.isFunction(value)){ + return "function"; // string + } + if(dojo.lang.isString(value)){ + return "string"; // string + } + if(dojo.lang.isNumber(value)){ + return "number"; // string + } + if(dojo.lang.isBoolean(value)){ + return "boolean"; // string + } + if(dojo.lang.isAlien(value)){ + return "alien"; // string + } + if(dojo.lang.isUndefined(value)){ + return "undefined"; // string + } + // FIXME: should this go first? + for(var name in dojo.lang.whatAmI.custom){ + if(dojo.lang.whatAmI.custom[name](value)){ + return name; // string + } + } + if(dojo.lang.isObject(value)){ + return "object"; // string + } + }catch(e){} + return "unknown"; // string +} + +dojo.lang.isNumeric = function(/* anything */ value){ + // summary: + // Returns true if value can be interpreted as a number + // value: Any literal value or object instance. + // examples: + // dojo.lang.isNumeric(3); // returns true + // dojo.lang.isNumeric("3"); // returns true + // dojo.lang.isNumeric(new Number(3)); // returns true + // dojo.lang.isNumeric(new String("3")); // returns true + // + // dojo.lang.isNumeric(3/0); // returns false + // dojo.lang.isNumeric("foo"); // returns false + // dojo.lang.isNumeric(new Number("foo")); // returns false + // dojo.lang.isNumeric(false); // returns false + // dojo.lang.isNumeric(true); // returns false + return (!isNaN(value) + && isFinite(value) + && (value != null) + && !dojo.lang.isBoolean(value) + && !dojo.lang.isArray(value) + && !/^\s*$/.test(value) + ); // boolean +} + +dojo.lang.isBuiltIn = function(/* anything */ value){ + // summary: + // Returns true if value is of a type provided by core JavaScript + // description: + // Returns true for any literal, and for any object that is an + // instance of a built-in type like String, Number, Boolean, Array, + // Function, or Error. + // value: Any literal value or object instance. + + return (dojo.lang.isArray(value) + || dojo.lang.isFunction(value) + || dojo.lang.isString(value) + || dojo.lang.isNumber(value) + || dojo.lang.isBoolean(value) + || (value == null) + || (value instanceof Error) + || (typeof value == "error") + ); // boolean +} + +dojo.lang.isPureObject = function(/* anything */ value){ + // summary: + // Returns true for any value where the value of value.constructor == + // Object + // description: + // Returns true for any literal, and for any object that is an + // instance of a built-in type like String, Number, Boolean, Array, + // Function, or Error. + // value: + // Any literal value or object instance. + // examples: + // dojo.lang.isPureObject(new Object()); // returns true + // dojo.lang.isPureObject({a: 1, b: 2}); // returns true + // + // dojo.lang.isPureObject(new Date()); // returns false + // dojo.lang.isPureObject([11, 2, 3]); // returns false + return ((value != null) + && dojo.lang.isObject(value) + && value.constructor == Object + ); // boolean +} + +dojo.lang.isOfType = function(/* anything */ value, /* function */ type, /* object? */ keywordParameters) { + /* summary: + * Returns true if 'value' is of type 'type' + * description: + * Given a value and a datatype, this method returns true if the + * type of the value matches the datatype. The datatype parameter + * can be an array of datatypes, in which case the method returns + * true if the type of the value matches any of the datatypes. + * value: Any literal value or object instance. + * type: A class of object, or a literal type, or the string name of a type, or an array with a list of types. + * keywordParameters: {optional: boolean} + */ + + /* examples: + * dojo.lang.isOfType("foo", String); // returns true + * dojo.lang.isOfType(12345, Number); // returns true + * dojo.lang.isOfType(false, Boolean); // returns true + * dojo.lang.isOfType([6, 8], Array); // returns true + * dojo.lang.isOfType(dojo.lang.isOfType, Function); // returns true + * dojo.lang.isOfType({foo: "bar"}, Object); // returns true + * dojo.lang.isOfType(new Date(), Date); // returns true + * + * dojo.lang.isOfType("foo", "string"); // returns true + * dojo.lang.isOfType(12345, "number"); // returns true + * dojo.lang.isOfType(false, "boolean"); // returns true + * dojo.lang.isOfType([6, 8], "array"); // returns true + * dojo.lang.isOfType(dojo.lang.isOfType, "function"); // returns true + * dojo.lang.isOfType({foo: "bar"}, "object"); // returns true + * dojo.lang.isOfType(xxxxx, "undefined"); // returns true + * dojo.lang.isOfType(null, "null"); // returns true + * + * dojo.lang.isOfType("foo", [Number, String, Boolean]); // returns true + * dojo.lang.isOfType(12345, [Number, String, Boolean]); // returns true + * dojo.lang.isOfType(false, [Number, String, Boolean]); // returns true + * + * dojo.lang.isOfType(null, Date, {optional: true} ); // returns true // description: + */ + var optional = false; + if(keywordParameters){ + optional = keywordParameters["optional"]; + } + if(optional && ((value === null) || dojo.lang.isUndefined(value))){ + return true; // boolean + } + if(dojo.lang.isArray(type)){ + var arrayOfTypes = type; + for(var i in arrayOfTypes){ + var aType = arrayOfTypes[i]; + if(dojo.lang.isOfType(value, aType)){ + return true; // boolean + } + } + return false; // boolean + }else{ + if(dojo.lang.isString(type)){ + type = type.toLowerCase(); + } + switch (type) { + case Array: + case "array": + return dojo.lang.isArray(value); // boolean + case Function: + case "function": + return dojo.lang.isFunction(value); // boolean + case String: + case "string": + return dojo.lang.isString(value); // boolean + case Number: + case "number": + return dojo.lang.isNumber(value); // boolean + case "numeric": + return dojo.lang.isNumeric(value); // boolean + case Boolean: + case "boolean": + return dojo.lang.isBoolean(value); // boolean + case Object: + case "object": + return dojo.lang.isObject(value); // boolean + case "pureobject": + return dojo.lang.isPureObject(value); // boolean + case "builtin": + return dojo.lang.isBuiltIn(value); // boolean + case "alien": + return dojo.lang.isAlien(value); // boolean + case "undefined": + return dojo.lang.isUndefined(value); // boolean + case null: + case "null": + return (value === null); // boolean + case "optional": + dojo.deprecated('dojo.lang.isOfType(value, [type, "optional"])', 'use dojo.lang.isOfType(value, type, {optional: true} ) instead', "0.5"); + return ((value === null) || dojo.lang.isUndefined(value)); // boolean + default: + if(dojo.lang.isFunction(type)){ + return (value instanceof type); // boolean + }else{ + dojo.raise("dojo.lang.isOfType() was passed an invalid type"); + } + } + } + dojo.raise("If we get here, it means a bug was introduced above."); +} + +dojo.lang.getObject=function(/* String */ str){ + // summary: + // Will return an object, if it exists, based on the name in the passed string. + var parts=str.split("."), i=0, obj=dj_global; + do{ + obj=obj[parts[i++]]; + }while(i 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(/*int?*/ delay, /*bool?*/ gotoStart){ + // summary: Start the animation. + // delay: How many milliseconds to delay before starting. + // gotoStart: If true, starts the animation from the beginning; otherwise, + // starts it from its current position. + if(gotoStart){ + clearTimeout(this._timer); + this._active = false; + this._paused = false; + this._percent = 0; + }else if(this._active && !this._paused){ + return this; // dojo.lfx.Animation + } + + this.fire("handler", ["beforeBegin"]); + this.fire("beforeBegin"); + + if(delay > 0){ + setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay); + return this; // dojo.lfx.Animation + } + + 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; // dojo.lfx.Animation + }, + + pause: function(){ + // summary: Pauses a running animation. + clearTimeout(this._timer); + if(!this._active){ return this; /*dojo.lfx.Animation*/} + this._paused = true; + var value = this.curve.getValue(this._percent / 100); + this.fire("handler", ["pause", value]); + this.fire("onPause", [value]); + return this; // dojo.lfx.Animation + }, + + gotoPercent: function(/*Decimal*/ pct, /*bool?*/ andPlay){ + // summary: Sets the progress of the animation. + // pct: A percentage in decimal notation (between and including 0.0 and 1.0). + // andPlay: If true, play the animation after setting the progress. + clearTimeout(this._timer); + this._active = true; + this._paused = true; + this._percent = pct; + if(andPlay){ this.play(); } + return this; // dojo.lfx.Animation + }, + + stop: function(/*bool?*/ gotoEnd){ + // summary: Stops a running animation. + // gotoEnd: If true, the animation will end. + 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; // dojo.lfx.Animation + }, + + status: function(){ + // summary: Returns a string representation of the status of + // the animation. + if(this._active){ + return this._paused ? "paused" : "playing"; // String + }else{ + return "stopped"; // String + } + 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.Animation + } +}); + +dojo.lfx.Combine = function(/*dojo.lfx.IAnimation...*/ animations){ + // summary: An animation object to play animations passed to it at the same time. + 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]))){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + 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(/*int?*/ delay, /*bool?*/ gotoStart){ + // summary: Start the animations. + // delay: How many milliseconds to delay before starting. + // gotoStart: If true, starts the animations from the beginning; otherwise, + // starts them from their current position. + if( !this._anims.length ){ return this; /*dojo.lfx.Combine*/} + + this.fire("beforeBegin"); + + if(delay > 0){ + setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay); + return this; // dojo.lfx.Combine + } + + if(gotoStart || this._anims[0].percent == 0){ + this.fire("onBegin"); + } + this.fire("onPlay"); + this._animsCall("play", null, gotoStart); + return this; // dojo.lfx.Combine + }, + + pause: function(){ + // summary: Pauses the running animations. + this.fire("onPause"); + this._animsCall("pause"); + return this; // dojo.lfx.Combine + }, + + stop: function(/*bool?*/ gotoEnd){ + // summary: Stops the running animations. + // gotoEnd: If true, the animations will end. + this.fire("onStop"); + this._animsCall("stop", gotoEnd); + return this; // dojo.lfx.Combine + }, + + // private methods + _onAnimsEnded: function(){ + this._animsEnded++; + if(this._animsEnded >= this._anims.length){ + this.fire("onEnd"); + } + return this; // dojo.lfx.Combine + }, + + _animsCall: function(/*String*/ 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.Combine + } +}); + +dojo.lfx.Chain = function(/*dojo.lfx.IAnimation...*/ animations) { + // summary: An animation object to play animations passed to it + // one after another. + 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]))){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + 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(/*int?*/ delay, /*bool?*/ gotoStart){ + // summary: Start the animation sequence. + // delay: How many milliseconds to delay before starting. + // gotoStart: If true, starts the sequence from the beginning; otherwise, + // starts it from its current position. + if( !this._anims.length ) { return this; /*dojo.lfx.Chain*/} + 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; // dojo.lfx.Chain + } + + 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; // dojo.lfx.Chain + }, + + pause: function(){ + // summary: Pauses the running animation sequence. + if( this._anims[this._currAnim] ) { + this._anims[this._currAnim].pause(); + this.fire("onPause", [this._currAnim]); + } + return this; // dojo.lfx.Chain + }, + + playPause: function(){ + // summary: If the animation sequence is playing, pause it; otherwise, + // play it. + 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; // dojo.lfx.Chain + }, + + stop: function(){ + // summary: Stops the running animations. + var currAnim = this._anims[this._currAnim]; + if(currAnim){ + currAnim.stop(); + this.fire("onStop", [this._currAnim]); + } + return currAnim; // dojo.lfx.IAnimation + }, + + // 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.Chain + } +}); + +dojo.lfx.combine = function(/*dojo.lfx.IAnimation...*/ animations){ + // summary: Convenience function. Returns a dojo.lfx.Combine created + // using the animations passed in. + var anims = arguments; + if(dojo.lang.isArray(arguments[0])){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + anims = arguments[0]; + } + if(anims.length == 1){ return anims[0]; } + return new dojo.lfx.Combine(anims); // dojo.lfx.Combine +} + +dojo.lfx.chain = function(/*dojo.lfx.IAnimation...*/ animations){ + // summary: Convenience function. Returns a dojo.lfx.Chain created + // using the animations passed in. + var anims = arguments; + if(dojo.lang.isArray(arguments[0])){ + /* animations: dojo.lfx.IAnimation[] + pId: a */ + anims = arguments[0]; + } + if(anims.length == 1){ return anims[0]; } + return new dojo.lfx.Chain(anims); // dojo.lfx.Combine +} diff --git a/source/web/scripts/ajax/dojo/src/lfx/__package__.js b/source/web/scripts/ajax/dojo/src/lfx/__package__.js new file mode 100644 index 0000000000..7e12e1c9d3 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lfx/__package__.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + browser: ["dojo.lfx.html"], + dashboard: ["dojo.lfx.html"] +}); +dojo.provide("dojo.lfx.*"); \ No newline at end of file diff --git a/source/web/scripts/ajax/dojo/src/lfx/extras.js b/source/web/scripts/ajax/dojo/src/lfx/extras.js new file mode 100644 index 0000000000..29605c9e75 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lfx/extras.js @@ -0,0 +1,148 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lfx.extras"); + +dojo.require("dojo.lfx.html"); +dojo.require("dojo.lfx.Animation"); + +dojo.lfx.html.fadeWipeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current + // opacity to fully opaque while wiping it in. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anim = dojo.lfx.combine( + dojo.lfx.fadeIn(nodes, duration, easing), + dojo.lfx.wipeIn(nodes, duration, easing) + ); + + if(callback){ + anim.connect("onEnd", function(){ + callback(nodes, anim); + }); + } + + return anim; // dojo.lfx.Combine +} + +dojo.lfx.html.fadeWipeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current + // opacity to fully transparent while wiping it out. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anim = dojo.lfx.combine( + dojo.lfx.fadeOut(nodes, duration, easing), + dojo.lfx.wipeOut(nodes, duration, easing) + ); + + if(callback){ + /* callback: Function + pId: f */ + anim.connect("onEnd", function(){ + callback(nodes, anim); + }); + } + + return anim; // dojo.lfx.Combine +} + +dojo.lfx.html.scale = function(/*DOMNode[]*/nodes, + /*int*/ percentage, + /*bool?*/ scaleContent, + /*bool?*/ fromCenter, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will scale "nodes" by "percentage". + // nodes: An array of DOMNodes or one DOMNode. + // percentage: A whole number representing the percentage to scale "nodes". + // scaleContent: If true, will scale the contents of "nodes". + // fromCenter: If true, will scale "nodes" from its center rather than the + // lower right corner. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + + dojo.lang.forEach(nodes, function(node){ + var outer = dojo.html.getMarginBox(node); + + var actualPct = percentage/100.0; + var props = [ + { property: "width", + start: outer.width, + end: outer.width * actualPct + }, + { property: "height", + start: outer.height, + end: outer.height * actualPct + }]; + + if(scaleContent){ + var fontSize = dojo.html.getStyle(node, 'font-size'); + var fontSizeType = null; + if(!fontSize){ + fontSize = parseFloat('100%'); + fontSizeType = '%'; + }else{ + dojo.lang.some(['em','px','%'], function(item, index, arr){ + if(fontSize.indexOf(item)>0){ + fontSize = parseFloat(fontSize); + fontSizeType = item; + return true; + } + }); + } + props.push({ + property: "font-size", + start: fontSize, + end: fontSize * actualPct, + units: fontSizeType }); + } + + if(fromCenter){ + var positioning = dojo.html.getStyle(node, "position"); + var originalTop = node.offsetTop; + var originalLeft = node.offsetLeft; + var endTop = ((outer.height * actualPct) - outer.height)/2; + var endLeft = ((outer.width * actualPct) - outer.width)/2; + props.push({ + property: "top", + start: originalTop, + end: (positioning == "absolute" ? originalTop - endTop : (-1*endTop)) + }); + props.push({ + property: "left", + start: originalLeft, + end: (positioning == "absolute" ? originalLeft - endLeft : (-1*endLeft)) + }); + } + + var anim = dojo.lfx.propertyAnimation(node, props, duration, easing); + if(callback){ + anim.connect("onEnd", function(){ + callback(node, anim); + }); + } + + anims.push(anim); + }); + + return dojo.lfx.combine(anims); // dojo.lfx.Combine +} + +dojo.lang.mixin(dojo.lfx, dojo.lfx.html); diff --git a/source/web/scripts/ajax/dojo/src/lfx/html.js b/source/web/scripts/ajax/dojo/src/lfx/html.js new file mode 100644 index 0000000000..068c5f47c0 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lfx/html.js @@ -0,0 +1,748 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lfx.html"); + +dojo.require("dojo.gfx.color"); +dojo.require("dojo.lfx.Animation"); +dojo.require("dojo.lang.array"); +dojo.require("dojo.html.display"); +dojo.require("dojo.html.color"); +dojo.require("dojo.html.layout"); + +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, + /*Object[]*/ propertyMap, + /*int*/ duration, + /*function*/ easing, + /*Object*/ handlers){ + // summary: Returns an animation that will transition the properties of "nodes" + // depending how they are defined in "propertyMap". + // nodes: An array of DOMNodes or one DOMNode. + // propertyMap: { property: String, start: Decimal?, end: Decimal?, units: String? } + // An array of objects defining properties to change. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // handlers: { handler: Function?, onstart: Function?, onstop: Function?, onanimate: Function? } + 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){ + try{ + if(s == "opacity"){ + dojo.html.setOpacity(n, style[s]); + }else{ + n.style[s] = style[s]; + } + }catch(e){ dojo.debug(e); } + } + } + + 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.gfx.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.gfx.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.Animation +} + +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(/*DOMNode[]*/ nodes, + /*Object*/values, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary:Returns an animation that will fade the "nodes" from the start to end values passed. + // nodes: An array of DOMNodes or one DOMNode. + // values: { start: Decimal?, end: Decimal? } + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.Animation +} + +dojo.lfx.html.fadeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current opacity to fully opaque. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + return dojo.lfx.html.fade(nodes, { end: 1 }, duration, easing, callback); // dojo.lfx.Animation +} + +dojo.lfx.html.fadeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current opacity to fully transparent. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + return dojo.lfx.html.fade(nodes, { end: 0 }, duration, easing, callback); // dojo.lfx.Animation +} + +dojo.lfx.html.fadeShow = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from transparent to opaque and shows + // "nodes" at the end if it is hidden. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.Animation +} + +dojo.lfx.html.fadeHide = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will fade "nodes" from its current opacity to opaque and hides + // "nodes" at the end. + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.Animation +} + +dojo.lfx.html.wipeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will show and wipe in "nodes". + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + + dojo.lang.forEach(nodes, function(node){ + var oprop = { }; // old properties of node (before we mucked w/them) + + // get node height, either it's natural height or it's height specified via style or class attributes + // (for FF, the node has to be (temporarily) rendered to measure height) + // TODO: should this offscreen code be part of dojo.html, so that getBorderBox() works on hidden nodes? + var origTop, origLeft, origPosition; + with(node.style){ + origTop=top; origLeft=left; origPosition=position; + top="-9999px"; left="-9999px"; position="absolute"; + display=""; + } + var height = dojo.html.getBorderBox(node).height; + with(node.style){ + top=origTop; left=origLeft; position=origPosition; + display="none"; + } + + var anim = dojo.lfx.propertyAnimation(node, + { "height": { + start: 1, // 0 causes IE to display the whole panel + end: function(){ return height; } + } + }, + duration, + easing); + + anim.connect("beforeBegin", function(){ + oprop.overflow = node.style.overflow; + oprop.height = node.style.height; + with(node.style){ + overflow = "hidden"; + height = "1px"; // 0 causes IE to display the whole panel + } + dojo.html.show(node); + }); + + anim.connect("onEnd", function(){ + with(node.style){ + overflow = oprop.overflow; + height = oprop.height; + } + if(callback){ callback(node, anim); } + }); + anims.push(anim); + }); + + return dojo.lfx.combine(anims); // dojo.lfx.Combine +} + +dojo.lfx.html.wipeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will wipe out and hide "nodes". + // nodes: An array of DOMNodes or one DOMNode. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + + dojo.lang.forEach(nodes, function(node){ + var oprop = { }; // old properties of node (before we mucked w/them) + var anim = dojo.lfx.propertyAnimation(node, + { "height": { + start: function(){ return dojo.html.getContentBox(node).height; }, + end: 1 // 0 causes IE to display the whole panel + } + }, + duration, + easing, + { + "beforeBegin": function(){ + oprop.overflow = node.style.overflow; + oprop.height = node.style.height; + with(node.style){ + overflow = "hidden"; + } + dojo.html.show(node); + }, + + "onEnd": function(){ + dojo.html.hide(node); + with(node.style){ + overflow = oprop.overflow; + height = oprop.height; + } + if(callback){ callback(node, anim); } + } + } + ); + anims.push(anim); + }); + + return dojo.lfx.combine(anims); // dojo.lfx.Combine +} + +dojo.lfx.html.slideTo = function(/*DOMNode*/ nodes, + /*Object*/ coords, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will slide "nodes" from its current position to + // the position defined in "coords". + // nodes: An array of DOMNodes or one DOMNode. + // coords: { top: Decimal?, left: Decimal? } + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + var compute = dojo.html.getComputedStyle; + + if(dojo.lang.isArray(coords)){ + /* coords: Array + pId: a */ + 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.Combine +} + +dojo.lfx.html.slideBy = function(/*DOMNode*/ nodes, /*Object*/ coords, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){ + // summary: Returns an animation that will slide "nodes" from its current position + // to its current position plus the numbers defined in "coords". + // nodes: An array of DOMNodes or one DOMNode. + // coords: { top: Decimal?, left: Decimal? } + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + var compute = dojo.html.getComputedStyle; + + if(dojo.lang.isArray(coords)){ + /* coords: Array + pId: a */ + 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.Combine +} + +dojo.lfx.html.explode = function(/*DOMNode*/ start, + /*DOMNode*/ endNode, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will + // start: + // endNode: + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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); + if(endNode.explodeClassName){ outline.className = endNode.explodeClassName; } + with(outline.style){ + position = "absolute"; + display = "none"; + // border = "1px solid black"; + var backgroundStyle = h.getStyle(start, "background-color"); + backgroundColor = backgroundStyle ? backgroundStyle.toLowerCase() : "transparent"; + backgroundColor = (backgroundColor == "transparent") ? "rgb(221, 221, 221)" : backgroundColor; + } + dojo.body().appendChild(outline); + + with(endNode.style){ + visibility = "hidden"; + display = "block"; + } + var endCoords = h.toCoordinateObject(endNode, true); + with(endNode.style){ + display = "none"; + visibility = "visible"; + } + + var props = { opacity: { start: 0.5, 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.Animation +} + +dojo.lfx.html.implode = function(/*DOMNode*/ startNode, + /*DOMNode*/ end, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will + // startNode: + // end: + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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); + if (startNode.explodeClassName) { outline.className = startNode.explodeClassName; } + 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.5 } }; + 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.Animation +} + +dojo.lfx.html.highlight = function(/*DOMNode[]*/ nodes, + /*dojo.gfx.color.Color*/ startColor, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will set the background color + // of "nodes" to startColor and transition it to "nodes" + // original color. + // startColor: Color to transition from. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + 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.gfx.color.Color(startColor); + var endRgb = new dojo.gfx.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.Combine +} + +dojo.lfx.html.unhighlight = function(/*DOMNode[]*/ nodes, + /*dojo.gfx.color.Color*/ endColor, + /*int?*/ duration, + /*Function?*/ easing, + /*Function?*/ callback){ + // summary: Returns an animation that will transition "nodes" background color + // from its current color to "endColor". + // endColor: Color to transition to. + // duration: Duration of the animation in milliseconds. + // easing: An easing function. + // callback: Function to run at the end of the animation. + nodes = dojo.lfx.html._byId(nodes); + var anims = []; + + dojo.lang.forEach(nodes, function(node){ + var color = new dojo.gfx.color.Color(dojo.html.getBackgroundColor(node)); + var rgb = new dojo.gfx.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.lfx.Combine +} + +dojo.lang.mixin(dojo.lfx, dojo.lfx.html); diff --git a/source/web/scripts/ajax/dojo/src/lfx/rounded.js b/source/web/scripts/ajax/dojo/src/lfx/rounded.js new file mode 100644 index 0000000000..aa4598b03f --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/lfx/rounded.js @@ -0,0 +1,512 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.lfx.rounded"); + +dojo.require("dojo.lang.common"); +dojo.require("dojo.html.common"); +dojo.require("dojo.html.style"); +dojo.require("dojo.html.display"); +dojo.require("dojo.html.layout"); + +/* Port of curvyCorners, by Cameron Cooke and Tim Hutchison. + * Original port done by Brian Lucas. + * Refactor and function by trt. + */ +dojo.lfx.rounded = function(/* object */settings /* ... */){ + // summary + // Creates a set of rounded corners based on settings. + var options={ + validTags:settings.validTags || ["div"], // tags we can apply this to + autoPad:settings.autoPad!=null ? settings.autoPad : true, // automatically pad + antiAlias:settings.antiAlias!=null ? settings.antiAlias : true, // anti-alias corners + radii:{ // corner radii + tl:(settings.tl && settings.tl.radius!=null) ? settings.tl.radius:5, + tr:(settings.tr && settings.tr.radius!=null) ? settings.tr.radius:5, + bl:(settings.bl && settings.bl.radius!=null) ? settings.bl.radius:5, + br:(settings.br && settings.br.radius!=null) ? settings.br.radius:5 + } + }; + + // get the node list to operate on. + var nodes; + if(typeof(arguments[1]) == "string"){ + // a CSS classname was passed, grab a node list. + nodes=dojo.html.getElementsByClass(arguments[1]); + } else if(dojo.lang.isArrayLike(arguments[1])){ + // we assume that the second argument is an array of nodes to apply this to. + nodes=arguments[1]; + for(var i=0; i0){ + node.innerHTML=""; + } + + var topHeight=Math.max(options.radii.tl, options.radii.tr); + var bottomHeight=Math.max(options.radii.bl, options.radii.br); + + // build the containers. + if(options.radii.tl || options.radii.tr){ + top = document.createElement("div"); + top.style.width="100%"; + top.style.fontSize="1px"; + top.style.overflow="hidden"; + top.style.position="absolute"; + top.style.paddingLeft=format.borderWidth+"px"; + top.style.paddingRight=format.borderWidth+"px"; + top.style.height=topHeight+"px"; + top.style.top=(0-topHeight)+"px"; + top.style.left=(0-format.borderWidth)+"px"; + node.appendChild(top); + } + if(options.radii.bl || options.radii.br){ // bottom + bottom = document.createElement("div"); + bottom.style.width="100%"; + bottom.style.fontSize="1px"; + bottom.style.overflow="hidden"; + bottom.style.position="absolute"; + bottom.style.paddingLeft=format.borderWidth+"px"; + bottom.style.paddingRight=format.borderWidth+"px"; + bottom.style.height=bottomHeight+"px"; + bottom.style.bottom=(0-bottomHeight)+"px"; + bottom.style.left=(0-format.borderWidth)+"px"; + node.appendChild(bottom); + } + + // turn off the borders + if(top){ node.style.borderTopWidth = "0px"; } + if(bottom){ node.style.borderBottomWidth = "0px"; } + + // do the corners + var corners = ["tr", "tl", "br", "bl"]; + for(var i=0; i= borderRadius){ var y1=-1; } + var y2=Math.ceil(Math.sqrt(Math.pow(borderRadius,2)-Math.pow(x,2))); + if(x >= borderRadius){ y2=-1; } + var y3=Math.floor(Math.sqrt(Math.pow(j,2)-Math.pow((x+1),2)))-1; + if((x+1) >= j){ y3=-1; } + var y4=Math.ceil(Math.sqrt(Math.pow(j, 2)-Math.pow(x, 2))); + if(x >= j){ y4=-1; } + + // start drawing + if(y1 > -1){ + fns.draw(x, 0, format.color, 100, (y1+1), corner, -1, j, topHeight, format); + } + + // cycle the y-axis + for(var y=(y1+1); y= y2){ + if(y2 == -1){ y2 = 0; } + fns.draw(x, y2, format.borderColor, 100, (y3-y2+1), corner, 0, 0, topHeight, format) + } else { + if(y3 >= y1){ + fns.draw(x, (y1+1), format.borderColor, 100, (y3-y1), corner, 0, 0, topHeight, format); + } + } + for(var y=(y3+1); y0 ? 0:-1), options.radii[cc], topHeight, format); + } + } else { + y3=y1; + } + } + + // reposition pixels if not the bottom right. + if(cc != "br"){ + for(var t=0, k=corner.childNodes.length; t0){ + var content=document.createElement("div"); + content.style.position="relative"; + content.innerHTML=format.content; + content.className="autoPadDiv"; + if(topHeight < format.padding){ + content.style.paddingTop = Math.abs(topHeight-format.padding)+"px"; + } + if(bottomHeight < format.padding){ + content.style.paddingBottom = Math.abs(bottomHeight-format.padding)+"px"; + } + content.style.paddingLeft=format.padding+"px"; + content.style.paddingRight=format.padding+"px"; + node.appendChild(content); + } +}; + +var count=0; + +// helper methods. +dojo.lfx.rounded._fns={ + blend:function(clr1, clr2, frac){ + var c1={ + r:parseInt(clr1.substr(1,2),16), + g:parseInt(clr1.substr(3,2),16), + b:parseInt(clr1.substr(5,2),16) + }; + var c2={ + r:parseInt(clr2.substr(1,2),16), + g:parseInt(clr2.substr(3,2),16), + b:parseInt(clr2.substr(5,2),16) + }; + if(frac>1||frac<0){ frac=1; } + var ret=[ + Math.min(Math.max(Math.round((c1.r*frac)+(c2.r*(1-frac))),0),255), + Math.min(Math.max(Math.round((c1.g*frac)+(c2.g*(1-frac))),0),255), + Math.min(Math.max(Math.round((c1.b*frac)+(c2.b*(1-frac))),0),255) + ]; + for(var i=0; i=y && intersect < (y+1)){ + whatsides="Left"; + xval[point]=0; + yval[point++]=intersect-y; + } + + intersect=Math.sqrt((Math.pow(r,2)-Math.pow(y+1,2))); + if(intersect >=x && intersect < (x+1)){ + whatsides += "Top"; + xval[point]=intersect-x; + yval[point++]=1; + } + + intersect=Math.sqrt((Math.pow(r,2)-Math.pow(x+1,2))); + if(intersect >= y && intersect < (y+1)){ + whatsides += "Right"; + xval[point]=1; + yval[point++] = intersect-y; + } + + intersect=Math.sqrt((Math.pow(r,2)-Math.pow(y,2))); + if(intersect >=x && intersect < (x+1)){ + whatsides += "Bottom"; + xval[point]=intersect-x; + yval[point]=1; + } + + switch(whatsides){ + case "LeftRight": + return Math.min(yval[0],yval[1]) + ((Math.max(yval[0],yval[1])-Math.min(yval[0],yval[1]))/2); + case "TopRight": + return 1-(((1-xval[0])*(1-yval[1]))/2); + case "TopBottom": + return Math.min(xval[0],xval[1]) + ((Math.max(xval[0],xval[1])-Math.min(xval[0],xval[1]))/2); + case "LeftBottom": + return (yval[0]*xval[1])/2; + default: return 1; + } + }, + draw:function(x, y, color, opac, height, corner, image, radius, top, format){ + var px=document.createElement("div"); + px.style.height=height+"px" + px.style.width="1px"; + px.style.position="absolute"; + px.style.fontSize="1px"; + px.style.overflow="hidden"; + if(image==-1 && format.bgImage!=""){ + px.style.backgroundImage=format.bgImage; + px.style.backgroundPosition="-"+(format.width-(radius-x)+format.borderWidth) + +"px -"+((format.height+top+y)-format.borderWidth)+"px"; + } else { + px.style.backgroundColor=color; + } + if(opac!=100){ dojo.html.setOpacity(px, (opac/100)); } + px.style.top=y+"px"; + px.style.left=x+"px"; + corner.appendChild(px); + }, + getRGB:function(clr){ + var ret="#ffffff"; + if(clr!="" && clr!="transparent"){ + if(clr.substr(0,3)=="rgb"){ + var t=clr.substring(4, clr.indexOf(")")); + t=t.split(","); + for(var i=0; i 1) { + dh.modulesLoadedListeners.push(function() { + obj[functionName](); + }); + } + + //Added for xdomain loading. dojo.addOnLoad is used to + //indicate callbacks after doing some dojo.require() statements. + //In the xdomain case, if all the requires are loaded (after initial + //page load), then immediately call any listeners. + if(dh.post_load_ && dh.inFlightCount == 0 && !dh.loadNotifying){ + dh.callLoaded(); + } +} + +dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){ +// summary: registers a function to be triggered when the page unloads +// +// usage: +// dojo.addOnLoad(functionPointer) +// dojo.addOnLoad(object, "functionName") + var dh = dojo.hostenv; + if(arguments.length == 1){ + dh.unloadListeners.push(obj); + } else if(arguments.length > 1) { + dh.unloadListeners.push(function() { + obj[functionName](); + }); + } +} + +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(/*String*/modulename){ +// summary: +// Converts a module name in dotted JS notation to an array representing the path in the source tree + var syms = modulename.split("."); + for(var i = syms.length; i>0; i--){ + var parentModule = syms.slice(0, i).join("."); + if((i==1) && !this.moduleHasPrefix(parentModule)){ + // Support default module directory (sibling of dojo) for top-level modules + syms[0] = "../" + syms[0]; + }else{ + var parentModulePath = this.getModulePrefix(parentModule); + if(parentModulePath != parentModule){ + syms.splice(0, i, parentModulePath); + break; + } + } + } + return syms; // Array +} + +dojo.hostenv._global_omit_module_check = false; +dojo.hostenv.loadModule = function(/*String*/moduleName, /*Boolean?*/exactOnly, /*Boolean?*/omitModuleCheck){ +// summary: +// loads a Javascript module from the appropriate URI +// +// description: +// loadModule("A.B") first checks to see if symbol A.B is defined. +// If it is, it is simply returned (nothing to do). +// +// If it is not defined, it will look for "A/B.js" in the script root directory, +// 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 + + if(!moduleName){ return; } + omitModuleCheck = this._global_omit_module_check || omitModuleCheck; + 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("."); + + // this line allowed loading of a module manifest as if it were a namespace + // it's an interesting idea, but shouldn't be combined with 'namespaces' proper + // and leads to unwanted dependencies + // the effect can be achieved in other (albeit less-flexible) ways now, so I am + // removing this pending further design work + // perhaps we can explicitly define this idea of a 'module manifest', and subclass + // 'namespace manifest' from that + //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]; + var ok; + // 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, !omitModuleCheck ? moduleName : null); + if(ok){ break; } + syms.pop(); + } + }else{ + relpath = syms.join("/") + '.js'; + moduleName = nsyms.join('.'); + var modArg = !omitModuleCheck ? moduleName : null; + ok = this.loadPath(relpath, modArg); + if(!ok && !exactOnly){ + syms.pop(); + while(syms.length){ + relpath = syms.join('/') + '.js'; + ok = this.loadPath(relpath, modArg); + if(ok){ break; } + syms.pop(); + relpath = syms.join('/') + '/'+this.pkgFileName+'.js'; + if(startedRelative && relpath.charAt(0)=="/"){ + relpath = relpath.slice(1); + } + ok = this.loadPath(relpath, modArg); + if(ok){ break; } + } + } + + if(!ok && !omitModuleCheck){ + 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(!omitModuleCheck && !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; +} + +dojo.hostenv.startPackage = function(/*String*/packageName){ +// summary: +// Creates a JavaScript package +// +// description: +// startPackage("A.B") follows the path, and at each level creates a new empty +// object or uses what already exists. It returns the result. +// +// packageName: the package to be created as a String in dot notation + + //Make sure we have a string. + var fullPkgName = String(packageName); + var strippedPkgName = fullPkgName; + + var syms = packageName.split(/\./); + if(syms[syms.length-1]=="*"){ + syms.pop(); + strippedPkgName = syms.join("."); + } + var evaledPkg = dojo.evalObjPath(strippedPkgName, true); + this.loaded_modules_[fullPkgName] = evaledPkg; + this.loaded_modules_[strippedPkgName] = evaledPkg; + + return evaledPkg; // Object +} + +dojo.hostenv.findModule = function(/*String*/moduleName, /*Boolean?*/mustExist){ +// summary: +// Returns the Object representing the module, if it exists, otherwise null. +// +// moduleName A fully qualified module including package name, like 'A.B'. +// mustExist Optional, default false. throw instead of returning null +// if the module does not currently exist. + + var lmn = String(moduleName); + + if(this.loaded_modules_[lmn]){ + return this.loaded_modules_[lmn]; // Object + } + + if(mustExist){ + dojo.raise("no loaded module named '" + moduleName + "'"); + } + return null; // null +} + +//Start of old bootstrap2: + +dojo.kwCompoundRequire = function(/*Object containing Arrays*/modMap){ +// description: +// This method taks a "map" of arrays which one can use to optionally load dojo +// modules. The map is indexed by the possible dojo.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.*" ] +// }); + + 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, + // relative to Dojo root. For example, module acme is mapped to ../acme. + // If you want to use a different module name, use dojo.registerModulePath. + return dojo.hostenv.setModulePrefix(module, prefix); +} + +dojo.setModulePrefix = function(/*String*/module, /*String*/prefix){ + // summary: maps a module name to a path + dojo.deprecated('dojo.setModulePrefix("' + module + '", "' + prefix + '")', "replaced by dojo.registerModulePath", "0.5"); + return dojo.registerModulePath(module, prefix); +} + +dojo.exists = function(/*Object*/obj, /*String*/name){ + // summary: determine if an object supports a given method + // description: useful for longer api chains where you have to test each object in the chain + var p = name.split("."); + for(var i = 0; i < p.length; i++){ + if(!obj[p[i]]){ return false; } // Boolean + obj = obj[p[i]]; + } + return true; // Boolean +} + +// Localization routines + +dojo.hostenv.normalizeLocale = function(/*String?*/locale){ +// summary: +// Returns canonical form of locale, as used by Dojo. All variants are case-insensitive and are separated by '-' +// as specified in RFC 3066. If no locale is specified, the user agent's default is returned. + + var result = locale ? locale.toLowerCase() : dojo.locale; + if(result == "root"){ + result = "ROOT"; + } + return result;// String +}; + +dojo.hostenv.searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){ +// summary: +// A helper method to assist in searching for locale-based resources. Will iterate through +// the variants of a particular locale, either up or down, executing a callback function. +// For example, "en-us" and true will try "en-us" followed by "en" and finally "ROOT". + + locale = dojo.hostenv.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; } + } +} + +//These two functions are placed outside of preloadLocalizations +//So that the xd loading can use/override them. +dojo.hostenv.localesGenerated /***BUILD:localesGenerated***/; // value will be inserted here at build time, if necessary + +dojo.hostenv.registerNlsPrefix = function(){ +// summary: +// Register module "nls" to point where Dojo can find pre-built localization files + dojo.registerModulePath("nls","nls"); +} + +dojo.hostenv.preloadLocalizations = function(){ +// summary: +// Load built, flattened resource bundles, if available for all locales used in the page. +// Execute only once. Note that this is a no-op unless there is a build. + + if(dojo.hostenv.localesGenerated){ + dojo.hostenv.registerNlsPrefix(); + + function preload(locale){ + locale = dojo.hostenv.normalizeLocale(locale); + dojo.hostenv.searchLocalePath(locale, true, function(loc){ + for(var i=0; i bestLocale.length){ + bestLocale = flatLocales[i]; + } + } + } + if(!bestLocale){ + bestLocale = "ROOT"; + } + } + + //See if the desired locale is already loaded. + var tempLocale = availableFlatLocales ? bestLocale : targetLocale; + var bundle = dojo.hostenv.findModule(bundlePackage); + var localizedBundle = null; + if(bundle){ + if(djConfig.localizationComplete && bundle._built){return;} + var jsLoc = tempLocale.replace('-', '_'); + var translationPackage = bundlePackage+"."+jsLoc; + localizedBundle = dojo.hostenv.findModule(translationPackage); + } + + if(!localizedBundle){ + bundle = dojo.hostenv.startPackage(bundlePackage); + var syms = dojo.hostenv.getModuleSymbols(moduleName); + var modpath = syms.concat("nls").join("/"); + var parent; + + dojo.hostenv.searchLocalePath(tempLocale, availableFlatLocales, function(loc){ + var jsLoc = loc.replace('-', '_'); + var translationPackage = bundlePackage + "." + jsLoc; + var loaded = false; + if(!dojo.hostenv.findModule(translationPackage)){ + // Mark loaded whether it's found or not, so that further load attempts will not be made + dojo.hostenv.startPackage(translationPackage); + 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 parent bundle, then mix-in result from loadPath + var clazz = function(){}; + clazz.prototype = parent; + bundle[jsLoc] = new clazz(); + for(var j in hash){ bundle[jsLoc][j] = hash[j]; } + }); + }else{ + loaded = true; + } + if(loaded && bundle[jsLoc]){ + parent = bundle[jsLoc]; + }else{ + bundle[jsLoc] = parent; + } + + if(availableFlatLocales){ + //Stop the locale path searching if we know the availableFlatLocales, since + //the first call to this function will load the only bundle that is needed. + return true; + } + }); + } + + //Save the best locale bundle as the target locale bundle when we know the + //the available bundles. + if(availableFlatLocales && targetLocale != bestLocale){ + bundle[targetLocale.replace('-', '_')] = bundle[bestLocale.replace('-', '_')]; + } +}; + +(function(){ + // If other locales are used, dojo.requireLocalization should load them as well, by default. + // Override dojo.requireLocalization to do load the default bundle, then iterate through the + // extraLocale list and load those translations as well, unless a particular locale was requested. + + var extra = djConfig.extraLocale; + if(extra){ + if(!extra instanceof Array){ + extra = [extra]; + } + + var req = dojo.requireLocalization; + dojo.requireLocalization = function(m, b, locale, availableFlatLocales){ + req(m,b,locale, availableFlatLocales); + if(locale){return;} + for(var i=0; i 0){ + output.push("depends: ["); + for(var i = 0; i < deps.length; i++){ + if(i > 0){ + output.push(",\n"); + } + output.push("[" + deps[i] + "]"); + } + output.push("],"); + } + + //Add the contents of the file inside a function. + //Pass in dojo as an argument to the function to help with + //allowing multiple versions of dojo in a page. + output.push("\ndefinePackage: function(dojo){"); + output.push(contents); + output.push("\n}});"); + + return output.join(""); //String +} + +dojo.hostenv.loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){ + //summary: Internal xd loader function. Overrides loadPath() from loader.js. + //xd loading requires slightly different behavior from loadPath(). + + + //Only do getBaseScriptUri if path does not start with a URL with a protocol. + //If there is a colon before the first / then, we have a URL with a protocol. + var colonIndex = relpath.indexOf(":"); + var slashIndex = relpath.indexOf("/"); + var uri; + var currentIsXDomain = false; + if(colonIndex > 0 && colonIndex < slashIndex){ + uri = relpath; + this.isXDomain = currentIsXDomain = true; + }else{ + uri = this.getBaseScriptUri() + relpath; + + //Is ithe base script URI-based URL a cross domain URL? + colonIndex = uri.indexOf(":"); + slashIndex = uri.indexOf("/"); + if(colonIndex > 0 && colonIndex < slashIndex && (!location.host || uri.indexOf("http://" + location.host) != 0)){ + this.isXDomain = currentIsXDomain = true; + } + } + + if(djConfig.cacheBust && dojo.render.html.capable) { uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,""); } + try{ + return ((!module || this.isXDomain) ? this.loadUri(uri, cb, currentIsXDomain, module) : this.loadUriAndCheck(uri, module, cb)); //boolean + }catch(e){ + dojo.debug(e); + return false; //boolean + } +} + +dojo.hostenv.loadUri = function(/*String*/uri, /*Function?*/cb, /*boolean*/currentIsXDomain, /*String?*/module){ + //summary: Internal xd loader function. Overrides loadUri() from loader.js. + // xd loading requires slightly different behavior from loadPath(). + //description: Wanted to override getText(), but it is used by + // the widget code in too many, synchronous ways right now. + if(this.loadedUris[uri]){ + return 1; //boolean + } + + //Add the module (package) to the list of modules. + if(this.isXDomain){ + //Curious: is this array going to get whacked with multiple access since scripts + //load asynchronously and may be accessing the array at the same time? + //JS is single-threaded supposedly, so it should be ok. And we don't need + //a precise ordering. + this.xdOrderedReqs.push(module); + + //Add to waiting packages. + //If this is a __package__.js file, then this must be + //a package.* request (since xdomain can only work with the first + //path in a package search list. However, .* module names are not + //passed to this function, so do an adjustment here. + if(uri.indexOf("__package__") != -1){ + module += ".*"; + } + + this.xdInFlight[module] = true; + + //Increment inFlightCount + //This will stop the modulesLoaded from firing all the way. + this.inFlightCount++; + + //Start timer + if(!this.xdTimer){ + this.xdTimer = setInterval("dojo.hostenv.watchInFlightXDomain();", 100); + } + this.xdStartTime = (new Date()).getTime(); + } + + if (currentIsXDomain){ + //Fix name to be a .xd.fileextension name. + var lastIndex = uri.lastIndexOf('.'); + if(lastIndex <= 0){ + lastIndex = uri.length - 1; + } + + var xdUri = uri.substring(0, lastIndex) + ".xd"; + if(lastIndex != uri.length - 1){ + xdUri += uri.substring(lastIndex, uri.length); + } + + //Add to script src + var element = document.createElement("script"); + element.type = "text/javascript"; + element.src = xdUri; + if(!this.headElement){ + this.headElement = document.getElementsByTagName("head")[0]; + } + this.headElement.appendChild(element); + }else{ + var contents = this.getText(uri, null, true); + if(contents == null){ return 0; /*boolean*/} + + if(this.isXDomain){ + var pkg = this.createXdPackage(contents); + dj_eval(pkg); + }else{ + if(cb){ contents = '('+contents+')'; } + var value = dj_eval(contents); + if(cb){ + cb(value); + } + } + } + + //These steps are done in the non-xd loader version of this function. + //Maintain these steps to fit in with the existing system. + this.loadedUris[uri] = true; + return 1; //boolean +} + +dojo.hostenv.packageLoaded = function(/*Object*/pkg){ + //summary: Internal xd loader function. Called by an xd module when + //it has been loaded via a script tag. + var deps = pkg.depends; + var requireList = null; + var requireAfterList = null; + var provideList = []; + if(deps && deps.length > 0){ + var dep = null; + var insertHint = 0; + var attachedPackage = false; + for(var i = 0; i < deps.length; i++){ + dep = deps[i]; + + //Look for specific dependency indicators. + if (dep[0] == "provide" || dep[0] == "hostenv.moduleLoaded"){ + provideList.push(dep[1]); + }else{ + if(!requireList){ + requireList = []; + } + if(!requireAfterList){ + requireAfterList = []; + } + + var unpackedDeps = this.unpackXdDependency(dep); + if(unpackedDeps.requires){ + requireList = requireList.concat(unpackedDeps.requires); + } + if(unpackedDeps.requiresAfter){ + requireAfterList = requireAfterList.concat(unpackedDeps.requiresAfter); + } + } + + //Call the dependency indicator to allow for the normal dojo setup. + //Only allow for one dot reference, for the hostenv.* type calls. + var depType = dep[0]; + var objPath = depType.split("."); + if(objPath.length == 2){ + dojo[objPath[0]][objPath[1]].apply(dojo[objPath[0]], dep.slice(1)); + }else{ + dojo[depType].apply(dojo, dep.slice(1)); + } + } + + //Save off the package contents for definition later. + var contentIndex = this.xdContents.push({content: pkg.definePackage, isDefined: false}) - 1; + + //Add provide/requires to dependency map. + for(var i = 0; i < provideList.length; i++){ + this.xdDepMap[provideList[i]] = { requires: requireList, requiresAfter: requireAfterList, contentIndex: contentIndex }; + } + + //Now update the inflight status for any provided packages in this loaded package. + //Do this at the very end (in a *separate* for loop) to avoid shutting down the + //inflight timer check too soon. + for(var i = 0; i < provideList.length; i++){ + this.xdInFlight[provideList[i]] = false; + } + } +} + +dojo.hostenv.xdLoadFlattenedBundle = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*Object*/bundleData){ + //summary: Internal xd loader function. Used when loading + //a flattened localized bundle via a script tag. + locale = locale || "root"; + var jsLoc = dojo.hostenv.normalizeLocale(locale).replace('-', '_'); + var bundlePackage = [moduleName, "nls", bundleName].join("."); + var bundle = dojo.hostenv.startPackage(bundlePackage); + bundle[jsLoc] = bundleData; + + //Assign the bundle for the original locale(s) we wanted. + var mapName = [moduleName, jsLoc, bundleName].join("."); + var bundleMap = dojo.hostenv.xdBundleMap[mapName]; + if(bundleMap){ + for(var param in bundleMap){ + bundle[param] = bundleData; + } + } +}; + + +dojo.hostenv.xdBundleMap = {}; + +dojo.xdRequireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String*/availableFlatLocales){ + //summary: Internal xd loader function. The xd version of dojo.requireLocalization. + var locales = availableFlatLocales.split(","); + + //Find the best-match locale to load. + var jsLoc = dojo.hostenv.normalizeLocale(locale); + + var bestLocale = ""; + for(var i = 0; i < locales.length; i++){ + //Locale must match from start of string. + if(jsLoc.indexOf(locales[i]) == 0){ + if(locales[i].length > bestLocale.length){ + bestLocale = locales[i]; + } + } + } + + var fixedBestLocale = bestLocale.replace('-', '_'); + //See if the bundle we are going to use is already loaded. + var bundlePackage = dojo.evalObjPath([moduleName, "nls", bundleName].join(".")); + if(bundlePackage && bundlePackage[fixedBestLocale]){ + bundle[jsLoc.replace('-', '_')] = bundlePackage[fixedBestLocale]; + }else{ + //Need to remember what locale we wanted and which one we actually use. + //Then when we load the one we are actually using, use that bundle for the one + //we originally wanted. + var mapName = [moduleName, (fixedBestLocale||"root"), bundleName].join("."); + var bundleMap = dojo.hostenv.xdBundleMap[mapName]; + if(!bundleMap){ + bundleMap = dojo.hostenv.xdBundleMap[mapName] = {}; + } + bundleMap[jsLoc.replace('-', '_')] = true; + + //Do just a normal dojo.require so the package tracking stuff works as usual. + dojo.require(moduleName + ".nls" + (bestLocale ? "." + bestLocale : "") + "." + bundleName); + } +} + +;(function(){ + // Simulate the extra locale work that dojo.requireLocalization does. + + var extra = djConfig.extraLocale; + if(extra){ + if(!extra instanceof Array){ + extra = [extra]; + } + + dojo._xdReqLoc = dojo.xdRequireLocalization; + dojo.xdRequireLocalization = function(m, b, locale, fLocales){ + dojo._xdReqLoc(m,b,locale, fLocales); + if(locale){return;} + for(var i=0; i 0){ + var nextReq; + for(var i = 0; i < reqs.length; i++){ + nextReq = reqs[i].name; + if(nextReq && !reqChain[nextReq]){ + //New req depedency. Follow it down. + reqChain.push(nextReq); + reqChain[nextReq] = true; + this.xdEvalReqs(reqChain); + } + } + } +} + +dojo.hostenv.xdEvalReqs = function(/*Array*/reqChain){ + //summary: Internal xd loader function. + //Does a depth first, breadth second search and eval of required modules. + if(reqChain.length > 0){ + var req = reqChain[reqChain.length - 1]; + var pkg = this.xdDepMap[req]; + if(pkg){ + //Trace down any requires for this package. + this.xdTraceReqs(pkg.requires, reqChain); + + //Evaluate the package. + var contents = this.xdContents[pkg.contentIndex]; + if(!contents.isDefined){ + //Evaluate the package to bring it into being. + //Pass dojo in so that later, to support multiple versions of dojo + //in a page, we can pass which version of dojo to use. + contents.content(dojo); + contents.isDefined = true; + } + this.xdDepMap[req] = null; + + //Trace down any requireAfters for this package.. + this.xdTraceReqs(pkg.requiresAfter, reqChain); + } + + //Done with that require. Remove it and go to the next one. + reqChain.pop(); + this.xdEvalReqs(reqChain); + } +} + +dojo.hostenv.clearXdInterval = function(){ + //summary: Internal xd loader function. + //Clears the interval timer used to check on the + //status of in-flight xd module resource requests. + clearInterval(this.xdTimer); + this.xdTimer = 0; +} + +dojo.hostenv.watchInFlightXDomain = function(){ + //summary: Internal xd loader function. + //Monitors in-flight requests for xd module resources. + + //Make sure we haven't waited timed out. + var waitInterval = (djConfig.xdWaitSeconds || 30) * 1000; + + if(this.xdStartTime + waitInterval < (new Date()).getTime()){ + this.clearXdInterval(); + var noLoads = ""; + for(var param in this.xdInFlight){ + if(this.xdInFlight[param]){ + noLoads += param + " "; + } + } + dojo.raise("Could not load cross-domain packages: " + noLoads); + } + + //If any are true, then still waiting. + //Come back later. + for(var param in this.xdInFlight){ + if(this.xdInFlight[param]){ + return; + } + } + + //All done loading. Clean up and notify that we are loaded. + this.clearXdInterval(); + + this.xdWalkReqs(); + + //Evaluate any packages that were not evaled before. + //This normally shouldn't happen with proper dojo.provide and dojo.require + //usage, but providing it just in case. Note that these may not be executed + //in the original order that the developer intended. + //Pass dojo in so that later, to support multiple versions of dojo + //in a page, we can pass which version of dojo to use. + for(var i = 0; i < this.xdContents.length; i++){ + var current = this.xdContents[i]; + if(current.content && !current.isDefined){ + current.content(dojo); + } + } + + //Clean up for the next round of xd loading. + this.resetXd(); + + //Clear inflight count so we will finally do finish work. + this.inFlightCount = 0; + this.callLoaded(); +} + +dojo.hostenv.flattenRequireArray = function(/*Array*/target){ + //summary: Internal xd loader function. + //Flattens an array of arrays into a one-level deep array. + + //Each result could be an array of 3 elements (the 3 arguments to dojo.require). + //We only need the first one. + if(target){ + for(var i = 0; i < target.length; i++){ + if(target[i] instanceof Array){ + target[i] = {name: target[i][0], content: null}; + }else{ + target[i] = {name: target[i], content: null}; + } + } + } +} + + +dojo.hostenv.xdHasCalledPreload = false; +dojo.hostenv.xdRealCallLoaded = dojo.hostenv.callLoaded; +dojo.hostenv.callLoaded = function(){ + //summary: Internal xd loader function. Overrides callLoaded() from loader.js + //description: The method is overridden because xd loading needs to preload + //any flattened i18n bundles before dojo starts executing code, + //since xd loading cannot do it synchronously, as the i18n code normally expects. + + //If getModulePrefix for dojo returns anything other than "src", that means + //there is a path registered for dojo, with implies that dojo was xdomain loaded. + if(this.xdHasCalledPreload || dojo.hostenv.getModulePrefix("dojo") == "src" || !this.localesGenerated){ + this.xdRealCallLoaded(); + this.xdHasCalledPreload = true; + }else{ + if(this.localesGenerated){ + this.registerNlsPrefix = function(){ + //Need to set the nls prefix to be the xd location. + dojo.registerModulePath("nls", dojo.hostenv.getModulePrefix("dojo") + "/../nls"); + }; + this.preloadLocalizations(); + } + this.xdHasCalledPreload = true; + } +} diff --git a/source/web/scripts/ajax/dojo/src/logging/ConsoleLogger.js b/source/web/scripts/ajax/dojo/src/logging/ConsoleLogger.js new file mode 100644 index 0000000000..c1188c8f46 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/logging/ConsoleLogger.js @@ -0,0 +1,108 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.logging.ConsoleLogger"); +dojo.require("dojo.logging.Logger"); + +dojo.lang.extend(dojo.logging.MemoryLogHandler,{ + + debug:function(){ + dojo.hostenv.println.apply(this,arguments); + }, + info:function(){ + dojo.hostenv.println.apply(this,arguments); + }, + warn:function(){ + dojo.hostenv.println.apply(this,arguments); + }, + error:function(){ + dojo.hostenv.println.apply(this,arguments); + }, + critical:function(){ + dojo.hostenv.println.apply(this,arguments); + }, + + emit:function(record){ + if (!djConfig.isDebug) { return; } + + var funcName=null; + switch(record.level){ + case 1: + funcName="debug"; + break; + case 2: + funcName="info"; + break; + case 3: + funcName="warn"; + break; + case 4: + funcName="error"; + break; + case 5: + funcName="critical"; + break; + default: + funcName="debug"; + } + + var logStr = String(dojo.log.getLevelName(record.level)+": " + +record.time.toLocaleTimeString())+": "+record.message; + if(record.msgArgs && record.msgArgs.length > 0){ + this[funcName].call(this, logStr, record.msgArgs); + } else { + this[funcName].call(this, logStr); + } + + this.data.push(record); + if(this.numRecords != -1){ + while(this.data.length>this.numRecords){ + this.data.shift(); + } + } + } +}); + +if(!dj_undef("console") && !dj_undef("info", console)){ + dojo.lang.extend(dojo.logging.MemoryLogHandler,{ + debug:function(){ + console.debug.apply(this, arguments); + }, + info:function(){ + console.info.apply(this, arguments); + }, + warn:function(){ + console.warn.apply(this, arguments); + }, + error:function(){ + console.error.apply(this, arguments); + }, + critical:function(){ + console.error.apply(this, arguments); + } + }); + + dojo.lang.extend(dojo.logging.Logger,{ + exception: function(msg, e, squelch){ + var args=[msg]; + + if(e){ + msg+=" : "+ e.name + " " + (e.description||e.message); + args.push(e); + } + + this.logType("ERROR", args); + if(!squelch){ + throw e; + } + } + }); + +} diff --git a/source/web/scripts/ajax/dojo/src/logging/Logger.js b/source/web/scripts/ajax/dojo/src/logging/Logger.js new file mode 100644 index 0000000000..e8f7e9f3ed --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/logging/Logger.js @@ -0,0 +1,474 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.logging.Logger"); +dojo.provide("dojo.logging.LogFilter"); +dojo.provide("dojo.logging.Record"); +dojo.provide("dojo.log"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.lang.declare"); + +/* This is the dojo logging facility, which is imported from nWidgets + (written by Alex Russell, CLA on file), which is patterned on the + Python logging module, which in turn has been heavily influenced by + log4j (execpt with some more pythonic choices, which we adopt as well). + + While the dojo logging facilities do provide a set of familiar + interfaces, many of the details are changed to reflect the constraints + of the browser environment. Mainly, file and syslog-style logging + facilites are not provided, with HTTP POST and GET requests being the + only ways of getting data from the browser back to a server. Minimal + support for this (and XML serialization of logs) is provided, but may + not be of practical use in a deployment environment. + + The Dojo logging classes are agnostic of any environment, and while + default loggers are provided for browser-based interpreter + environments, this file and the classes it define are explicitly + designed to be portable to command-line interpreters and other + ECMA-262v3 envrionments. + + the logger needs to accomidate: + log "levels" + type identifiers + file? + message + tic/toc? + + The logger should ALWAYS record: + time/date logged + message + type + level +*/ +// TODO: define DTD for XML-formatted log messages +// TODO: write XML Formatter class +// TODO: write HTTP Handler which uses POST to send log lines/sections + + +dojo.logging.Record = function(/*Integer*/logLevel, /*String||Array*/message){ + // summary: + // A simple data structure class that stores information for and about + // a logged event. Objects of this type are created automatically when + // an event is logged and are the internal format in which information + // about log events is kept. + // logLevel: + // Integer mapped via the dojo.logging.log.levels object from a + // string. This mapping also corresponds to an instance of + // dojo.logging.Logger + // message: + // The contents of the message represented by this log record. + this.level = logLevel; + this.message = ""; + this.msgArgs = []; + this.time = new Date(); + + if(dojo.lang.isArray(message)){ + if(message.length > 0 && dojo.lang.isString(message[0])){ + this.message=message.shift(); + } + this.msgArgs = message; + }else{ + this.message = message; + } + // FIXME: what other information can we receive/discover here? +} + +dojo.logging.LogFilter = function(loggerChain){ + // summary: + // An empty parent (abstract) class which concrete filters should + // inherit from. Filters should have only a single method, filter(), + // which processes a record and returns true or false to denote + // whether or not it should be handled by the next step in a filter + // chain. + this.passChain = loggerChain || ""; + this.filter = function(record){ + // FIXME: need to figure out a way to enforce the loggerChain + // restriction + return true; // pass all records + } +} + +dojo.logging.Logger = function(){ + this.cutOffLevel = 0; + this.propagate = true; + this.parent = null; + // storage for dojo.logging.Record objects seen and accepted by this logger + this.data = []; + this.filters = []; + this.handlers = []; +} + +dojo.extend(dojo.logging.Logger,{ + _argsToArr: function(args){ + var ret = []; + for(var x=0; x= this.cutOffLevel; // boolean + }, + + getEffectiveLevel: function(){ + // summary: + // gets the effective cutoff level, including that of any + // potential parent loggers in the chain. + if((this.cutOffLevel==0)&&(this.parent)){ + return this.parent.getEffectiveLevel(); // Integer + } + return this.cutOffLevel; // Integer + }, + + addFilter: function(/*dojo.logging.LogFilter*/flt){ + // summary: + // registers a new LogFilter object. All records will be passed + // through this filter from now on. + this.filters.push(flt); + return this.filters.length-1; // Integer + }, + + removeFilterByIndex: function(/*Integer*/fltIndex){ + // summary: + // removes the filter at the specified index from the filter + // chain. Returns whether or not removal was successful. + if(this.filters[fltIndex]){ + delete this.filters[fltIndex]; + return true; // boolean + } + return false; // boolean + }, + + removeFilter: function(/*dojo.logging.LogFilter*/fltRef){ + // summary: + // removes the passed LogFilter. Returns whether or not removal + // was successful. + for(var x=0; x=this.cutOffLevel)){ + this.parent.log(lvl, msg); + return false; + } + // FIXME: need to call logging providers here! + this.handle(new dojo.logging.Record(lvl, msg)); + return true; + }, + + // logger helpers + debug:function(/*string*/msg){ + // summary: + // log the msg and any other arguments at the "debug" logging + // level. + return this.logType("DEBUG", this._argsToArr(arguments)); + }, + + info: function(msg){ + // summary: + // log the msg and any other arguments at the "info" logging + // level. + return this.logType("INFO", this._argsToArr(arguments)); + }, + + warning: function(msg){ + // summary: + // log the msg and any other arguments at the "warning" logging + // level. + return this.logType("WARNING", this._argsToArr(arguments)); + }, + + error: function(msg){ + // summary: + // log the msg and any other arguments at the "error" logging + // level. + return this.logType("ERROR", this._argsToArr(arguments)); + }, + + critical: function(msg){ + // summary: + // log the msg and any other arguments at the "critical" logging + // level. + return this.logType("CRITICAL", this._argsToArr(arguments)); + }, + + exception: function(/*string*/msg, /*Error*/e, /*boolean*/squelch){ + // summary: + // logs the error and the message at the "exception" logging + // level. If squelch is true, also prevent bubbling of the + // exception. + + // FIXME: this needs to be modified to put the exception in the msg + // if we're on Moz, we can get the following from the exception object: + // lineNumber + // message + // fileName + // stack + // name + // on IE, we get: + // name + // message (from MDA?) + // number + // description (same as message!) + if(e){ + var eparts = [e.name, (e.description||e.message)]; + if(e.fileName){ + eparts.push(e.fileName); + eparts.push("line "+e.lineNumber); + // eparts.push(e.stack); + } + msg += " "+eparts.join(" : "); + } + + this.logType("ERROR", msg); + if(!squelch){ + throw e; + } + }, + + logType: function(/*string*/type, /*array*/args){ + // summary: + // a more "user friendly" version of the log() function. Takes the + // named log level instead of the corresponding integer. + return this.log.apply(this, [dojo.logging.log.getLevel(type), + args]); + }, + + warn:function(){ + // summary: shorthand for warning() + this.warning.apply(this,arguments); + }, + err:function(){ + // summary: shorthand for error() + this.error.apply(this,arguments); + }, + crit:function(){ + // summary: shorthand for critical() + this.critical.apply(this,arguments); + } +}); + +// the Handler class +dojo.logging.LogHandler = function(level){ + this.cutOffLevel = (level) ? level : 0; + this.formatter = null; // FIXME: default formatter? + this.data = []; + this.filters = []; +} +dojo.lang.extend(dojo.logging.LogHandler,{ + + setFormatter:function(formatter){ + dojo.unimplemented("setFormatter"); + }, + + flush:function(){ + // summary: + // Unimplemented. Should be implemented by subclasses to handle + // finishing a transaction or otherwise comitting pending log + // messages to whatevery underlying transport or storage system is + // available. + }, + close:function(){ + // summary: + // Unimplemented. Should be implemented by subclasses to handle + // shutting down the logger, including a call to flush() + }, + handleError:function(){ + // summary: + // Unimplemented. Should be implemented by subclasses. + dojo.deprecated("dojo.logging.LogHandler.handleError", "use handle()", "0.6"); + }, + + handle:function(/*dojo.logging.Record*/record){ + // summary: + // Emits the record object passed in should the record meet the + // current logging level cuttof, as specified in cutOffLevel. + if((this.filter(record))&&(record.level>=this.cutOffLevel)){ + this.emit(record); + } + }, + + emit:function(/*dojo.logging.Record*/record){ + // summary: + // Unimplemented. Should be implemented by subclasses to handle + // an individual record. Subclasses may batch records and send + // them to their "substrate" only when flush() is called, but this + // is generally not a good idea as losing logging messages may + // make debugging significantly more difficult. Tuning the volume + // of logging messages written to storage should be accomplished + // with log levels instead. + dojo.unimplemented("emit"); + } +}); + +// set aliases since we don't want to inherit from dojo.logging.Logger +void(function(){ // begin globals protection closure + var names = [ + "setLevel", "addFilter", "removeFilterByIndex", "removeFilter", + "removeAllFilters", "filter" + ]; + var tgt = dojo.logging.LogHandler.prototype; + var src = dojo.logging.Logger.prototype; + for(var x=0; xinteger conversion for log levels + for(var x=0; xthis.numRecords){ + this.data.shift(); + } + } + } + } +); + +dojo.logging.logQueueHandler = new dojo.logging.MemoryLogHandler(0,50,0,10000); + +dojo.logging.log.addHandler(dojo.logging.logQueueHandler); +dojo.log = dojo.logging.log; diff --git a/source/web/scripts/ajax/dojo/src/logging/__package__.js b/source/web/scripts/ajax/dojo/src/logging/__package__.js new file mode 100644 index 0000000000..f3b606375e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/logging/__package__.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: [["dojo.logging.Logger", false, false]], + rhino: ["dojo.logging.RhinoLogger"] +}); +dojo.provide("dojo.logging.*"); diff --git a/source/web/scripts/ajax/dojo/src/math.js b/source/web/scripts/ajax/dojo/src/math.js new file mode 100644 index 0000000000..6410101c63 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/math.js @@ -0,0 +1,127 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.math"); + +dojo.math.degToRad = function(/* float */x) { + // summary + // Converts degrees to radians. + return (x*Math.PI) / 180; // float +} +dojo.math.radToDeg = function(/* float */x) { + // summary + // Converts radians to degrees. + return (x*180) / Math.PI; // float +} + +dojo.math.factorial = function(/* integer */n){ + // summary + // Returns n! + if(n<1){ return 0; } + var retVal = 1; + for(var i=1;i<=n;i++){ retVal *= i; } + return retVal; // integer +} + +dojo.math.permutations = function(/* integer */n, /* integer */k) { + // summary + // The number of ways of obtaining an ordered subset of k elements from a set of n elements + if(n==0 || k==0) return 1; + return (dojo.math.factorial(n) / dojo.math.factorial(n-k)); // float +} + +dojo.math.combinations = function (/* integer */n, /* integer */r) { + // summary + // The number of ways of picking n unordered outcomes from r possibilities + if(n==0 || r==0) return 1; + return (dojo.math.factorial(n) / (dojo.math.factorial(n-r) * dojo.math.factorial(r))); // float +} + +dojo.math.bernstein = function(/* float */t, /* float */n, /* float */i) { + // summary + // Calculates a weighted average based on the Bernstein theorem. + return (dojo.math.combinations(n,i) * Math.pow(t,i) * Math.pow(1-t,n-i)); // float +} + +dojo.math.gaussianRandom = function(){ + // summary + // Returns random numbers with a Gaussian distribution, with the mean set at 0 and the variance set at 1. + var k = 2; + do { + var i = 2 * Math.random() - 1; + var j = 2 * Math.random() - 1; + k = i * i + j * j; + } while (k >= 1); + k = Math.sqrt((-2 * Math.log(k)) / k); + return i * k; // float +} + +dojo.math.mean = function() { + // summary + // Calculates the mean of an Array of numbers. + var array = dojo.lang.isArray(arguments[0]) ? arguments[0] : arguments; + var mean = 0; + for (var i = 0; i < array.length; i++) { mean += array[i]; } + return mean / array.length; // float +} + +dojo.math.round = function(/* float */number, /* integer */places) { + // summary + // Extends Math.round by adding a second argument specifying the number of decimal places to round to. + // TODO: add support for significant figures + if (!places) { var shift = 1; } + else { var shift = Math.pow(10, places); } + return Math.round(number * shift) / shift; // float +} + +dojo.math.sd = dojo.math.standardDeviation = function(/* array */){ + // summary + // Calculates the standard deviation of an Array of numbers + var array = dojo.lang.isArray(arguments[0]) ? arguments[0] : arguments; + return Math.sqrt(dojo.math.variance(array)); // float +} + +dojo.math.variance = function(/* array */) { + // summary + // Calculates the variance of an Array of numbers + var array = dojo.lang.isArray(arguments[0]) ? arguments[0] : arguments; + var mean = 0, squares = 0; + for (var i = 0; i < array.length; i++) { + mean += array[i]; + squares += Math.pow(array[i], 2); + } + return (squares / array.length) - Math.pow(mean / array.length, 2); // float +} + +dojo.math.range = function(/* integer */a, /* integer */b, /* integer */step) { + // summary + // implementation of Python's range() + if(arguments.length < 2) { + b = a; + a = 0; + } + if(arguments.length < 3) { + step = 1; + } + + var range = []; + if(step > 0) { + for(var i = a; i < b; i += step) { + range.push(i); + } + } else if(step < 0) { + for(var i = a; i > b; i += step) { + range.push(i); + } + } else { + throw new Error("dojo.math.range: step must be non-zero"); + } + return range; // array +} diff --git a/source/web/scripts/ajax/dojo/src/math/__package__.js b/source/web/scripts/ajax/dojo/src/math/__package__.js new file mode 100644 index 0000000000..942aaa1cf9 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/math/__package__.js @@ -0,0 +1,18 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: [ + ["dojo.math", false, false], + ["dojo.math.curves", false, false], + ["dojo.math.points", false, false] + ] +}); +dojo.provide("dojo.math.*"); diff --git a/source/web/scripts/ajax/dojo/src/math/curves.js b/source/web/scripts/ajax/dojo/src/math/curves.js new file mode 100644 index 0000000000..26751ebf14 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/math/curves.js @@ -0,0 +1,242 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.math.curves"); +dojo.require("dojo.math"); + +/* Curves from Dan's 13th lib stuff. + * See: http://pupius.co.uk/js/Toolkit.Drawing.js + * http://pupius.co.uk/dump/dojo/Dojo.Math.js + */ + +dojo.math.curves = { + Line: function(/* array */start, /* array */end) { + // summary + // Creates a straight line object + this.start = start; + this.end = end; + this.dimensions = start.length; + + for(var i = 0; i < start.length; i++) { + start[i] = Number(start[i]); + } + + for(var i = 0; i < end.length; i++) { + end[i] = Number(end[i]); + } + + //simple function to find point on an n-dimensional, straight line + this.getValue = function(/* float */n){ + // summary + // Returns the point at point N (in terms of percentage) on this line. + var retVal = new Array(this.dimensions); + for(var i=0;i= 1) return this.p[this.p.length-1]; // if step>=1 we must be at the end of the curve + if(step <= 0) return this.p[0]; // if step<=0 we must be at the start of the curve + var retVal = new Array(this.p[0].length); + for(var k=0;j= this.p.length) i1 = this.p.length-1; + var i2 = node+2; if(i2 >= this.p.length) i2 = this.p.length-1; + + var u = progress; + var u2 = progress*progress; + var u3 = progress*progress*progress; + + var retVal = new Array(this.p[0].length); + for(var k=0;k 2D point for center of arc + // radius => scalar quantity for radius of arc + // start => to define an arc specify start angle (default: 0) + // end => to define an arc specify start angle + this.center = center; + this.radius = radius; + this.start = start || 0; + this.end = end; + + this.getValue = function(/* float */n) { + // summary + // Returns the point at point N (in terms of percentage) on this curve. + var retVal = new Array(2); + var theta = dojo.math.degToRad(this.start+((this.end-this.start)*n)); + + retVal[0] = this.center[0] + this.radius*Math.sin(theta); + retVal[1] = this.center[1] - this.radius*Math.cos(theta); + + return retVal; // array + } + + return this; // dojo.math.curves.CenteredArc + }, + + Circle : function(/* array */center, /* float */radius) { + // summary + // Special case of Arc (start = 0, end = 360) + dojo.math.curves.CenteredArc.call(this, center, radius, 0, 360); + return this; // dojo.math.curves.Circle + }, + + Path : function() { + // summary + // Generic path shape, created from curve segments + var curves = []; + var weights = []; + var ranges = []; + var totalWeight = 0; + + this.add = function(/* dojo.math.curves.* */curve, /* float */weight) { + // summary + // Add a curve segment to this path + if( weight < 0 ) { dojo.raise("dojo.math.curves.Path.add: weight cannot be less than 0"); } + curves.push(curve); + weights.push(weight); + totalWeight += weight; + computeRanges(); + } + + this.remove = function(/* dojo.math.curves.* */curve) { + // summary + // Remove a curve segment from this path + for(var i = 0; i < curves.length; i++) { + if( curves[i] == curve ) { + curves.splice(i, 1); + totalWeight -= weights.splice(i, 1)[0]; + break; + } + } + computeRanges(); + } + + this.removeAll = function() { + // summary + // Remove all curve segments + curves = []; + weights = []; + totalWeight = 0; + } + + this.getValue = function(/* float */n) { + // summary + // Returns the point at point N (in terms of percentage) on this curve. + var found = false, value = 0; + for(var i = 0; i < ranges.length; i++) { + var r = ranges[i]; + //w(r.join(" ... ")); + if( n >= r[0] && n < r[1] ) { + var subN = (n - r[0]) / r[2]; + value = curves[i].getValue(subN); + found = true; + break; + } + } + + // FIXME: Do we want to assume we're at the end? + if( !found ) { + value = curves[curves.length-1].getValue(1); + } + + for(var j = 0; j < i; j++) { + value = dojo.math.points.translate(value, curves[j].getValue(1)); + } + return value; // array + } + + function computeRanges() { + var start = 0; + for(var i = 0; i < weights.length; i++) { + var end = start + weights[i] / totalWeight; + var len = end - start; + ranges[i] = [start, end, len]; + start = end; + } + } + + return this; // dojo.math.curves.Path + } +}; diff --git a/source/web/scripts/ajax/dojo/src/math/matrix.js b/source/web/scripts/ajax/dojo/src/math/matrix.js new file mode 100644 index 0000000000..61ad99db1c --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/math/matrix.js @@ -0,0 +1,377 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.math.matrix"); + +// some of this code is based on +// http://www.mkaz.com/math/MatrixCalculator.java +// (published under a BSD Open Source License) +// +// the rest is from my vague memory of matricies in school [cal] +// +// the copying of arguments is a little excessive, and could be trimmed back in +// the case where a function doesn't modify them at all (but some do!) +// +// 2006-06-25: Some enhancements submitted by Erel Segal: +// * addition: a tolerance constant for determinant calculations. +// * performance fix: removed unnecessary argument copying. +// * addition: function "product" for multiplying more than 2 matrices +// * addition: function "sum" for adding any number of matrices +// * bug fix: inversion of a 1x1 matrix without using the adjoint +// * performance fixes: upperTriangle +// * addition: argument "value" to function create, to initialize the matrix with a custom val +// * addition: functions "ones" and "zeros" - like Matlab[TM] functions with the same name. +// * addition: function "identity" for creating an identity matrix of a given size. +// * addition: argument "decimal_points" to function format +// * bug fix: adjoint of a 0-size matrix +// * performance fixes: adjoint +// + +dojo.math.matrix.iDF = 0; + +// Erel: values lower than this value are considered zero (in detereminant calculations). +// It is analogous to Maltab[TM]'s "eps". +dojo.math.matrix.ALMOST_ZERO = 1e-10; +dojo.math.matrix.multiply = function(a, b){ + var ay = a.length; + var ax = a[0].length; + var by = b.length; + var bx = b[0].length; + + if (ax != by){ + dojo.debug("Can't multiply matricies of sizes "+ax+','+ay+' and '+bx+','+by); + return [[0]]; + } + + var c = []; + for(var k=0; k0? a[0].length: 0; + var buffer = ''; + for (var y=0; y by convention + if(!dojo.hostenv.moduleHasPrefix(name)){ + dojo.registerModulePath(name, "../" + name); + } + req([name, 'manifest'].join('.'), false, true); + } + if(!this.namespaces[name]){ + this.failed[name] = true; //only look for a namespace once + } + }finally{ + this.loading[name]=false; + } + return this.namespaces[name]; // Ns + } +} + +dojo.ns.Ns = function(/*String*/name, /*String*/module, /*Function?*/resolver){ + // summary: this object simply encapsulates namespace data + this.name = name; + this.module = module; + this.resolver = resolver; + this._loaded = [ ]; + this._failed = [ ]; +} + +dojo.ns.Ns.prototype.resolve = function(/*String*/name, /*String*/domain, /*Boolean?*/omitModuleCheck){ + //summary: map component with 'name' and 'domain' to a module via namespace resolver, if specified + if(!this.resolver || djConfig["skipAutoRequire"]){return false;} // Boolean + 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])&&(!this._failed[fullName])){ + //workaround so we don't break the build system + var req = dojo.require; + req(fullName, false, true); //omit the module check, we'll do it ourselves. + if(dojo.hostenv.findModule(fullName, false)){ + this._loaded[fullName] = true; + }else{ + if(!omitModuleCheck){dojo.raise("dojo.ns.Ns.resolve: module '" + fullName + "' not found after loading via namespace '" + this.name + "'");} + this._failed[fullName] = true; + } + } + return Boolean(this._loaded[fullName]); // Boolean +} + +dojo.registerNamespace = function(/*String*/name, /*String*/module, /*Function?*/resolver){ + // summary: maps a module name to a namespace for widgets, and optionally maps widget names to modules for auto-loading + // description: An unregistered namespace is mapped to an eponymous module. + // For example, namespace acme is mapped to module acme, and widgets are + // assumed to belong to acme.widget. If you want to use a different widget + // module, use dojo.registerNamespace. + dojo.ns.register.apply(dojo.ns, arguments); +} + +dojo.registerNamespaceResolver = function(/*String*/name, /*Function*/resolver){ + // summary: a resolver function maps widget names to modules, so the + // widget manager can auto-load needed widget implementations + // + // description: The resolver provides information to allow Dojo + // to load widget modules on demand. When a widget is created, + // a namespace resolver can tell Dojo what module to require + // to ensure that the widget implementation code is loaded. + // + // name: will always be lower-case. + // + // example: + // dojo.registerNamespaceResolver("acme", + // function(name){ + // return "acme.widget."+dojo.string.capitalize(name); + // } + // ); + var n = dojo.ns.namespaces[name]; + if(n){ + n.resolver = resolver; + } +} + +dojo.registerNamespaceManifest = function(/*String*/module, /*String*/path, /*String*/name, /*String*/widgetModule, /*Function?*/resolver){ + // summary: convenience function to register a module path, a namespace, and optionally a resolver all at once. + dojo.registerModulePath(name, path); + dojo.registerNamespace(name, widgetModule, resolver); +} + +// NOTE: rather put this in dojo.widget.Widget, but that fubars debugAtAllCosts +dojo.registerNamespace("dojo", "dojo.widget"); diff --git a/source/web/scripts/ajax/dojo/src/profile.js b/source/web/scripts/ajax/dojo/src/profile.js new file mode 100644 index 0000000000..6f1dd8be65 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/profile.js @@ -0,0 +1,146 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.profile"); + +// summary: +// provides a manual profiling utility that can be used to gather relative +// timing data. + + +// FIXME: need to tie into the event system or provide a closure-based way to +// watch timings of functions without manually instrumenting them. +// FIXME: need to make the dump() function work in command line environments + +dojo.profile = { + _profiles: {}, + _pns: [], + + start:function(/*String*/ name){ + // summary: + // start an iteration for the profiling target with the specified + // name. If a previously started iteration has not yet been ended + // for this name, it's automatically closed out and a new + // iteration begun. + // name: + // a unique name to identify the thing being profiled + if(!this._profiles[name]){ + this._profiles[name] = {iters: 0, total: 0}; + this._pns[this._pns.length] = name; + }else{ + if(this._profiles[name]["start"]){ + this.end(name); + } + } + this._profiles[name].end = null; + this._profiles[name].start = new Date(); + }, + + end:function(/*String*/ name){ + // summary: + // closes a timing loop for the named profiling target + // name: + // a unique name to identify the thing being profiled. The name + // passed to end() should be the same as that passed to start() + var ed = new Date(); + if((this._profiles[name])&&(this._profiles[name]["start"])){ + with(this._profiles[name]){ + end = ed; + total += (end - start); + start = null; + iters++; + } + }else{ + // oops! bad call to end(), what should we do here? + return true; + } + }, + + dump:function(/*boolean*/ appendToDoc){ + // summary: + // output profiling data to an HTML table, optionally adding it to + // the bottom of the document. If profiling data has already been + // generated and appended to the document, it's replaced with the + // new data. + // appendToDoc: + // optional. Defautls to "false". Should profiling information be + // added to the document? + var tbl = document.createElement("table"); + with(tbl.style){ + border = "1px solid black"; + borderCollapse = "collapse"; + } + var hdr = tbl.createTHead(); + var hdrtr = hdr.insertRow(0); + // document.createElement("tr"); + var cols = ["Identifier","Calls","Total","Avg"]; + for(var x=0; x0){ + var bdytr = tbl.insertRow(true); + var vals = [this._pns[x], prf.iters, prf.total, parseInt(prf.total/prf.iters)]; + for(var y=0; y0){ + textAlign = "right"; + borderRight = "1px solid gray"; + }else{ + borderRight = "1px solid black"; + } + } + } + } + } + + if(appendToDoc){ + var ne = document.createElement("div"); + ne.id = "profileOutputTable"; + with(ne.style){ + fontFamily = "Courier New, monospace"; + fontSize = "12px"; + lineHeight = "16px"; + borderTop = "1px solid black"; + padding = "10px"; + } + if(document.getElementById("profileOutputTable")){ + dojo.body().replaceChild(ne, document.getElementById("profileOutputTable")); + }else{ + dojo.body().appendChild(ne); + } + ne.appendChild(tbl); + } + + return tbl; // DOMNode + } +} + +dojo.profile.stop = dojo.profile.end; diff --git a/source/web/scripts/ajax/dojo/src/regexp.js b/source/web/scripts/ajax/dojo/src/regexp.js new file mode 100644 index 0000000000..c089a1e507 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/regexp.js @@ -0,0 +1,577 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.regexp"); +dojo.evalObjPath("dojo.regexp.us", true); // this file also defines stuff in the dojo.regexp.us module (TODO: move to separate file?) + +// *** Regular Expression Generators *** + +dojo.regexp.tld = function(/*Object?*/flags){ + // summary: Builds a RE that matches a top-level domain + // + // flags: + // flags.allowCC Include 2 letter country code domains. Default is true. + // flags.allowGeneric Include the generic domains. Default is true. + // flags.allowInfra Include infrastructure domains. Default is true. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.allowCC != "boolean"){ flags.allowCC = true; } + if(typeof flags.allowInfra != "boolean"){ flags.allowInfra = true; } + if(typeof flags.allowGeneric != "boolean"){ flags.allowGeneric = true; } + + // Infrastructure top-level domain - only one at present + var infraRE = "arpa"; + + // Generic top-level domains RE. + var genericRE = + "aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|xxx|jobs|mobi|post"; + + // Country Code top-level domains RE + var ccRE = + "ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|" + + "bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|" + + "ec|ee|eg|er|eu|es|et|fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|" + + + "gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kr|kw|ky|kz|" + + "la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|" + + "my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|" + + "re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sk|sl|sm|sn|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|" + + "tn|to|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw"; + + // Build top-level domain RE + var a = []; + if(flags.allowInfra){ a.push(infraRE); } + if(flags.allowGeneric){ a.push(genericRE); } + if(flags.allowCC){ a.push(ccRE); } + + var tldRE = ""; + if (a.length > 0) { + tldRE = "(" + a.join("|") + ")"; + } + + return tldRE; // String +} + +dojo.regexp.ipAddress = function(/*Object?*/flags){ + // summary: Builds a RE that matches an IP Address + // + // description: + // Supports 5 formats for IPv4: dotted decimal, dotted hex, dotted octal, decimal and hexadecimal. + // Supports 2 formats for Ipv6. + // + // flags An object. All flags are boolean with default = true. + // flags.allowDottedDecimal Example, 207.142.131.235. No zero padding. + // flags.allowDottedHex Example, 0x18.0x11.0x9b.0x28. Case insensitive. Zero padding allowed. + // flags.allowDottedOctal Example, 0030.0021.0233.0050. Zero padding allowed. + // flags.allowDecimal Example, 3482223595. A decimal number between 0-4294967295. + // flags.allowHex Example, 0xCF8E83EB. Hexadecimal number between 0x0-0xFFFFFFFF. + // Case insensitive. Zero padding allowed. + // flags.allowIPv6 IPv6 address written as eight groups of four hexadecimal digits. + // flags.allowHybrid IPv6 address written as six groups of four hexadecimal digits + // followed by the usual 4 dotted decimal digit notation of IPv4. x:x:x:x:x:x:d.d.d.d + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.allowDottedDecimal != "boolean"){ flags.allowDottedDecimal = true; } + if(typeof flags.allowDottedHex != "boolean"){ flags.allowDottedHex = true; } + if(typeof flags.allowDottedOctal != "boolean"){ flags.allowDottedOctal = true; } + if(typeof flags.allowDecimal != "boolean"){ flags.allowDecimal = true; } + if(typeof flags.allowHex != "boolean"){ flags.allowHex = true; } + if(typeof flags.allowIPv6 != "boolean"){ flags.allowIPv6 = true; } + if(typeof flags.allowHybrid != "boolean"){ flags.allowHybrid = true; } + + // decimal-dotted IP address RE. + var dottedDecimalRE = + // Each number is between 0-255. Zero padding is not allowed. + "((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])"; + + // dotted hex IP address RE. Each number is between 0x0-0xff. Zero padding is allowed, e.g. 0x00. + var dottedHexRE = "(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]"; + + // dotted octal IP address RE. Each number is between 0000-0377. + // Zero padding is allowed, but each number must have at least 4 characters. + var dottedOctalRE = "(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]"; + + // decimal IP address RE. A decimal number between 0-4294967295. + var decimalRE = "(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|" + + "4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])"; + + // hexadecimal IP address RE. + // A hexadecimal number between 0x0-0xFFFFFFFF. Case insensitive. Zero padding is allowed. + var hexRE = "0[xX]0*[\\da-fA-F]{1,8}"; + + // IPv6 address RE. + // The format is written as eight groups of four hexadecimal digits, x:x:x:x:x:x:x:x, + // where x is between 0000-ffff. Zero padding is optional. Case insensitive. + var ipv6RE = "([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}"; + + // IPv6/IPv4 Hybrid address RE. + // The format is written as six groups of four hexadecimal digits, + // followed by the 4 dotted decimal IPv4 format. x:x:x:x:x:x:d.d.d.d + var hybridRE = "([\\da-fA-F]{1,4}\\:){6}" + + "((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])"; + + // Build IP Address RE + var a = []; + if(flags.allowDottedDecimal){ a.push(dottedDecimalRE); } + if(flags.allowDottedHex){ a.push(dottedHexRE); } + if(flags.allowDottedOctal){ a.push(dottedOctalRE); } + if(flags.allowDecimal){ a.push(decimalRE); } + if(flags.allowHex){ a.push(hexRE); } + if(flags.allowIPv6){ a.push(ipv6RE); } + if(flags.allowHybrid){ a.push(hybridRE); } + + var ipAddressRE = ""; + if(a.length > 0){ + ipAddressRE = "(" + a.join("|") + ")"; + } + + return ipAddressRE; // String +} + +dojo.regexp.host = function(/*Object?*/flags){ + // summary: Builds a RE that matches a host + // description: A host is a domain name or an IP address, possibly followed by a port number. + // flags: An object. + // flags.allowIP Allow an IP address for hostname. Default is true. + // flags.allowLocal Allow the host to be "localhost". Default is false. + // flags.allowPort Allow a port number to be present. Default is true. + // flags in regexp.ipAddress can be applied. + // flags in regexp.tld can be applied. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.allowIP != "boolean"){ flags.allowIP = true; } + if(typeof flags.allowLocal != "boolean"){ flags.allowLocal = false; } + if(typeof flags.allowPort != "boolean"){ flags.allowPort = true; } + + // Domain names can not end with a dash. + var domainNameRE = "([0-9a-zA-Z]([-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?\\.)+" + dojo.regexp.tld(flags); + + // port number RE + var portRE = ( flags.allowPort ) ? "(\\:" + dojo.regexp.integer({signed: false}) + ")?" : ""; + + // build host RE + var hostNameRE = domainNameRE; + if(flags.allowIP){ hostNameRE += "|" + dojo.regexp.ipAddress(flags); } + if(flags.allowLocal){ hostNameRE += "|localhost"; } + + return "(" + hostNameRE + ")" + portRE; // String +} + +dojo.regexp.url = function(/*Object?*/flags){ + // summary: Builds a regular expression that matches a URL + // + // flags: An object + // flags.scheme Can be true, false, or [true, false]. + // This means: required, not allowed, or match either one. + // flags in regexp.host can be applied. + // flags in regexp.ipAddress can be applied. + // flags in regexp.tld can be applied. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.scheme == "undefined"){ flags.scheme = [true, false]; } + + // Scheme RE + var protocolRE = dojo.regexp.buildGroupRE(flags.scheme, + function(q){ if(q){ return "(https?|ftps?)\\://"; } return ""; } + ); + + // Path and query and anchor RE + var pathRE = "(/([^?#\\s/]+/)*)?([^?#\\s/]+(\\?[^?#\\s/]*)?(#[A-Za-z][\\w.:-]*)?)?"; + + return protocolRE + dojo.regexp.host(flags) + pathRE; +} + + +dojo.regexp.emailAddress = function(/*Object?*/flags){ + // summary: Builds a regular expression that matches an email address + // + //flags: An object + // flags.allowCruft Allow address like . Default is false. + // flags in regexp.host can be applied. + // flags in regexp.ipAddress can be applied. + // flags in regexp.tld can be applied. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if (typeof flags.allowCruft != "boolean") { flags.allowCruft = false; } + flags.allowPort = false; // invalid in email addresses + + // user name RE - apostrophes are valid if there's not 2 in a row + var usernameRE = "([\\da-z]+[-._+&'])*[\\da-z]+"; + + // build emailAddress RE + var emailAddressRE = usernameRE + "@" + dojo.regexp.host(flags); + + // Allow email addresses with cruft + if ( flags.allowCruft ) { + emailAddressRE = "?"; + } + + return emailAddressRE; // String +} + +dojo.regexp.emailAddressList = function(/*Object?*/flags){ + // summary: Builds a regular expression that matches a list of email addresses. + // + // flags: An object. + // flags.listSeparator The character used to separate email addresses. Default is ";", ",", "\n" or " ". + // flags in regexp.emailAddress can be applied. + // flags in regexp.host can be applied. + // flags in regexp.ipAddress can be applied. + // flags in regexp.tld can be applied. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.listSeparator != "string"){ flags.listSeparator = "\\s;,"; } + + // build a RE for an Email Address List + var emailAddressRE = dojo.regexp.emailAddress(flags); + var emailAddressListRE = "(" + emailAddressRE + "\\s*[" + flags.listSeparator + "]\\s*)*" + + emailAddressRE + "\\s*[" + flags.listSeparator + "]?\\s*"; + + return emailAddressListRE; // String +} + +dojo.regexp.integer = function(/*Object?*/flags){ + // summary: Builds a regular expression that matches an integer + // + // flags: An object + // flags.signed The leading plus-or-minus sign. Can be true, false, or [true, false]. + // Default is [true, false], (i.e. will match if it is signed or unsigned). + // flags.separator The character used as the thousands separator. Default is no separator. + // For more than one symbol use an array, e.g. [",", ""], makes ',' optional. + // flags.groupSize group size between separators + // flags.groupSize2 second grouping (for India) + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.signed == "undefined"){ flags.signed = [true, false]; } + if(typeof flags.separator == "undefined"){ + flags.separator = ""; + } else if(typeof flags.groupSize == "undefined"){ + flags.groupSize = 3; + } + // build sign RE + var signRE = dojo.regexp.buildGroupRE(flags.signed, + function(q) { return q ? "[-+]" : ""; } + ); + + // number RE + var numberRE = dojo.regexp.buildGroupRE(flags.separator, + function(sep){ + if(sep == ""){ + return "(0|[1-9]\\d*)"; + } + var grp = flags.groupSize, grp2 = flags.groupSize2; + if(typeof grp2 != "undefined"){ + var grp2RE = "(0|[1-9]\\d{0," + (grp2-1) + "}([" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})"; + return ((grp-grp2) > 0) ? "(" + grp2RE + "|(0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE; + } + return "(0|[1-9]\\d{0," + (grp-1) + "}([" + sep + "]\\d{" + grp + "})*)"; + } + ); + + // integer RE + return signRE + numberRE; // String +} + +dojo.regexp.realNumber = function(/*Object?*/flags){ + // summary: Builds a regular expression to match a real number in exponential notation + // + // flags:An object + // flags.places The integer number of decimal places. + // If not given, the decimal part is optional and the number of places is unlimited. + // flags.decimal A string for the character used as the decimal point. Default is ".". + // flags.fractional Whether decimal places are allowed. + // Can be true, false, or [true, false]. Default is [true, false] + // flags.exponent Express in exponential notation. Can be true, false, or [true, false]. + // Default is [true, false], (i.e. will match if the exponential part is present are not). + // flags.eSigned The leading plus-or-minus sign on the exponent. Can be true, false, + // or [true, false]. Default is [true, false], (i.e. will match if it is signed or unsigned). + // flags in regexp.integer can be applied. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.places != "number"){ flags.places = Infinity; } + if(typeof flags.decimal != "string"){ flags.decimal = "."; } + if(typeof flags.fractional == "undefined"){ flags.fractional = [true, false]; } + if(typeof flags.exponent == "undefined"){ flags.exponent = [true, false]; } + if(typeof flags.eSigned == "undefined"){ flags.eSigned = [true, false]; } + + // integer RE + var integerRE = dojo.regexp.integer(flags); + + // decimal RE + var decimalRE = dojo.regexp.buildGroupRE(flags.fractional, + function(q){ + var re = ""; + if(q && (flags.places > 0)){ + re = "\\" + flags.decimal; + if(flags.places == Infinity){ + re = "(" + re + "\\d+)?"; + }else{ + re = re + "\\d{" + flags.places + "}"; + } + } + + return re; + } + ); + + // exponent RE + var exponentRE = dojo.regexp.buildGroupRE(flags.exponent, + function(q){ + if(q){ return "([eE]" + dojo.regexp.integer({ signed: flags.eSigned}) + ")"; } + return ""; + } + ); + + // real number RE + return integerRE + decimalRE + exponentRE; // String +} + +dojo.regexp.currency = function(/*Object?*/flags){ + // summary: Builds a regular expression to match a monetary value + // + // flags: An object + // flags.symbol A currency symbol such as Yen "�", Pound "�", or the Euro sign "�". + // Default is "$". For more than one symbol use an array, e.g. ["$", ""], makes $ optional. + // flags.placement The symbol can come "before" the number or "after" the number. Default is "before". + // flags.signPlacement The sign can come "before" the number or "after" the sign, + // "around" to put parentheses around negative values, or "end" for the final char. Default is "before". + // flags.cents deprecated, in favor of flags.fractional + // flags in regexp.realNumber can be applied except exponent, eSigned. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.signed == "undefined"){ flags.signed = [true, false]; } + if(typeof flags.symbol == "undefined"){ flags.symbol = "$"; } + if(typeof flags.placement != "string"){ flags.placement = "before"; } + if(typeof flags.signPlacement != "string"){ flags.signPlacement = "before"; } + if(typeof flags.separator == "undefined"){ flags.separator = ","; } + if(typeof flags.fractional == "undefined" && typeof flags.cents != "undefined"){ + dojo.deprecated("dojo.regexp.currency: flags.cents", "use flags.fractional instead", "0.5"); + flags.fractional = flags.cents; + } + if(typeof flags.decimal != "string"){ flags.decimal = "."; } + + // build sign RE + var signRE = dojo.regexp.buildGroupRE(flags.signed, + function(q){ if (q){ return "[-+]"; } return ""; } + ); + + // build symbol RE + var symbolRE = dojo.regexp.buildGroupRE(flags.symbol, + function(symbol){ + // escape all special characters + return "\\s?" + symbol.replace( /([.$?*!=:|\\\/^])/g, "\\$1") + "\\s?"; + } + ); + + switch (flags.signPlacement){ + case "before": + symbolRE = signRE + symbolRE; + break; + case "after": + symbolRE = symbolRE + signRE; + break; + } + + // number RE + var flagsCopy = flags; //TODO: copy by value? + flagsCopy.signed = false; flagsCopy.exponent = false; + var numberRE = dojo.regexp.realNumber(flagsCopy); + + // build currency RE + var currencyRE; + switch (flags.placement){ + case "before": + currencyRE = symbolRE + numberRE; + break; + case "after": + currencyRE = numberRE + symbolRE; + break; + } + + switch (flags.signPlacement){ + case "around": + currencyRE = "(" + currencyRE + "|" + "\\(" + currencyRE + "\\)" + ")"; + break; + case "begin": + currencyRE = signRE + currencyRE; + break; + case "end": + currencyRE = currencyRE + signRE; + break; + } + return currencyRE; // String +} + + +dojo.regexp.us.state = function(/*Object?*/flags){ + // summary: A regular expression to match US state and territory abbreviations + // + // flags An object. + // flags.allowTerritories Allow Guam, Puerto Rico, etc. Default is true. + // flags.allowMilitary Allow military 'states', e.g. Armed Forces Europe (AE). Default is true. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.allowTerritories != "boolean"){ flags.allowTerritories = true; } + if(typeof flags.allowMilitary != "boolean"){ flags.allowMilitary = true; } + + // state RE + var statesRE = + "AL|AK|AZ|AR|CA|CO|CT|DE|DC|FL|GA|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|" + + "NE|NV|NH|NJ|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY"; + + // territories RE + var territoriesRE = "AS|FM|GU|MH|MP|PW|PR|VI"; + + // military states RE + var militaryRE = "AA|AE|AP"; + + // Build states and territories RE + if(flags.allowTerritories){ statesRE += "|" + territoriesRE; } + if(flags.allowMilitary){ statesRE += "|" + militaryRE; } + + return "(" + statesRE + ")"; // String +} + +dojo.regexp.time = function(/*Object?*/flags){ + // summary: Builds a regular expression to match any International format for time + // description: The RE can match one format or one of multiple formats. + // + // Format + // h 12 hour, no zero padding. + // hh 12 hour, has leading zero. + // H 24 hour, no zero padding. + // HH 24 hour, has leading zero. + // m minutes, no zero padding. + // mm minutes, has leading zero. + // s seconds, no zero padding. + // ss seconds, has leading zero. + // t am or pm, case insensitive. + // All other characters must appear literally in the expression. + // + // Example + // "h:m:s t" -> 2:5:33 PM + // "HH:mm:ss" -> 14:05:33 + // + // flags: An object + // flags.format A string or an array of strings. Default is "h:mm:ss t". + // flags.amSymbol The symbol used for AM. Default is "AM". + // flags.pmSymbol The symbol used for PM. Default is "PM". + + dojo.deprecated("dojo.regexp.time", "Use dojo.date.parse instead", "0.5"); + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.format == "undefined"){ flags.format = "h:mm:ss t"; } + if(typeof flags.amSymbol != "string"){ flags.amSymbol = "AM"; } + if(typeof flags.pmSymbol != "string"){ flags.pmSymbol = "PM"; } + + // Converts a time format to a RE + var timeRE = function(format){ + // escape all special characters + format = format.replace( /([.$?*!=:|{}\(\)\[\]\\\/^])/g, "\\$1"); + var amRE = flags.amSymbol.replace( /([.$?*!=:|{}\(\)\[\]\\\/^])/g, "\\$1"); + var pmRE = flags.pmSymbol.replace( /([.$?*!=:|{}\(\)\[\]\\\/^])/g, "\\$1"); + + // replace tokens with Regular Expressions + format = format.replace("hh", "(0[1-9]|1[0-2])"); + format = format.replace("h", "([1-9]|1[0-2])"); + format = format.replace("HH", "([01][0-9]|2[0-3])"); + format = format.replace("H", "([0-9]|1[0-9]|2[0-3])"); + format = format.replace("mm", "([0-5][0-9])"); + format = format.replace("m", "([1-5][0-9]|[0-9])"); + format = format.replace("ss", "([0-5][0-9])"); + format = format.replace("s", "([1-5][0-9]|[0-9])"); + format = format.replace("t", "\\s?(" + amRE + "|" + pmRE + ")\\s?" ); + + return format; // String + }; + + // build RE for multiple time formats + return dojo.regexp.buildGroupRE(flags.format, timeRE); // String +} + +dojo.regexp.numberFormat = function(/*Object?*/flags){ + // summary: Builds a regular expression to match any sort of number based format + // description: + // Use this method for phone numbers, social security numbers, zip-codes, etc. + // The RE can match one format or one of multiple formats. + // + // Format + // # Stands for a digit, 0-9. + // ? Stands for an optional digit, 0-9 or nothing. + // All other characters must appear literally in the expression. + // + // Example + // "(###) ###-####" -> (510) 542-9742 + // "(###) ###-#### x#???" -> (510) 542-9742 x153 + // "###-##-####" -> 506-82-1089 i.e. social security number + // "#####-####" -> 98225-1649 i.e. zip code + // + // flags: An object + // flags.format A string or an Array of strings for multiple formats. + + // assign default values to missing paramters + flags = (typeof flags == "object") ? flags : {}; + if(typeof flags.format == "undefined"){ flags.format = "###-###-####"; } + + // Converts a number format to RE. + var digitRE = function(format){ + // escape all special characters, except '?' + format = format.replace( /([.$*!=:|{}\(\)\[\]\\\/^])/g, "\\$1"); + + // Now replace '?' with Regular Expression + format = format.replace(/\?/g, "\\d?"); + + // replace # with Regular Expression + format = format.replace(/#/g, "\\d"); + + return format; // String + }; + + // build RE for multiple number formats + return dojo.regexp.buildGroupRE(flags.format, digitRE); //String +} + + +dojo.regexp.buildGroupRE = function(/*value or Array of values*/a, /*Function(x) returns a regular expression as a String*/re){ + // summary: Builds a regular expression that groups subexpressions + // description: A utility function used by some of the RE generators. + // The subexpressions are constructed by the function, re, in the second parameter. + // re builds one subexpression for each elem in the array a, in the first parameter. + // Returns a string for a regular expression that groups all the subexpressions. + // + // a: A single value or an array of values. + // re: A function. Takes one parameter and converts it to a regular expression. + + // case 1: a is a single value. + if(!(a instanceof Array)){ + return re(a); // String + } + + // case 2: a is an array + var b = []; + for (var i = 0; i < a.length; i++){ + // convert each elem to a RE + b.push(re(a[i])); + } + + // join the REs as alternatives in a RE group. + return "(" + b.join("|") + ")"; // String +} diff --git a/source/web/scripts/ajax/dojo/src/rpc/Deferred.js b/source/web/scripts/ajax/dojo/src/rpc/Deferred.js new file mode 100644 index 0000000000..1e49dc90a2 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/rpc/Deferred.js @@ -0,0 +1,16 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.rpc.Deferred"); +dojo.require("dojo.Deferred"); + +dojo.deprecated("dojo.rpc.Deferred", "replaced by dojo.Deferred", "0.6"); +dojo.rpc.Deferred = dojo.Deferred; +dojo.rpc.Deferred.prototype = dojo.Deferred.prototype; diff --git a/source/web/scripts/ajax/dojo/src/rpc/JotService.js b/source/web/scripts/ajax/dojo/src/rpc/JotService.js new file mode 100644 index 0000000000..2d63e0d30e --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/rpc/JotService.js @@ -0,0 +1,43 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.rpc.JotService"); +dojo.require("dojo.rpc.RpcService"); dojo.require("dojo.rpc.JsonService"); dojo.require("dojo.json"); dojo.rpc.JotService = function(){ + this.serviceUrl = "/_/jsonrpc"; +} + +dojo.inherits(dojo.rpc.JotService, dojo.rpc.JsonService); + +dojo.lang.extend(dojo.rpc.JotService, { + bind: function(method, parameters, deferredRequestHandler, url){ + //summary + //Jot bind method. Takes remote method, parameters, deferred, + //and a url, calls createRequest to make a Jot RPC envelope and + //passes that off with bind. + dojo.io.bind({ + url: url||this.serviceUrl, + content: { + json: this.createRequest(method, parameters) + }, + method: "POST", + mimetype: "text/json", + load: this.resultCallback(deferredRequestHandler), + error: this.errorCallback(deferredRequestHandler), + preventCache: true + }); + }, + + createRequest: function(method, params){ + //summary + //create the json portion of the Jot request + var req = { "params": params, "method": method, "id": this.lastSubmissionId++ }; + return dojo.json.serialize(req); + } +}); diff --git a/source/web/scripts/ajax/dojo/src/rpc/JsonService.js b/source/web/scripts/ajax/dojo/src/rpc/JsonService.js new file mode 100644 index 0000000000..31ae727f90 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/rpc/JsonService.js @@ -0,0 +1,119 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.rpc.JsonService"); +dojo.require("dojo.rpc.RpcService"); +dojo.require("dojo.io.*"); +dojo.require("dojo.json"); +dojo.require("dojo.lang.common"); + +dojo.rpc.JsonService = function(args){ + // passing just the URL isn't terribly useful. It's expected that at + // various times folks will want to specify: + // - just the serviceUrl (for use w/ remoteCall()) + // - the text of the SMD to evaluate + // - a raw SMD object + // - the SMD URL + if(args){ + if(dojo.lang.isString(args)){ + // we assume it's an SMD file to be processed, since this was the + // earlier function signature + + // FIXME: also accept dojo.uri.Uri objects? + this.connect(args); + }else{ + // otherwise we assume it's an arguments object with the following + // (optional) properties: + // - serviceUrl + // - strictArgChecks + // - smdUrl + // - smdStr + // - smdObj + if(args["smdUrl"]){ + this.connect(args.smdUrl); + } + if(args["smdStr"]){ + this.processSmd(dj_eval("("+args.smdStr+")")); + } + if(args["smdObj"]){ + this.processSmd(args.smdObj); + } + if(args["serviceUrl"]){ + this.serviceUrl = args.serviceUrl; + } + if(typeof args["strictArgChecks"] != "undefined"){ + this.strictArgChecks = args.strictArgChecks; + } + } + } +} + +dojo.inherits(dojo.rpc.JsonService, dojo.rpc.RpcService); + +dojo.extend(dojo.rpc.JsonService, { + + bustCache: false, + + contentType: "application/json-rpc", + + lastSubmissionId: 0, + + callRemote: function(method, params){ + //summary + // call an arbitrary remote method without requiring it + // to be predefined with SMD + var deferred = new dojo.Deferred(); + this.bind(method, params, deferred); + return deferred; + }, + + bind: function(method, parameters, deferredRequestHandler, url){ + //summary + //JSON-RPC bind method. Takes remote method, parameters, deferred, + //and a url, calls createRequest to make a JSON-RPC envelope and + //passes that off with bind. + + dojo.io.bind({ + url: url||this.serviceUrl, + postContent: this.createRequest(method, parameters), + method: "POST", + contentType: this.contentType, + mimetype: "text/json", + load: this.resultCallback(deferredRequestHandler), + error: this.errorCallback(deferredRequestHandler), + preventCache:this.bustCache + }); + }, + + createRequest: function(method, params){ + //summary + //create a JSON-RPC envelope for the request + var req = { "params": params, "method": method, "id": ++this.lastSubmissionId }; + var data = dojo.json.serialize(req); + dojo.debug("JsonService: JSON-RPC Request: " + data); + return data; + }, + + parseResults: function(obj){ + //summary + //parse the result envelope and pass the results back to + // to the callback function + if(!obj){ return; } + if (obj["Result"]!=null){ + return obj["Result"]; + }else if(obj["result"]!=null){ + return obj["result"]; + }else if(obj["ResultSet"]){ + return obj["ResultSet"]; + }else{ + return obj; + } + } +}); diff --git a/source/web/scripts/ajax/dojo/src/rpc/RpcService.js b/source/web/scripts/ajax/dojo/src/rpc/RpcService.js new file mode 100644 index 0000000000..1968dad13d --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/rpc/RpcService.js @@ -0,0 +1,122 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.rpc.RpcService"); +dojo.require("dojo.io.*"); +dojo.require("dojo.json"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.Deferred"); + +dojo.rpc.RpcService = function(url){ + // summary + // constructor for rpc base class + if(url){ + this.connect(url); + } +} + +dojo.lang.extend(dojo.rpc.RpcService, { + + strictArgChecks: true, + serviceUrl: "", + + parseResults: function(obj){ + // summary + // parse the results coming back from an rpc request. + // this base implementation, just returns the full object + // subclasses should parse and only return the actual results + return obj; + }, + + errorCallback: function(/* dojo.Deferred */ deferredRequestHandler){ + // summary + // create callback that calls the Deferres errback method + return function(type, e){ + deferredRequestHandler.errback(new Error(e.message)); + } + }, + + resultCallback: function(/* dojo.Deferred */ deferredRequestHandler){ + // summary + // create callback that calls the Deferred's callback method + var tf = dojo.lang.hitch(this, + function(type, obj, e){ + if (obj["error"]!=null) { + var err = new Error(obj.error); + err.id = obj.id; + deferredRequestHandler.errback(err); + } else { + var results = this.parseResults(obj); + deferredRequestHandler.callback(results); + } + } + ); + return tf; + }, + + + generateMethod: function(/*string*/ method, /*array*/ parameters, /*string*/ url){ + // summary + // generate the local bind methods for the remote object + return dojo.lang.hitch(this, function(){ + var deferredRequestHandler = new dojo.Deferred(); + + // if params weren't specified, then we can assume it's varargs + if( (this.strictArgChecks) && + (parameters != null) && + (arguments.length != parameters.length) + ){ + // put error stuff here, no enough params + dojo.raise("Invalid number of parameters for remote method."); + } else { + this.bind(method, arguments, deferredRequestHandler, url); + } + + return deferredRequestHandler; + }); + }, + + processSmd: function(/*json*/ object){ + // summary + // callback method for reciept of a smd object. Parse the smd and + // generate functions based on the description + dojo.debug("RpcService: Processing returned SMD."); + if(object.methods){ + dojo.lang.forEach(object.methods, function(m){ + if(m && m["name"]){ + dojo.debug("RpcService: Creating Method: this.", m.name, "()"); + this[m.name] = this.generateMethod( m.name, + m.parameters, + m["url"]||m["serviceUrl"]||m["serviceURL"]); + if(dojo.lang.isFunction(this[m.name])){ + dojo.debug("RpcService: Successfully created", m.name, "()"); + }else{ + dojo.debug("RpcService: Failed to create", m.name, "()"); + } + } + }, this); + } + + this.serviceUrl = object.serviceUrl||object.serviceURL; + dojo.debug("RpcService: Dojo RpcService is ready for use."); + }, + + connect: function(/*String*/ smdUrl){ + // summary + // connect to a remote url and retrieve a smd object + dojo.debug("RpcService: Attempting to load SMD document from:", smdUrl); + dojo.io.bind({ + url: smdUrl, + mimetype: "text/json", + load: dojo.lang.hitch(this, function(type, object, e){ return this.processSmd(object); }), + sync: true + }); + } +}); diff --git a/source/web/scripts/ajax/dojo/src/rpc/YahooService.js b/source/web/scripts/ajax/dojo/src/rpc/YahooService.js new file mode 100644 index 0000000000..e695611796 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/rpc/YahooService.js @@ -0,0 +1,59 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.rpc.YahooService"); +dojo.require("dojo.rpc.RpcService"); +dojo.require("dojo.rpc.JsonService"); +dojo.require("dojo.json"); +dojo.require("dojo.uri.*"); +dojo.require("dojo.io.ScriptSrcIO"); + +dojo.rpc.YahooService = function(appId){ + this.appId = appId; + if(!appId){ + this.appId = "dojotoolkit"; + dojo.debug( "please initialize the YahooService class with your own", + "application ID. Using the default may cause problems during", + "deployment of your application"); + } + this.connect(dojo.uri.dojoUri("src/rpc/yahoo.smd")); + this.strictArgChecks = false; +} + +dojo.inherits(dojo.rpc.YahooService, dojo.rpc.JsonService); + +dojo.lang.extend(dojo.rpc.YahooService, { + strictArgChecks: false, + + bind: function(method, parameters, deferredRequestHandler, url){ + //summary + //Yahoo RPC bind method. Takes remote method, parameters, deferred, + //and a url and sends of a ScriptSrcIO request to connect to Yahoo + //services crossplatform + var params = parameters; + if( (dojo.lang.isArrayLike(parameters))&& + (parameters.length == 1)){ + params = parameters[0]; + } + params.output = "json"; + params.appid= this.appId; + dojo.io.bind({ + url: url||this.serviceUrl, + transport: "ScriptSrcTransport", + // FIXME: need to get content interpolation fixed + content: params, + jsonParamName: "callback", + mimetype: "text/json", + load: this.resultCallback(deferredRequestHandler), + error: this.errorCallback(deferredRequestHandler), + preventCache: true + }); + } +}); diff --git a/source/web/scripts/ajax/dojo/src/rpc/__package__.js b/source/web/scripts/ajax/dojo/src/rpc/__package__.js new file mode 100644 index 0000000000..7fb4f9c9d9 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/rpc/__package__.js @@ -0,0 +1,14 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: [["dojo.rpc.JsonService", false, false]] +}); +dojo.provide("dojo.rpc.*"); diff --git a/source/web/scripts/ajax/dojo/src/rpc/yahoo.smd b/source/web/scripts/ajax/dojo/src/rpc/yahoo.smd new file mode 100644 index 0000000000..0a305caef8 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/rpc/yahoo.smd @@ -0,0 +1,289 @@ +{ + "SMDVersion":".1", + "objectName":"yahoo", + "serviceType":"JSON-P", + "methods":[ + // + // MAPS + // + { + // http://developer.yahoo.com/maps/rest/V1/mapImage.html + "name":"mapImage", + "serviceURL": "http://api.local.yahoo.com/MapsService/V1/mapImage", + "parameters":[ + { "name":"street", "type":"STRING" }, + { "name":"city", "type":"STRING" }, + { "name":"zip", "type":"INTEGER" }, + { "name":"location", "type":"STRING" }, + { "name":"longitude", "type":"FLOAT" }, + { "name":"latitude", "type":"FLOAT" }, + { "name":"image_type", "type":"STRING" }, + { "name":"image_width", "type":"INTEGER" }, + { "name":"image_height", "type":"INTEGER" }, + { "name":"zoom", "type":"INTEGER" }, + { "name":"radius", "type":"INTEGER" } + ] + }, + { + // http://developer.yahoo.com/traffic/rest/V1/index.html + "name":"trafficData", + "serviceURL": "http://api.local.yahoo.com/MapsService/V1/trafficData", + "parameters":[ + { "name":"street", "type":"STRING" }, + { "name":"city", "type":"STRING" }, + { "name":"zip", "type":"INTEGER" }, + { "name":"location", "type":"STRING" }, + { "name":"longitude", "type":"FLOAT" }, + { "name":"latitude", "type":"FLOAT" }, + { "name":"severity", "type":"INTEGER" }, + { "name":"include_map", "type":"INTEGER" }, + { "name":"image_type", "type":"STRING" }, + { "name":"image_width", "type":"INTEGER" }, + { "name":"image_height", "type":"INTEGER" }, + { "name":"zoom", "type":"INTEGER" }, + { "name":"radius", "type":"INTEGER" } + ] + }, + /* + // Yahoo's geocoding service is f'd for JSON and Y! advises that it + // may not be returning + { + // http://developer.yahoo.com/maps/rest/V1/geocode.html + "name":"geocode", + "serviceURL": "http://api.local.yahoo.com/MapsService/V1/geocode", + "parameters":[ + { "name":"street", "type":"STRING" }, + { "name":"city", "type":"STRING" }, + { "name":"zip", "type":"INTEGER" }, + { "name":"location", "type":"STRING" } + ] + }, + */ + // + // LOCAL SEARCH + // + { + // http://developer.yahoo.com/search/local/V3/localSearch.html + "name":"localSearch", + "serviceURL": "http://api.local.yahoo.com/LocalSearchService/V3/localSearch", + "parameters":[ + { "name":"street", "type":"STRING" }, + { "name":"city", "type":"STRING" }, + { "name":"zip", "type":"INTEGER" }, + { "name":"location", "type":"STRING" }, + { "name":"listing_id", "type":"STRING" }, + { "name":"sort", "type":"STRING" }, // "relevence", "title", "distance", or "rating" + { "name":"start", "type":"INTEGER" }, + { "name":"radius", "type":"FLOAT" }, + { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10 + { "name":"longitude", "type":"FLOAT" }, + { "name":"latitude", "type":"FLOAT" }, + { "name":"category", "type":"INTEGER" }, + { "name":"omit_category", "type":"INTEGER" }, + { "name":"minimum_rating", "type":"INTEGER" } + ] + }, + // + // WEB SEARCH + // + { + // http://developer.yahoo.com/search/web/V1/webSearch.html + "name":"webSearch", + "serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/webSearch", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // defaults to "all" + { "name":"region", "type":"STRING" }, // defaults to "us" + { "name":"results", "type":"INTEGER" }, // defaults to 10 + { "name":"start", "type":"INTEGER" }, // defaults to 1 + { "name":"format", "type":"STRING" }, // defaults to "any", can be "html", "msword", "pdf", "ppt", "rst", "txt", or "xls" + { "name":"adult_ok", "type":"INTEGER" }, // defaults to null + { "name":"similar_ok", "type":"INTEGER" }, // defaults to null + { "name":"language", "type":"STRING" }, // defaults to null + { "name":"country", "type":"STRING" }, // defaults to null + { "name":"site", "type":"STRING" }, // defaults to null + { "name":"subscription", "type":"STRING" }, // defaults to null + { "name":"license", "type":"STRING" } // defaults to "any" + ] + }, + { + // http://developer.yahoo.com/search/web/V1/spellingSuggestion.html + "name":"spellingSuggestion", + "serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/spellingSuggestion", + "parameters":[ { "name":"query", "type":"STRING" } ] + }, + { + // http://developer.yahoo.com/search/web/V1/relatedSuggestion.html + "name":"spellingSuggestion", + "serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/relatedSuggestion", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"results", "type":"INTEGER" } // 1-50, defaults to 10 + ] + }, + { + // http://developer.yahoo.com/search/content/V1/termExtraction.html + "name":"termExtraction", + "serviceURL": "http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"context", "type":"STRING" }, + { "name":"results", "type":"INTEGER" } // 1-50, defaults to 10 + ] + }, + { + // http://developer.yahoo.com/search/web/V1/contextSearch.html + "name":"contextSearch", + "serviceURL": "http://search.yahooapis.com/WebSearchService/V1/contextSearch", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"context", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // defaults to "all" + { "name":"results", "type":"INTEGER" }, // defaults to 10 + { "name":"start", "type":"INTEGER" }, // defaults to 1 + { "name":"format", "type":"STRING" }, // defaults to "any", can be "html", "msword", "pdf", "ppt", "rst", "txt", or "xls" + { "name":"adult_ok", "type":"INTEGER" }, // defaults to null + { "name":"similar_ok", "type":"INTEGER" }, // defaults to null + { "name":"language", "type":"STRING" }, // defaults to null + { "name":"country", "type":"STRING" }, // defaults to null + { "name":"site", "type":"STRING" }, // defaults to null + { "name":"license", "type":"STRING" } // defaults to "any", could be "cc_any", "cc_commercial", "cc_modifiable" + ] + }, + // + // IMAGE SEARCH + // + { + // http://developer.yahoo.com/search/image/V1/imageSearch.html + "name":"imageSearch", + "serviceURL": "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase" + { "name":"results", "type":"INTEGER" }, // defaults to 10 + { "name":"start", "type":"INTEGER" }, // defaults to 1 + { "name":"format", "type":"STRING" }, // defaults to "any", can be "bmp", "gif", "jpeg", or "png" + { "name":"adult_ok", "type":"INTEGER" }, // defaults to null + { "name":"coloration", "type":"STRING" }, // "any", "color", or "bw" + { "name":"site", "type":"STRING" } // defaults to null + ] + }, + // + // SITE EXPLORER + // + { + // http://developer.yahoo.com/search/siteexplorer/V1/inlinkData.html + "name":"inlinkData", + "serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/inlinkData", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase" + { "name":"entire_site", "type":"INTEGER" }, // defaults to null + { "name":"omit_inlinks", "type":"STRING" }, // "domain" or "subdomain", defaults to null + { "name":"results", "type":"INTEGER" }, // defaults to 50 + { "name":"start", "type":"INTEGER" }, // defaults to 1 + { "name":"site", "type":"STRING" } // defaults to null + ] + }, + { + // http://developer.yahoo.com/search/siteexplorer/V1/pageData.html + "name":"pageData", + "serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/pageData", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase" + { "name":"domain_only", "type":"INTEGER" }, // defaults to null + { "name":"results", "type":"INTEGER" }, // defaults to 50 + { "name":"start", "type":"INTEGER" }, // defaults to 1 + { "name":"site", "type":"STRING" } // defaults to null + ] + }, + // + // MUSIC SEARCH + // + { + // http://developer.yahoo.com/search/audio/V1/artistSearch.html + "name":"artistSearch", + "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/artistSearch", + "parameters":[ + { "name":"artist", "type":"STRING" }, + { "name":"artistid", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // "all", "any", or "phrase" + { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10 + { "name":"start", "type":"INTEGER" } // defaults to 1 + ] + }, + { + // http://developer.yahoo.com/search/audio/V1/albumSearch.html + "name":"albumSearch", + "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/albumSearch", + "parameters":[ + { "name":"artist", "type":"STRING" }, + { "name":"artistid", "type":"STRING" }, + { "name":"album", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // "all", "any", or "phrase" + { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10 + { "name":"start", "type":"INTEGER" } // defaults to 1 + ] + }, + { + // http://developer.yahoo.com/search/audio/V1/songSearch.html + "name":"songSearch", + "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songSearch", + "parameters":[ + { "name":"artist", "type":"STRING" }, + { "name":"artistid", "type":"STRING" }, + { "name":"album", "type":"STRING" }, + { "name":"albumid", "type":"STRING" }, + { "name":"song", "type":"STRING" }, + { "name":"songid", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // "all", "any", or "phrase" + { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10 + { "name":"start", "type":"INTEGER" } // defaults to 1 + ] + }, + { + // http://developer.yahoo.com/search/audio/V1/songDownloadLocation.html + "name":"songDownloadLocation", + "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songDownloadLocation", + "parameters":[ + { "name":"songid", "type":"STRING" }, + // "source" can contain: + // audiolunchbox artistdirect buymusic dmusic + // emusic epitonic garageband itunes yahoo + // livedownloads mp34u msn musicmatch mapster passalong + // rhapsody soundclick theweb + { "name":"source", "type":"STRING" }, + { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10 + { "name":"start", "type":"INTEGER" } // defaults to 1 + ] + }, + // + // NEWS SEARCH + // + { + // http://developer.yahoo.com/search/news/V1/newsSearch.html + "name":"newsSearch", + "serviceURL": "http://api.search.yahoo.com/NewsSearchService/V1/newsSearch", + "parameters":[ + { "name":"query", "type":"STRING" }, + { "name":"type", "type":"STRING" }, // defaults to "all" + { "name":"results", "type":"INTEGER" }, // defaults to 10 + { "name":"start", "type":"INTEGER" }, // defaults to 1 + { "name":"sort", "type":"STRING" }, // "rank" or "date" + { "name":"language", "type":"STRING" }, // defaults to null + { "name":"site", "type":"STRING" } // defaults to null + ] + } + /* + { + // + "name":"", + "serviceURL": "", + "parameters":[ + { "name":"street", "type":"STRING" }, + ] + } + */ + ] +} diff --git a/source/web/scripts/ajax/dojo/src/selection/Selection.js b/source/web/scripts/ajax/dojo/src/selection/Selection.js new file mode 100644 index 0000000000..5a40a2bc7a --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/selection/Selection.js @@ -0,0 +1,472 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.selection.Selection"); +dojo.require("dojo.lang.array"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.lang.common"); +dojo.require("dojo.math"); + +dojo.declare("dojo.selection.Selection", null, + { + initializer: function(items, isCollection){ + this.items = []; + this.selection = []; + this._pivotItems = []; + this.clearItems(); + + if(items) { + if(isCollection) { + this.setItemsCollection(items); + } else { + this.setItems(items); + } + } + }, + + // Array: items to select from, order matters for growable selections + items: null, + + // Array: items selected, aren't stored in order (see sorted()) + selection: null, + lastSelected: null, // last item selected + + // Boolean: if true, grow selection will start from 0th item when nothing is selected + allowImplicit: true, + + // Integer: number of *selected* items + length: 0, + + // Boolean: + // if true, the selection is treated as an in-order and can grow + // by ranges, not just by single item + isGrowable: true, + + _pivotItems: null, // stack of pivot items + _pivotItem: null, // item we grow selections from, top of stack + + // event handlers + onSelect: function(item){ + // summary: slot to be connect()'d to + }, + onDeselect: function(item){ + // summary: slot to be connect()'d to + }, + onSelectChange: function(item, selected){ + // summary: slot to be connect()'d to + }, + + _find: function(item, inSelection) { + if(inSelection) { + return dojo.lang.find(this.selection, item); + } else { + return dojo.lang.find(this.items, item); + } + }, + + isSelectable: function(/*Object*/item){ + // summary: + // user-customizable and should be over-ridden, will filter + // items through this + return true; // boolean + }, + + setItems: function(/* ... */){ + // summary: + // adds all passed arguments to the items array, removing any + // previously selected items. + this.clearItems(); + this.addItems.call(this, arguments); + }, + + + setItemsCollection: function(/*Object*/collection){ + // summary: + // like setItems, but use in case you have an active + // collection array-like object (i.e. getElementsByTagName + // collection) that manages its own order and item list + this.items = collection; + }, + + addItems: function(/* ... */){ + // summary: + // adds all passed arguments to the items array + var args = dojo.lang.unnest(arguments); + for(var i = 0; i < args.length; i++){ + this.items.push(args[i]); + } + }, + + addItemsAt: function(/*Object*/item, /*Object*/before /* ... */){ + // summary: + // add items to the array after the the passed "before" item. + if(this.items.length == 0){ // work for empy case + return this.addItems(dojo.lang.toArray(arguments, 2)); + } + + if(!this.isItem(item)){ + item = this.items[item]; + } + if(!item){ throw new Error("addItemsAt: item doesn't exist"); } + var idx = this._find(item); + if(idx > 0 && before){ idx--; } + for(var i = 2; i < arguments.length; i++){ + if(!this.isItem(arguments[i])){ + this.items.splice(idx++, 0, arguments[i]); + } + } + }, + + removeItem: function(/*Object*/item){ + // summary: remove item + var idx = this._find(item); + if(idx > -1) { + this.items.splice(idx, 1); + } + // remove from selection + // FIXME: do we call deselect? I don't think so because this isn't how + // you usually want to deselect an item. For example, if you deleted an + // item, you don't really want to deselect it -- you want it gone. -DS + idx = this._find(item, true); + if(idx > -1) { + this.selection.splice(idx, 1); + } + }, + + clearItems: function(){ + // summary: remove and uselect all items + this.items = []; + this.deselectAll(); + }, + + isItem: function(/*Object*/item){ + // summary: do we already "know" about the passed item? + return this._find(item) > -1; // boolean + }, + + isSelected: function(/*Object*/item){ + // summary: + // do we know about the item and is it selected by this + // selection? + return this._find(item, true) > -1; // boolean + }, + + /** + * allows you to filter item in or out of the selection + * depending on the current selection and action to be taken + **/ + selectFilter: function(item, selection, add, grow) { + return true; + }, + + update: function(/*Object*/item, /*Boolean*/add, /*Boolean*/grow, noToggle) { + // summary: manages selections, most selecting should be done here + // item: item which may be added/grown to/only selected/deselected + // add: behaves like ctrl in windows selection world + // grow: behaves like shift + // noToggle: if true, don't toggle selection on item + if(!this.isItem(item)){ return false; } // boolean + + if(this.isGrowable && grow){ + if( (!this.isSelected(item)) && + this.selectFilter(item, this.selection, false, true) ){ + this.grow(item); + this.lastSelected = item; + } + }else if(add){ + if(this.selectFilter(item, this.selection, true, false)){ + if(noToggle){ + if(this.select(item)){ + this.lastSelected = item; + } + }else if(this.toggleSelected(item)){ + this.lastSelected = item; + } + } + }else{ + this.deselectAll(); + this.select(item); + } + + this.length = this.selection.length; + return true; // Boolean + }, + + grow: function(/*Object*/toItem, /*Object*/fromItem){ + // summary: + // Grow a selection. Any items in (fromItem, lastSelected] + // that aren't part of (fromItem, toItem] will be deselected + // toItem: which item to grow selection to + // fromItem: which item to start the growth from (it won't be selected) + if(!this.isGrowable){ return; } + + if(arguments.length == 1){ + fromItem = this._pivotItem; + if(!fromItem && this.allowImplicit){ + fromItem = this.items[0]; + } + } + if(!toItem || !fromItem){ return false; } + + var fromIdx = this._find(fromItem); + + // get items to deselect (fromItem, lastSelected] + var toDeselect = {}; + var lastIdx = -1; + if(this.lastSelected){ + lastIdx = this._find(this.lastSelected); + var step = fromIdx < lastIdx ? -1 : 1; + var range = dojo.math.range(lastIdx, fromIdx, step); + for(var i = 0; i < range.length; i++){ + toDeselect[range[i]] = true; + } + } + + // add selection (fromItem, toItem] + var toIdx = this._find(toItem); + var step = fromIdx < toIdx ? -1 : 1; + var shrink = lastIdx >= 0 && step == 1 ? lastIdx < toIdx : lastIdx > toIdx; + var range = dojo.math.range(toIdx, fromIdx, step); + if(range.length){ + for(var i = range.length-1; i >= 0; i--){ + var item = this.items[range[i]]; + if(this.selectFilter(item, this.selection, false, true)){ + if(this.select(item, true) || shrink){ + this.lastSelected = item; + } + if(range[i] in toDeselect){ + delete toDeselect[range[i]]; + } + } + } + }else{ + this.lastSelected = fromItem; + } + + // now deselect... + for(var i in toDeselect){ + if(this.items[i] == this.lastSelected){ + //dojo.debug("oops!"); + } + this.deselect(this.items[i]); + } + + // make sure everything is all kosher after selections+deselections + this._updatePivot(); + }, + + growUp: function(){ + // summary: Grow selection upwards one item from lastSelected + if(!this.isGrowable){ return; } + + var idx = this._find(this.lastSelected) - 1; + while(idx >= 0){ + if(this.selectFilter(this.items[idx], this.selection, false, true)){ + this.grow(this.items[idx]); + break; + } + idx--; + } + }, + + growDown: function(){ + // summary: Grow selection downwards one item from lastSelected + if(!this.isGrowable){ return; } + + var idx = this._find(this.lastSelected); + if(idx < 0 && this.allowImplicit){ + this.select(this.items[0]); + idx = 0; + } + idx++; + while(idx > 0 && idx < this.items.length){ + if(this.selectFilter(this.items[idx], this.selection, false, true)){ + this.grow(this.items[idx]); + break; + } + idx++; + } + }, + + toggleSelected: function(/*Object*/item, /*Boolean*/noPivot){ + // summary: + // like it says on the tin. If noPivot is true, no selection + // pivot is added (or removed) from the selection. Returns 1 + // if the item is selected, -1 if it is deselected, and 0 if + // the item is not under management. + if(this.isItem(item)){ + if(this.select(item, noPivot)){ return 1; } + if(this.deselect(item)){ return -1; } + } + return 0; + }, + + select: function(/*Object*/item, /*Boolean*/noPivot){ + // summary: + // like it says on the tin. If noPivot is true, no selection + // pivot is added from the selection. + if(this.isItem(item) && !this.isSelected(item) + && this.isSelectable(item)){ + this.selection.push(item); + this.lastSelected = item; + this.onSelect(item); + this.onSelectChange(item, true); + if(!noPivot){ + this._addPivot(item); + } + this.length = this.selection.length; + return true; + } + return false; + }, + + deselect: function(item){ + // summary: deselects the item if it's selected. + var idx = this._find(item, true); + if(idx > -1){ + this.selection.splice(idx, 1); + this.onDeselect(item); + this.onSelectChange(item, false); + if(item == this.lastSelected){ + this.lastSelected = null; + } + this._removePivot(item); + this.length = this.selection.length; + return true; + } + return false; + }, + + selectAll: function(){ + // summary: selects all known items + for(var i = 0; i < this.items.length; i++){ + this.select(this.items[i]); + } + }, + + deselectAll: function(){ + // summary: deselects all currently selected items + while(this.selection && this.selection.length){ + this.deselect(this.selection[0]); + } + }, + + selectNext: function(){ + // summary: + // clobbers the existing selection (if any) and selects the + // next item "below" the previous "bottom" selection. Returns + // whether or not selection was successful. + var idx = this._find(this.lastSelected); + while(idx > -1 && ++idx < this.items.length){ + if(this.isSelectable(this.items[idx])){ + this.deselectAll(); + this.select(this.items[idx]); + return true; + } + } + return false; + }, + + selectPrevious: function(){ + // summary: + // clobbers the existing selection (if any) and selects the + // item "above" the previous "top" selection. Returns whether + // or not selection was successful. + var idx = this._find(this.lastSelected); + while(idx-- > 0){ + if(this.isSelectable(this.items[idx])){ + this.deselectAll(); + this.select(this.items[idx]); + return true; + } + } + return false; + }, + + selectFirst: function(){ + // summary: + // select first selectable item. Returns whether or not an + // item was selected. + this.deselectAll(); + var idx = 0; + while(this.items[idx] && !this.select(this.items[idx])){ + idx++; + } + return this.items[idx] ? true : false; + }, + + selectLast: function(){ + // summary: select last selectable item + this.deselectAll(); + var idx = this.items.length-1; + while(this.items[idx] && !this.select(this.items[idx])) { + idx--; + } + return this.items[idx] ? true : false; + }, + + _addPivot: function(item, andClear){ + this._pivotItem = item; + if(andClear){ + this._pivotItems = [item]; + }else{ + this._pivotItems.push(item); + } + }, + + _removePivot: function(item){ + var i = dojo.lang.find(this._pivotItems, item); + if(i > -1){ + this._pivotItems.splice(i, 1); + this._pivotItem = this._pivotItems[this._pivotItems.length-1]; + } + + this._updatePivot(); + }, + + _updatePivot: function(){ + if(this._pivotItems.length == 0){ + if(this.lastSelected){ + this._addPivot(this.lastSelected); + } + } + }, + + sorted: function(){ + // summary: returns an array of items in sort order + return dojo.lang.toArray(this.selection).sort( + dojo.lang.hitch(this, function(a, b){ + var A = this._find(a), B = this._find(b); + if(A > B){ + return 1; + }else if(A < B){ + return -1; + }else{ + return 0; + } + }) + ); + }, + + updateSelected: function(){ + // summary: + // remove any items from the selection that are no longer in + // this.items + for(var i = 0; i < this.selection.length; i++) { + if(this._find(this.selection[i]) < 0) { + var removed = this.selection.splice(i, 1); + + this._removePivot(removed[0]); + } + } + this.length = this.selection.length; + } + } +); diff --git a/source/web/scripts/ajax/dojo/src/storage.js b/source/web/scripts/ajax/dojo/src/storage.js new file mode 100644 index 0000000000..3a15982350 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/storage.js @@ -0,0 +1,394 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.storage"); + +dojo.require("dojo.lang.*"); +dojo.require("dojo.event.*"); + + +dojo.storage = new function(){ + // summary: A singleton for working with Dojo Storage. + // description: + // dojo.storage exposes the current available storage + // provider on this platform. It gives you methods such + // as dojo.storage.put(), dojo.storage.get(), etc. + // + // For more details on Dojo Storage, see the primary + // documentation page at + // http://manual.dojotoolkit.org/storage.html + // + // Note for storage provider developers who are creating + // subclasses- + // This is the base class for all storage providers + // Specific kinds of Storage Providers should subclass this + // and implement these methods. You should avoid initialization + // storage provider subclass's constructor; instead, perform + // initialization in your initialize() method. +} + +dojo.declare("dojo.storage", null, { + // SUCCESS: String + // Flag that indicates a put() call to a + // storage provider was succesful. + SUCCESS: "success", + + // FAILED: String + // Flag that indicates a put() call to + // a storage provider failed. + FAILED: "failed", + + // PENDING: String + // Flag that indicates a put() call to a + // storage provider is pending user approval. + PENDING: "pending", + + // SIZE_NOT_AVAILABLE: String + // Returned by getMaximumSize() if this storage provider can not determine + // the maximum amount of data it can support. + SIZE_NOT_AVAILABLE: "Size not available", + + // SIZE_NO_LIMIT: String + // Returned by getMaximumSize() if this storage provider has no theoretical + // limit on the amount of data it can store. + SIZE_NO_LIMIT: "No size limit", + + // namespace: String + // The namespace for all storage operations. This is useful if several + // applications want access to the storage system from the same domain but + //want different storage silos. + namespace: "default", + + // onHideSettingsUI: Function + // If a function is assigned to this property, then when the settings + // provider's UI is closed this function is called. Useful, for example, + // if the user has just cleared out all storage for this provider using + // the settings UI, and you want to update your UI. + onHideSettingsUI: null, + + initialize: function(){ + // summary: + // Allows this storage provider to initialize itself. This is + // called after the page has finished loading, so you can not do + // document.writes(). Storage Provider subclasses should initialize + // themselves inside of here rather than in their function + // constructor. + dojo.unimplemented("dojo.storage.initialize"); + }, + + isAvailable: function(){ /*Boolean*/ + // summary: + // Returns whether this storage provider is available on this + // platform. + dojo.unimplemented("dojo.storage.isAvailable"); + }, + + put: function( /*string*/ key, + /*object*/ value, + /*function*/ resultsHandler){ + // summary: + // Puts a key and value into this storage system. + // description: + // Example- + // var resultsHandler = function(status, key, message){ + // alert("status="+status+", key="+key+", message="+message); + // }; + // dojo.storage.put("test", "hello world", resultsHandler); + // key: + // A string key to use when retrieving this value in the future. + // value: + // A value to store; this can be any JavaScript type. + // resultsHandler: + // A callback function that will receive three arguments. The + // first argument is one of three values: dojo.storage.SUCCESS, + // dojo.storage.FAILED, or dojo.storage.PENDING; these values + // determine how the put request went. In some storage systems + // users can deny a storage request, resulting in a + // dojo.storage.FAILED, while in other storage systems a storage + // request must wait for user approval, resulting in a + // dojo.storage.PENDING status until the request is either + // approved or denied, resulting in another call back with + // dojo.storage.SUCCESS. + // The second argument in the call back is the key name that was being stored. + // The third argument in the call back is an optional message that + // details possible error messages that might have occurred during + // the storage process. + + dojo.unimplemented("dojo.storage.put"); + }, + + get: function(/*string*/ key){ /*Object*/ + // summary: + // Gets the value with the given key. Returns null if this key is + // not in the storage system. + // key: + // A string key to get the value of. + // return: Returns any JavaScript object type; null if the key is not present + dojo.unimplemented("dojo.storage.get"); + }, + + hasKey: function(/*string*/ key){ /*Boolean*/ + // summary: Determines whether the storage has the given key. + return (this.get(key) != null); + }, + + getKeys: function(){ /*Array*/ + // summary: Enumerates all of the available keys in this storage system. + // return: Array of available keys + dojo.unimplemented("dojo.storage.getKeys"); + }, + + clear: function(){ + // summary: + // Completely clears this storage system of all of it's values and + // keys. + dojo.unimplemented("dojo.storage.clear"); + }, + + remove: function(key){ + // summary: Removes the given key from this storage system. + dojo.unimplemented("dojo.storage.remove"); + }, + + isPermanent: function(){ /*Boolean*/ + // summary: + // Returns whether this storage provider's values are persisted + // when this platform is shutdown. + dojo.unimplemented("dojo.storage.isPermanent"); + }, + + getMaximumSize: function(){ /* mixed */ + // summary: The maximum storage allowed by this provider + // returns: + // Returns the maximum storage size + // supported by this provider, in + // thousands of bytes (i.e., if it + // returns 60 then this means that 60K + // of storage is supported). + // + // If this provider can not determine + // it's maximum size, then + // dojo.storage.SIZE_NOT_AVAILABLE is + // returned; if there is no theoretical + // limit on the amount of storage + // this provider can return, then + // dojo.storage.SIZE_NO_LIMIT is + // returned + dojo.unimplemented("dojo.storage.getMaximumSize"); + }, + + hasSettingsUI: function(){ /*Boolean*/ + // summary: Determines whether this provider has a settings UI. + return false; + }, + + showSettingsUI: function(){ + // summary: If this provider has a settings UI, determined + // by calling hasSettingsUI(), it is shown. + dojo.unimplemented("dojo.storage.showSettingsUI"); + }, + + hideSettingsUI: function(){ + // summary: If this provider has a settings UI, hides it. + dojo.unimplemented("dojo.storage.hideSettingsUI"); + }, + + getType: function(){ /*String*/ + // summary: + // The provider name as a string, such as + // "dojo.storage.FlashStorageProvider". + dojo.unimplemented("dojo.storage.getType"); + }, + + isValidKey: function(/*string*/ keyName){ /*Boolean*/ + // summary: + // Subclasses can call this to ensure that the key given is valid + // in a consistent way across different storage providers. We use + // the lowest common denominator for key values allowed: only + // letters, numbers, and underscores are allowed. No spaces. + if((keyName == null)||(typeof keyName == "undefined")){ + return false; + } + + return /^[0-9A-Za-z_]*$/.test(keyName); + } +}); + + + + +dojo.storage.manager = new function(){ + // summary: A singleton class in charge of the Dojo Storage system + // description: + // Initializes the storage systems and figures out the best available + // storage options on this platform. + + // currentProvider: Object + // The storage provider that was automagically chosen to do storage + // on this platform, such as dojo.storage.browser.FlashStorageProvider. + this.currentProvider = null; + + // available: Boolean + // Whether storage of some kind is available + this.available = false; + + this._initialized = false; + this._providers = []; + + // namespace: String + // An optional namespace value that can be used by a single application + // to partition storage into seperate units - not well supported yet. + this.namespace = "default"; + + this.initialize = function(){ + // summary: + // Initializes the storage system and autodetects the best storage + // provider we can provide on this platform + this.autodetect(); + }; + + this.register = function(/*string*/ name, /*Object*/ instance) { + // summary: + // Registers the existence of a new storage provider; used by + // subclasses to inform the manager of their existence. The + // storage manager will select storage providers based on + // their ordering, so the order in which you call this method + // matters. + // name: + // The full class name of this provider, such as + // "dojo.storage.browser.FlashStorageProvider". + // instance: + // An instance of this provider, which we will use to call + // isAvailable() on. + this._providers[this._providers.length] = instance; + this._providers[name] = instance; + }; + + this.setProvider = function(storageClass){ + // summary: + // Instructs the storageManager to use the given storage class for + // all storage requests. + // description: + // Example- + // dojo.storage.setProvider( + // dojo.storage.browser.IEStorageProvider) + + }; + + this.autodetect = function(){ + // summary: + // Autodetects the best possible persistent storage provider + // available on this platform. + if(this._initialized == true){ // already finished + return; + } + + // go through each provider, seeing if it can be used + var providerToUse = null; + for(var i = 0; i < this._providers.length; i++){ + providerToUse = this._providers[i]; + // a flag to force the storage manager to use a particular + // storage provider type, such as + // djConfig = {forceStorageProvider: "dojo.storage.browser.WhatWGStorageProvider"}; + if(dojo.lang.isUndefined(djConfig["forceStorageProvider"]) == false + && providerToUse.getType() == djConfig["forceStorageProvider"]){ + // still call isAvailable for this provider, since this helps some + // providers internally figure out if they are available + providerToUse.isAvailable(); + break; + }else if(dojo.lang.isUndefined(djConfig["forceStorageProvider"]) == true + && providerToUse.isAvailable()){ + break; + } + } + + if(providerToUse == null){ // no provider available + this._initialized = true; + this.available = false; + this.currentProvider = null; + dojo.raise("No storage provider found for this platform"); + } + + // create this provider and copy over it's properties + this.currentProvider = providerToUse; + for(var i in providerToUse){ + dojo.storage[i] = providerToUse[i]; + } + dojo.storage.manager = this; + + // have the provider initialize itself + dojo.storage.initialize(); + + this._initialized = true; + this.available = true; + }; + + this.isAvailable = function(){ /*Boolean*/ + // summary: Returns whether any storage options are available. + return this.available; + }; + + this.isInitialized = function(){ /*Boolean*/ + // summary: + // Returns whether the storage system is initialized and ready to + // be used. + + // FIXME: This should REALLY not be in here, but it fixes a tricky + // Flash timing bug + if(this.currentProvider.getType() == "dojo.storage.browser.FlashStorageProvider" + && dojo.flash.ready == false){ + return false; + }else{ + return this._initialized; + } + }; + + this.supportsProvider = function(/*string*/ storageClass){ /* Boolean */ + // summary: Determines if this platform supports the given storage provider. + // description: + // Example- + // dojo.storage.manager.supportsProvider( + // "dojo.storage.browser.InternetExplorerStorageProvider"); + + // construct this class dynamically + try{ + // dynamically call the given providers class level isAvailable() + // method + var provider = eval("new " + storageClass + "()"); + var results = provider.isAvailable(); + if(results == null || typeof results == "undefined") + return false; + return results; + }catch (exception){ + return false; + } + }; + + this.getProvider = function(){ /* Object */ + // summary: Gets the current provider + return this.currentProvider; + }; + + this.loaded = function(){ + // summary: + // The storage provider should call this method when it is loaded + // and ready to be used. Clients who will use the provider will + // connect to this method to know when they can use the storage + // system. + // description: + // Example- + // if(dojo.storage.manager.isInitialized() == false){ + // dojo.event.connect(dojo.storage.manager, "loaded", TestStorage, + // TestStorage.initialize); + // }else{ + // dojo.event.connect(dojo, "loaded", TestStorage, TestStorage.initialize); + // } + }; +}; diff --git a/source/web/scripts/ajax/dojo/src/storage/Storage.as b/source/web/scripts/ajax/dojo/src/storage/Storage.as new file mode 100644 index 0000000000..831a1aace0 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/storage/Storage.as @@ -0,0 +1,146 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +import DojoExternalInterface; + +class Storage { + public static var SUCCESS = "success"; + public static var FAILED = "failed"; + public static var PENDING = "pending"; + + public var so; + + public function Storage(){ + //getURL("javascript:dojo.debug('FLASH:Storage constructor')"); + DojoExternalInterface.initialize(); + DojoExternalInterface.addCallback("put", this, put); + DojoExternalInterface.addCallback("get", this, get); + DojoExternalInterface.addCallback("showSettings", this, showSettings); + DojoExternalInterface.addCallback("clear", this, clear); + DojoExternalInterface.addCallback("getKeys", this, getKeys); + DojoExternalInterface.addCallback("remove", this, remove); + DojoExternalInterface.loaded(); + + // preload the System Settings finished button movie for offline + // access so it is in the cache + _root.createEmptyMovieClip("_settingsBackground", 1); + // getURL("javascript:alert('"+DojoExternalInterface.dojoPath+"');"); + _root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath + "storage_dialog.swf"); + } + + public function put(keyName, keyValue, namespace){ + // Get the SharedObject for these values and save it + so = SharedObject.getLocal(namespace); + + // prepare a storage status handler + var self = this; + so.onStatus = function(infoObject:Object){ + //getURL("javascript:dojo.debug('FLASH: onStatus, infoObject="+infoObject.code+"')"); + + // delete the data value if the request was denied + if (infoObject.code == "SharedObject.Flush.Failed"){ + delete self.so.data[keyName]; + } + + var statusResults; + if(infoObject.code == "SharedObject.Flush.Failed"){ + statusResults = Storage.FAILED; + }else if(infoObject.code == "SharedObject.Flush.Pending"){ + statusResults = Storage.PENDING; + }else if(infoObject.code == "SharedObject.Flush.Success"){ + statusResults = Storage.SUCCESS; + } + //getURL("javascript:dojo.debug('FLASH: onStatus, statusResults="+statusResults+"')"); + + // give the status results to JavaScript + DojoExternalInterface.call("dojo.storage._onStatus", null, statusResults, + keyName); + } + + // save the key and value + so.data[keyName] = keyValue; + var flushResults = so.flush(); + + // return results of this command to JavaScript + var statusResults; + if(flushResults == true){ + statusResults = Storage.SUCCESS; + }else if(flushResults == "pending"){ + statusResults = Storage.PENDING; + }else{ + statusResults = Storage.FAILED; + } + + DojoExternalInterface.call("dojo.storage._onStatus", null, statusResults, + keyName); + } + + public function get(keyName, namespace){ + // Get the SharedObject for these values and save it + so = SharedObject.getLocal(namespace); + var results = so.data[keyName]; + + return results; + } + + public function showSettings(){ + // Show the configuration options for the Flash player, opened to the + // section for local storage controls (pane 1) + System.showSettings(1); + + // there is no way we can intercept when the Close button is pressed, allowing us + // to hide the Flash dialog. Instead, we need to load a movie in the + // background that we can show a close button on. + _root.createEmptyMovieClip("_settingsBackground", 1); + _root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath + "storage_dialog.swf"); + } + + public function clear(namespace){ + so = SharedObject.getLocal(namespace); + so.clear(); + so.flush(); + } + + public function getKeys(namespace){ + // Returns a list of the available keys in this namespace + + // get the storage object + so = SharedObject.getLocal(namespace); + + // get all of the keys + var results = new Array(); + for(var i in so.data) + results.push(i); + + // join the keys together in a comma seperated string + results = results.join(","); + + return results; + } + + public function remove(keyName, namespace){ + // Removes a key + + // get the storage object + so = SharedObject.getLocal(namespace); + + // delete this value + delete so.data[keyName]; + + // save the changes + so.flush(); + } + + static function main(mc){ + //getURL("javascript:dojo.debug('FLASH: storage loaded')"); + _root.app = new Storage(); + } +} + diff --git a/source/web/scripts/ajax/dojo/src/storage/__package__.js b/source/web/scripts/ajax/dojo/src/storage/__package__.js new file mode 100644 index 0000000000..eeb35ca4d3 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/storage/__package__.js @@ -0,0 +1,16 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.kwCompoundRequire({ + common: ["dojo.storage"], + browser: ["dojo.storage.browser"] +}); +dojo.provide("dojo.storage.*"); + diff --git a/source/web/scripts/ajax/dojo/src/storage/browser.js b/source/web/scripts/ajax/dojo/src/storage/browser.js new file mode 100644 index 0000000000..0b6cfe0d08 --- /dev/null +++ b/source/web/scripts/ajax/dojo/src/storage/browser.js @@ -0,0 +1,363 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.storage.browser"); + +dojo.require("dojo.storage"); +dojo.require("dojo.flash"); +dojo.require("dojo.json"); +dojo.require("dojo.uri.*"); + + + +dojo.storage.browser.WhatWGStorageProvider = function(){ + // summary: + // Storage provider that uses WHAT Working Group features in Firefox 2 + // to achieve permanent storage. + // description: + // The WHAT WG storage API is documented at + // http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side + // + // You can disable this storage provider with the following djConfig + // variable: + // var djConfig = { disableWhatWGStorage: true }; + // + // Authors of this storage provider- + // JB Boisseau, jb.boisseau@eutech-ssii.com + // Brad Neuberg, bkn3@columbia.edu +} + +dojo.inherits(dojo.storage.browser.WhatWGStorageProvider, dojo.storage); + +// instance methods and properties +dojo.lang.extend(dojo.storage.browser.WhatWGStorageProvider, { + namespace: "default", + initialized: false, + + _domain: null, + _available: null, + _statusHandler: null, + + initialize: function(){ + if(djConfig["disableWhatWGStorage"] == true){ + return; + } + + // get current domain + this._domain = location.hostname; + + // indicate that this storage provider is now loaded + this.initialized = true; + dojo.storage.manager.loaded(); + }, + + isAvailable: function(){ + try{ + var myStorage = globalStorage[location.hostname]; + }catch(e){ + this._available = false; + return this._available; + } + + this._available = true; + return this._available; + }, + + put: function(key, value, resultsHandler){ + if(this.isValidKey(key) == false){ + dojo.raise("Invalid key given: " + key); + } + + this._statusHandler = resultsHandler; + + // serialize the value; + // handle strings differently so they have better performance + if(dojo.lang.isString(value)){ + value = "string:" + value; + }else{ + value = dojo.json.serialize(value); + } + + // register for successful storage events + window.addEventListener("storage", function(evt){ + // indicate we succeeded + resultsHandler.call(null, dojo.storage.SUCCESS, key); + }, false); + + // try to store the value + try{ + var myStorage = globalStorage[this._domain]; + myStorage.setItem(key,value); + }catch(e){ + // indicate we failed + this._statusHandler.call(null, dojo.storage.FAILED, + key, e.toString()); + } + }, + + get: function(key){ + if(this.isValidKey(key) == false){ + dojo.raise("Invalid key given: " + key); + } + + var myStorage = globalStorage[this._domain]; + + var results = myStorage.getItem(key); + + if(results == null){ + return null; + } + + results = results.value; + + // destringify the content back into a + // real JavaScript object; + // handle strings differently so they have better performance + if(!dojo.lang.isUndefined(results) && results != null + && /^string:/.test(results)){ + results = results.substring("string:".length); + }else{ + results = dojo.json.evalJson(results); + } + + return results; + }, + + getKeys: function(){ + var myStorage = globalStorage[this._domain]; + var keysArray = new Array(); + for(i=0; i