");
+}
+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;i=4){
+this.changeUrl=_14a;
+}
+}
+};
+dojo.lang.extend(dojo.io.Request,{url:"",mimetype:"text/plain",method:"GET",content:undefined,transport:undefined,changeUrl:undefined,formNode:undefined,sync:false,bindSuccess:false,useCache:false,preventCache:false,load:function(type,data,_14d,_14e){
+},error:function(type,_150,_151,_152){
+},timeout:function(type,_154,_155,_156){
+},handle:function(type,data,_159,_15a){
+},timeoutSeconds:0,abort:function(){
+},fromKwArgs:function(_15b){
+if(_15b["url"]){
+_15b.url=_15b.url.toString();
+}
+if(_15b["formNode"]){
+_15b.formNode=dojo.byId(_15b.formNode);
+}
+if(!_15b["method"]&&_15b["formNode"]&&_15b["formNode"].method){
+_15b.method=_15b["formNode"].method;
+}
+if(!_15b["handle"]&&_15b["handler"]){
+_15b.handle=_15b.handler;
+}
+if(!_15b["load"]&&_15b["loaded"]){
+_15b.load=_15b.loaded;
+}
+if(!_15b["changeUrl"]&&_15b["changeURL"]){
+_15b.changeUrl=_15b.changeURL;
+}
+_15b.encoding=dojo.lang.firstValued(_15b["encoding"],djConfig["bindEncoding"],"");
+_15b.sendTransport=dojo.lang.firstValued(_15b["sendTransport"],djConfig["ioSendTransport"],false);
+var _15c=dojo.lang.isFunction;
+for(var x=0;x0){
+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:
+ *