summaryrefslogtreecommitdiff
path: root/lib/dojo/_base/html.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dojo/_base/html.js')
-rw-r--r--lib/dojo/_base/html.js2549
1 files changed, 1817 insertions, 732 deletions
diff --git a/lib/dojo/_base/html.js b/lib/dojo/_base/html.js
index 050841531..be5fd2aaa 100644
--- a/lib/dojo/_base/html.js
+++ b/lib/dojo/_base/html.js
@@ -5,745 +5,1830 @@
*/
-if(!dojo._hasResource["dojo._base.html"]){
-dojo._hasResource["dojo._base.html"]=true;
+if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.html"] = true;
dojo.require("dojo._base.lang");
dojo.provide("dojo._base.html");
+
+// FIXME: need to add unit tests for all the semi-public methods
+
try{
-document.execCommand("BackgroundImageCache",false,true);
-}
-catch(e){
+ document.execCommand("BackgroundImageCache", false, true);
+}catch(e){
+ // sane browsers don't have cache "issues"
}
-if(dojo.isIE||dojo.isOpera){
-dojo.byId=function(id,_1){
-if(typeof id!="string"){
-return id;
-}
-var _2=_1||dojo.doc,te=_2.getElementById(id);
-if(te&&(te.attributes.id.value==id||te.id==id)){
-return te;
+
+// =============================
+// DOM Functions
+// =============================
+
+/*=====
+dojo.byId = function(id, doc){
+ // summary:
+ // Returns DOM node with matching `id` attribute or `null`
+ // if not found. If `id` is a DomNode, this function is a no-op.
+ //
+ // id: String|DOMNode
+ // A string to match an HTML id attribute or a reference to a DOM Node
+ //
+ // doc: Document?
+ // Document to work in. Defaults to the current value of
+ // dojo.doc. Can be used to retrieve
+ // node references from other documents.
+ //
+ // example:
+ // Look up a node by ID:
+ // | var n = dojo.byId("foo");
+ //
+ // example:
+ // Check if a node exists, and use it.
+ // | var n = dojo.byId("bar");
+ // | if(n){ doStuff() ... }
+ //
+ // example:
+ // Allow string or DomNode references to be passed to a custom function:
+ // | var foo = function(nodeOrId){
+ // | nodeOrId = dojo.byId(nodeOrId);
+ // | // ... more stuff
+ // | }
+=====*/
+
+if(dojo.isIE || dojo.isOpera){
+ dojo.byId = function(id, doc){
+ if(typeof id != "string"){
+ return id;
+ }
+ var _d = doc || dojo.doc, te = _d.getElementById(id);
+ // attributes.id.value is better than just id in case the
+ // user has a name=id inside a form
+ if(te && (te.attributes.id.value == id || te.id == id)){
+ return te;
+ }else{
+ var eles = _d.all[id];
+ if(!eles || eles.nodeName){
+ eles = [eles];
+ }
+ // if more than 1, choose first with the correct id
+ var i=0;
+ while((te=eles[i++])){
+ if((te.attributes && te.attributes.id && te.attributes.id.value == id)
+ || te.id == id){
+ return te;
+ }
+ }
+ }
+ };
}else{
-var _3=_2.all[id];
-if(!_3||_3.nodeName){
-_3=[_3];
-}
-var i=0;
-while((te=_3[i++])){
-if((te.attributes&&te.attributes.id&&te.attributes.id.value==id)||te.id==id){
-return te;
-}
-}
+ dojo.byId = function(id, doc){
+ // inline'd type check
+ return (typeof id == "string") ? (doc || dojo.doc).getElementById(id) : id; // DomNode
+ };
}
+/*=====
};
-}else{
-dojo.byId=function(id,_4){
-return (typeof id=="string")?(_4||dojo.doc).getElementById(id):id;
-};
-}
+=====*/
+
(function(){
-var d=dojo;
-var _5=d.byId;
-var _6=null,_7;
-d.addOnWindowUnload(function(){
-_6=null;
-});
-dojo._destroyElement=dojo.destroy=function(_8){
-_8=_5(_8);
-try{
-var _9=_8.ownerDocument;
-if(!_6||_7!=_9){
-_6=_9.createElement("div");
-_7=_9;
-}
-_6.appendChild(_8.parentNode?_8.parentNode.removeChild(_8):_8);
-_6.innerHTML="";
-}
-catch(e){
-}
-};
-dojo.isDescendant=function(_a,_b){
-try{
-_a=_5(_a);
-_b=_5(_b);
-while(_a){
-if(_a==_b){
-return true;
-}
-_a=_a.parentNode;
-}
-}
-catch(e){
-}
-return false;
-};
-dojo.setSelectable=function(_c,_d){
-_c=_5(_c);
-if(d.isMozilla){
-_c.style.MozUserSelect=_d?"":"none";
-}else{
-if(d.isKhtml||d.isWebKit){
-_c.style.KhtmlUserSelect=_d?"auto":"none";
-}else{
-if(d.isIE){
-var v=(_c.unselectable=_d?"":"on");
-d.query("*",_c).forEach("item.unselectable = '"+v+"'");
-}
-}
-}
-};
-var _e=function(_f,ref){
-var _10=ref.parentNode;
-if(_10){
-_10.insertBefore(_f,ref);
-}
-};
-var _11=function(_12,ref){
-var _13=ref.parentNode;
-if(_13){
-if(_13.lastChild==ref){
-_13.appendChild(_12);
-}else{
-_13.insertBefore(_12,ref.nextSibling);
-}
-}
-};
-dojo.place=function(_14,_15,_16){
-_15=_5(_15);
-if(typeof _14=="string"){
-_14=_14.charAt(0)=="<"?d._toDom(_14,_15.ownerDocument):_5(_14);
-}
-if(typeof _16=="number"){
-var cn=_15.childNodes;
-if(!cn.length||cn.length<=_16){
-_15.appendChild(_14);
-}else{
-_e(_14,cn[_16<0?0:_16]);
-}
-}else{
-switch(_16){
-case "before":
-_e(_14,_15);
-break;
-case "after":
-_11(_14,_15);
-break;
-case "replace":
-_15.parentNode.replaceChild(_14,_15);
-break;
-case "only":
-d.empty(_15);
-_15.appendChild(_14);
-break;
-case "first":
-if(_15.firstChild){
-_e(_14,_15.firstChild);
-break;
-}
-default:
-_15.appendChild(_14);
-}
-}
-return _14;
-};
-dojo.boxModel="content-box";
-if(d.isIE){
-d.boxModel=document.compatMode=="BackCompat"?"border-box":"content-box";
-}
-var gcs;
-if(d.isWebKit){
-gcs=function(_17){
-var s;
-if(_17.nodeType==1){
-var dv=_17.ownerDocument.defaultView;
-s=dv.getComputedStyle(_17,null);
-if(!s&&_17.style){
-_17.style.display="";
-s=dv.getComputedStyle(_17,null);
-}
-}
-return s||{};
-};
-}else{
-if(d.isIE){
-gcs=function(_18){
-return _18.nodeType==1?_18.currentStyle:{};
-};
-}else{
-gcs=function(_19){
-return _19.nodeType==1?_19.ownerDocument.defaultView.getComputedStyle(_19,null):{};
-};
-}
-}
-dojo.getComputedStyle=gcs;
-if(!d.isIE){
-d._toPixelValue=function(_1a,_1b){
-return parseFloat(_1b)||0;
-};
-}else{
-d._toPixelValue=function(_1c,_1d){
-if(!_1d){
-return 0;
-}
-if(_1d=="medium"){
-return 4;
-}
-if(_1d.slice&&_1d.slice(-2)=="px"){
-return parseFloat(_1d);
-}
-with(_1c){
-var _1e=style.left;
-var _1f=runtimeStyle.left;
-runtimeStyle.left=currentStyle.left;
-try{
-style.left=_1d;
-_1d=style.pixelLeft;
-}
-catch(e){
-_1d=0;
-}
-style.left=_1e;
-runtimeStyle.left=_1f;
-}
-return _1d;
-};
-}
-var px=d._toPixelValue;
-var _20="DXImageTransform.Microsoft.Alpha";
-var af=function(n,f){
-try{
-return n.filters.item(_20);
-}
-catch(e){
-return f?{}:null;
-}
-};
-dojo._getOpacity=d.isIE?function(_21){
-try{
-return af(_21).Opacity/100;
-}
-catch(e){
-return 1;
-}
-}:function(_22){
-return gcs(_22).opacity;
-};
-dojo._setOpacity=d.isIE?function(_23,_24){
-var ov=_24*100,_25=_24==1;
-_23.style.zoom=_25?"":1;
-if(!af(_23)){
-if(_25){
-return _24;
-}
-_23.style.filter+=" progid:"+_20+"(Opacity="+ov+")";
-}else{
-af(_23,1).Opacity=ov;
-}
-af(_23,1).Enabled=!_25;
-if(_23.nodeName.toLowerCase()=="tr"){
-d.query("> td",_23).forEach(function(i){
-d._setOpacity(i,_24);
-});
-}
-return _24;
-}:function(_26,_27){
-return _26.style.opacity=_27;
-};
-var _28={left:true,top:true};
-var _29=/margin|padding|width|height|max|min|offset/;
-var _2a=function(_2b,_2c,_2d){
-_2c=_2c.toLowerCase();
-if(d.isIE){
-if(_2d=="auto"){
-if(_2c=="height"){
-return _2b.offsetHeight;
-}
-if(_2c=="width"){
-return _2b.offsetWidth;
-}
-}
-if(_2c=="fontweight"){
-switch(_2d){
-case 700:
-return "bold";
-case 400:
-default:
-return "normal";
-}
-}
-}
-if(!(_2c in _28)){
-_28[_2c]=_29.test(_2c);
-}
-return _28[_2c]?px(_2b,_2d):_2d;
-};
-var _2e=d.isIE?"styleFloat":"cssFloat",_2f={"cssFloat":_2e,"styleFloat":_2e,"float":_2e};
-dojo.style=function(_30,_31,_32){
-var n=_5(_30),_33=arguments.length,op=(_31=="opacity");
-_31=_2f[_31]||_31;
-if(_33==3){
-return op?d._setOpacity(n,_32):n.style[_31]=_32;
-}
-if(_33==2&&op){
-return d._getOpacity(n);
-}
-var s=gcs(n);
-if(_33==2&&typeof _31!="string"){
-for(var x in _31){
-d.style(_30,x,_31[x]);
-}
-return s;
-}
-return (_33==1)?s:_2a(n,_31,s[_31]||n.style[_31]);
-};
-dojo._getPadExtents=function(n,_34){
-var s=_34||gcs(n),l=px(n,s.paddingLeft),t=px(n,s.paddingTop);
-return {l:l,t:t,w:l+px(n,s.paddingRight),h:t+px(n,s.paddingBottom)};
-};
-dojo._getBorderExtents=function(n,_35){
-var ne="none",s=_35||gcs(n),bl=(s.borderLeftStyle!=ne?px(n,s.borderLeftWidth):0),bt=(s.borderTopStyle!=ne?px(n,s.borderTopWidth):0);
-return {l:bl,t:bt,w:bl+(s.borderRightStyle!=ne?px(n,s.borderRightWidth):0),h:bt+(s.borderBottomStyle!=ne?px(n,s.borderBottomWidth):0)};
-};
-dojo._getPadBorderExtents=function(n,_36){
-var s=_36||gcs(n),p=d._getPadExtents(n,s),b=d._getBorderExtents(n,s);
-return {l:p.l+b.l,t:p.t+b.t,w:p.w+b.w,h:p.h+b.h};
-};
-dojo._getMarginExtents=function(n,_37){
-var s=_37||gcs(n),l=px(n,s.marginLeft),t=px(n,s.marginTop),r=px(n,s.marginRight),b=px(n,s.marginBottom);
-if(d.isWebKit&&(s.position!="absolute")){
-r=l;
-}
-return {l:l,t:t,w:l+r,h:t+b};
-};
-dojo._getMarginBox=function(_38,_39){
-var s=_39||gcs(_38),me=d._getMarginExtents(_38,s);
-var l=_38.offsetLeft-me.l,t=_38.offsetTop-me.t,p=_38.parentNode;
-if(d.isMoz){
-var sl=parseFloat(s.left),st=parseFloat(s.top);
-if(!isNaN(sl)&&!isNaN(st)){
-l=sl,t=st;
-}else{
-if(p&&p.style){
-var pcs=gcs(p);
-if(pcs.overflow!="visible"){
-var be=d._getBorderExtents(p,pcs);
-l+=be.l,t+=be.t;
-}
-}
-}
-}else{
-if(d.isOpera||(d.isIE>7&&!d.isQuirks)){
-if(p){
-be=d._getBorderExtents(p);
-l-=be.l;
-t-=be.t;
-}
-}
-}
-return {l:l,t:t,w:_38.offsetWidth+me.w,h:_38.offsetHeight+me.h};
-};
-dojo._getContentBox=function(_3a,_3b){
-var s=_3b||gcs(_3a),pe=d._getPadExtents(_3a,s),be=d._getBorderExtents(_3a,s),w=_3a.clientWidth,h;
-if(!w){
-w=_3a.offsetWidth,h=_3a.offsetHeight;
-}else{
-h=_3a.clientHeight,be.w=be.h=0;
-}
-if(d.isOpera){
-pe.l+=be.l;
-pe.t+=be.t;
-}
-return {l:pe.l,t:pe.t,w:w-pe.w-be.w,h:h-pe.h-be.h};
-};
-dojo._getBorderBox=function(_3c,_3d){
-var s=_3d||gcs(_3c),pe=d._getPadExtents(_3c,s),cb=d._getContentBox(_3c,s);
-return {l:cb.l-pe.l,t:cb.t-pe.t,w:cb.w+pe.w,h:cb.h+pe.h};
-};
-dojo._setBox=function(_3e,l,t,w,h,u){
-u=u||"px";
-var s=_3e.style;
-if(!isNaN(l)){
-s.left=l+u;
-}
-if(!isNaN(t)){
-s.top=t+u;
-}
-if(w>=0){
-s.width=w+u;
-}
-if(h>=0){
-s.height=h+u;
-}
-};
-dojo._isButtonTag=function(_3f){
-return _3f.tagName=="BUTTON"||_3f.tagName=="INPUT"&&(_3f.getAttribute("type")||"").toUpperCase()=="BUTTON";
-};
-dojo._usesBorderBox=function(_40){
-var n=_40.tagName;
-return d.boxModel=="border-box"||n=="TABLE"||d._isButtonTag(_40);
-};
-dojo._setContentSize=function(_41,_42,_43,_44){
-if(d._usesBorderBox(_41)){
-var pb=d._getPadBorderExtents(_41,_44);
-if(_42>=0){
-_42+=pb.w;
-}
-if(_43>=0){
-_43+=pb.h;
-}
-}
-d._setBox(_41,NaN,NaN,_42,_43);
-};
-dojo._setMarginBox=function(_45,_46,_47,_48,_49,_4a){
-var s=_4a||gcs(_45),bb=d._usesBorderBox(_45),pb=bb?_4b:d._getPadBorderExtents(_45,s);
-if(d.isWebKit){
-if(d._isButtonTag(_45)){
-var ns=_45.style;
-if(_48>=0&&!ns.width){
-ns.width="4px";
-}
-if(_49>=0&&!ns.height){
-ns.height="4px";
-}
-}
-}
-var mb=d._getMarginExtents(_45,s);
-if(_48>=0){
-_48=Math.max(_48-pb.w-mb.w,0);
-}
-if(_49>=0){
-_49=Math.max(_49-pb.h-mb.h,0);
-}
-d._setBox(_45,_46,_47,_48,_49);
-};
-var _4b={l:0,t:0,w:0,h:0};
-dojo.marginBox=function(_4c,box){
-var n=_5(_4c),s=gcs(n),b=box;
-return !b?d._getMarginBox(n,s):d._setMarginBox(n,b.l,b.t,b.w,b.h,s);
-};
-dojo.contentBox=function(_4d,box){
-var n=_5(_4d),s=gcs(n),b=box;
-return !b?d._getContentBox(n,s):d._setContentSize(n,b.w,b.h,s);
-};
-var _4e=function(_4f,_50){
-if(!(_4f=(_4f||0).parentNode)){
-return 0;
-}
-var val,_51=0,_52=d.body();
-while(_4f&&_4f.style){
-if(gcs(_4f).position=="fixed"){
-return 0;
-}
-val=_4f[_50];
-if(val){
-_51+=val-0;
-if(_4f==_52){
-break;
-}
-}
-_4f=_4f.parentNode;
-}
-return _51;
-};
-dojo._docScroll=function(){
-var n=d.global;
-return "pageXOffset" in n?{x:n.pageXOffset,y:n.pageYOffset}:(n=d.doc.documentElement,n.clientHeight?{x:d._fixIeBiDiScrollLeft(n.scrollLeft),y:n.scrollTop}:(n=d.body(),{x:n.scrollLeft||0,y:n.scrollTop||0}));
-};
-dojo._isBodyLtr=function(){
-return "_bodyLtr" in d?d._bodyLtr:d._bodyLtr=(d.body().dir||d.doc.documentElement.dir||"ltr").toLowerCase()=="ltr";
-};
-dojo._getIeDocumentElementOffset=function(){
-var de=d.doc.documentElement;
-if(d.isIE<8){
-var r=de.getBoundingClientRect();
-var l=r.left,t=r.top;
-if(d.isIE<7){
-l+=de.clientLeft;
-t+=de.clientTop;
-}
-return {x:l<0?0:l,y:t<0?0:t};
-}else{
-return {x:0,y:0};
-}
-};
-dojo._fixIeBiDiScrollLeft=function(_53){
-var dd=d.doc;
-if(d.isIE<8&&!d._isBodyLtr()){
-var de=d.isQuirks?dd.body:dd.documentElement;
-return _53+de.clientWidth-de.scrollWidth;
-}
-return _53;
-};
-dojo._abs=dojo.position=function(_54,_55){
-var db=d.body(),dh=db.parentNode,ret;
-_54=_5(_54);
-if(_54["getBoundingClientRect"]){
-ret=_54.getBoundingClientRect();
-ret={x:ret.left,y:ret.top,w:ret.right-ret.left,h:ret.bottom-ret.top};
-if(d.isIE){
-var _56=d._getIeDocumentElementOffset();
-ret.x-=_56.x+(d.isQuirks?db.clientLeft+db.offsetLeft:0);
-ret.y-=_56.y+(d.isQuirks?db.clientTop+db.offsetTop:0);
-}else{
-if(d.isFF==3){
-var cs=gcs(dh);
-ret.x-=px(dh,cs.marginLeft)+px(dh,cs.borderLeftWidth);
-ret.y-=px(dh,cs.marginTop)+px(dh,cs.borderTopWidth);
-}
-}
-}else{
-ret={x:0,y:0,w:_54.offsetWidth,h:_54.offsetHeight};
-if(_54["offsetParent"]){
-ret.x-=_4e(_54,"scrollLeft");
-ret.y-=_4e(_54,"scrollTop");
-var _57=_54;
-do{
-var n=_57.offsetLeft,t=_57.offsetTop;
-ret.x+=isNaN(n)?0:n;
-ret.y+=isNaN(t)?0:t;
-cs=gcs(_57);
-if(_57!=_54){
-if(d.isMoz){
-ret.x+=2*px(_57,cs.borderLeftWidth);
-ret.y+=2*px(_57,cs.borderTopWidth);
-}else{
-ret.x+=px(_57,cs.borderLeftWidth);
-ret.y+=px(_57,cs.borderTopWidth);
-}
-}
-if(d.isMoz&&cs.position=="static"){
-var _58=_57.parentNode;
-while(_58!=_57.offsetParent){
-var pcs=gcs(_58);
-if(pcs.position=="static"){
-ret.x+=px(_57,pcs.borderLeftWidth);
-ret.y+=px(_57,pcs.borderTopWidth);
-}
-_58=_58.parentNode;
-}
-}
-_57=_57.offsetParent;
-}while((_57!=dh)&&_57);
-}else{
-if(_54.x&&_54.y){
-ret.x+=isNaN(_54.x)?0:_54.x;
-ret.y+=isNaN(_54.y)?0:_54.y;
-}
-}
-}
-if(_55){
-var _59=d._docScroll();
-ret.x+=_59.x;
-ret.y+=_59.y;
-}
-return ret;
-};
-dojo.coords=function(_5a,_5b){
-var n=_5(_5a),s=gcs(n),mb=d._getMarginBox(n,s);
-var abs=d.position(n,_5b);
-mb.x=abs.x;
-mb.y=abs.y;
-return mb;
-};
-var _5c={"class":"className","for":"htmlFor",tabindex:"tabIndex",readonly:"readOnly",colspan:"colSpan",frameborder:"frameBorder",rowspan:"rowSpan",valuetype:"valueType"},_5d={classname:"class",htmlfor:"for",tabindex:"tabIndex",readonly:"readOnly"},_5e={innerHTML:1,className:1,htmlFor:d.isIE,value:1};
-var _5f=function(_60){
-return _5d[_60.toLowerCase()]||_60;
-};
-var _61=function(_62,_63){
-var _64=_62.getAttributeNode&&_62.getAttributeNode(_63);
-return _64&&_64.specified;
-};
-dojo.hasAttr=function(_65,_66){
-var lc=_66.toLowerCase();
-return _5e[_5c[lc]||_66]||_61(_5(_65),_5d[lc]||_66);
-};
-var _67={},_68=0,_69=dojo._scopeName+"attrid",_6a={col:1,colgroup:1,table:1,tbody:1,tfoot:1,thead:1,tr:1,title:1};
-dojo.attr=function(_6b,_6c,_6d){
-_6b=_5(_6b);
-var _6e=arguments.length,_6f;
-if(_6e==2&&typeof _6c!="string"){
-for(var x in _6c){
-d.attr(_6b,x,_6c[x]);
-}
-return _6b;
-}
-var lc=_6c.toLowerCase(),_70=_5c[lc]||_6c,_71=_5e[_70],_72=_5d[lc]||_6c;
-if(_6e==3){
-do{
-if(_70=="style"&&typeof _6d!="string"){
-d.style(_6b,_6d);
-break;
-}
-if(_70=="innerHTML"){
-if(d.isIE&&_6b.tagName.toLowerCase() in _6a){
-d.empty(_6b);
-_6b.appendChild(d._toDom(_6d,_6b.ownerDocument));
-}else{
-_6b[_70]=_6d;
-}
-break;
-}
-if(d.isFunction(_6d)){
-var _73=d.attr(_6b,_69);
-if(!_73){
-_73=_68++;
-d.attr(_6b,_69,_73);
-}
-if(!_67[_73]){
-_67[_73]={};
-}
-var h=_67[_73][_70];
-if(h){
-d.disconnect(h);
-}else{
-try{
-delete _6b[_70];
-}
-catch(e){
-}
-}
-_67[_73][_70]=d.connect(_6b,_70,_6d);
-break;
-}
-if(_71||typeof _6d=="boolean"){
-_6b[_70]=_6d;
-break;
-}
-_6b.setAttribute(_72,_6d);
-}while(false);
-return _6b;
-}
-_6d=_6b[_70];
-if(_71&&typeof _6d!="undefined"){
-return _6d;
-}
-if(_70!="href"&&(typeof _6d=="boolean"||d.isFunction(_6d))){
-return _6d;
-}
-return _61(_6b,_72)?_6b.getAttribute(_72):null;
-};
-dojo.removeAttr=function(_74,_75){
-_5(_74).removeAttribute(_5f(_75));
-};
-dojo.getNodeProp=function(_76,_77){
-_76=_5(_76);
-var lc=_77.toLowerCase(),_78=_5c[lc]||_77;
-if((_78 in _76)&&_78!="href"){
-return _76[_78];
-}
-var _79=_5d[lc]||_77;
-return _61(_76,_79)?_76.getAttribute(_79):null;
-};
-dojo.create=function(tag,_7a,_7b,pos){
-var doc=d.doc;
-if(_7b){
-_7b=_5(_7b);
-doc=_7b.ownerDocument;
-}
-if(typeof tag=="string"){
-tag=doc.createElement(tag);
-}
-if(_7a){
-d.attr(tag,_7a);
-}
-if(_7b){
-d.place(tag,_7b,pos);
-}
-return tag;
-};
-d.empty=d.isIE?function(_7c){
-_7c=_5(_7c);
-for(var c;c=_7c.lastChild;){
-d.destroy(c);
-}
-}:function(_7d){
-_5(_7d).innerHTML="";
-};
-var _7e={option:["select"],tbody:["table"],thead:["table"],tfoot:["table"],tr:["table","tbody"],td:["table","tbody","tr"],th:["table","thead","tr"],legend:["fieldset"],caption:["table"],colgroup:["table"],col:["table","colgroup"],li:["ul"]},_7f=/<\s*([\w\:]+)/,_80={},_81=0,_82="__"+d._scopeName+"ToDomId";
-for(var _83 in _7e){
-var tw=_7e[_83];
-tw.pre=_83=="option"?"<select multiple=\"multiple\">":"<"+tw.join("><")+">";
-tw.post="</"+tw.reverse().join("></")+">";
-}
-d._toDom=function(_84,doc){
-doc=doc||d.doc;
-var _85=doc[_82];
-if(!_85){
-doc[_82]=_85=++_81+"";
-_80[_85]=doc.createElement("div");
-}
-_84+="";
-var _86=_84.match(_7f),tag=_86?_86[1].toLowerCase():"",_87=_80[_85],_88,i,fc,df;
-if(_86&&_7e[tag]){
-_88=_7e[tag];
-_87.innerHTML=_88.pre+_84+_88.post;
-for(i=_88.length;i;--i){
-_87=_87.firstChild;
-}
-}else{
-_87.innerHTML=_84;
-}
-if(_87.childNodes.length==1){
-return _87.removeChild(_87.firstChild);
-}
-df=doc.createDocumentFragment();
-while(fc=_87.firstChild){
-df.appendChild(fc);
-}
-return df;
-};
-var _89="className";
-dojo.hasClass=function(_8a,_8b){
-return ((" "+_5(_8a)[_89]+" ").indexOf(" "+_8b+" ")>=0);
-};
-var _8c=/\s+/,a1=[""],_8d=function(s){
-if(typeof s=="string"||s instanceof String){
-if(s.indexOf(" ")<0){
-a1[0]=s;
-return a1;
-}else{
-return s.split(_8c);
-}
-}
-return s||"";
-};
-dojo.addClass=function(_8e,_8f){
-_8e=_5(_8e);
-_8f=_8d(_8f);
-var cls=_8e[_89],_90;
-cls=cls?" "+cls+" ":" ";
-_90=cls.length;
-for(var i=0,len=_8f.length,c;i<len;++i){
-c=_8f[i];
-if(c&&cls.indexOf(" "+c+" ")<0){
-cls+=c+" ";
-}
-}
-if(_90<cls.length){
-_8e[_89]=cls.substr(1,cls.length-2);
-}
-};
-dojo.removeClass=function(_91,_92){
-_91=_5(_91);
-var cls;
-if(_92!==undefined){
-_92=_8d(_92);
-cls=" "+_91[_89]+" ";
-for(var i=0,len=_92.length;i<len;++i){
-cls=cls.replace(" "+_92[i]+" "," ");
-}
-cls=d.trim(cls);
-}else{
-cls="";
-}
-if(_91[_89]!=cls){
-_91[_89]=cls;
-}
-};
-dojo.toggleClass=function(_93,_94,_95){
-if(_95===undefined){
-_95=!d.hasClass(_93,_94);
-}
-d[_95?"addClass":"removeClass"](_93,_94);
-};
+ var d = dojo;
+ var byId = d.byId;
+
+ var _destroyContainer = null,
+ _destroyDoc;
+ d.addOnWindowUnload(function(){
+ _destroyContainer = null; //prevent IE leak
+ });
+
+/*=====
+ dojo._destroyElement = function(node){
+ // summary:
+ // Existing alias for `dojo.destroy`. Deprecated, will be removed
+ // in 2.0
+ }
+=====*/
+ dojo._destroyElement = dojo.destroy = function(/*String|DomNode*/node){
+ // summary:
+ // Removes a node from its parent, clobbering it and all of its
+ // children.
+ //
+ // description:
+ // Removes a node from its parent, clobbering it and all of its
+ // children. Function only works with DomNodes, and returns nothing.
+ //
+ // node:
+ // A String ID or DomNode reference of the element to be destroyed
+ //
+ // example:
+ // Destroy a node byId:
+ // | dojo.destroy("someId");
+ //
+ // example:
+ // Destroy all nodes in a list by reference:
+ // | dojo.query(".someNode").forEach(dojo.destroy);
+
+ node = byId(node);
+ try{
+ var doc = node.ownerDocument;
+ // cannot use _destroyContainer.ownerDocument since this can throw an exception on IE
+ if(!_destroyContainer || _destroyDoc != doc){
+ _destroyContainer = doc.createElement("div");
+ _destroyDoc = doc;
+ }
+ _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
+ // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
+ _destroyContainer.innerHTML = "";
+ }catch(e){
+ /* squelch */
+ }
+ };
+
+ dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
+ // summary:
+ // Returns true if node is a descendant of ancestor
+ // node: string id or node reference to test
+ // ancestor: string id or node reference of potential parent to test against
+ //
+ // example:
+ // Test is node id="bar" is a descendant of node id="foo"
+ // | if(dojo.isDescendant("bar", "foo")){ ... }
+ try{
+ node = byId(node);
+ ancestor = byId(ancestor);
+ while(node){
+ if(node == ancestor){
+ return true; // Boolean
+ }
+ node = node.parentNode;
+ }
+ }catch(e){ /* squelch, return false */ }
+ return false; // Boolean
+ };
+
+ dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
+ // summary:
+ // Enable or disable selection on a node
+ // node:
+ // id or reference to node
+ // selectable:
+ // state to put the node in. false indicates unselectable, true
+ // allows selection.
+ // example:
+ // Make the node id="bar" unselectable
+ // | dojo.setSelectable("bar");
+ // example:
+ // Make the node id="bar" selectable
+ // | dojo.setSelectable("bar", true);
+ node = byId(node);
+ if(d.isMozilla){
+ node.style.MozUserSelect = selectable ? "" : "none";
+ }else if(d.isKhtml || d.isWebKit){
+ node.style.KhtmlUserSelect = selectable ? "auto" : "none";
+ }else if(d.isIE){
+ var v = (node.unselectable = selectable ? "" : "on");
+ d.query("*", node).forEach("item.unselectable = '"+v+"'");
+ }
+ //FIXME: else? Opera?
+ };
+
+ var _insertBefore = function(/*DomNode*/node, /*DomNode*/ref){
+ var parent = ref.parentNode;
+ if(parent){
+ parent.insertBefore(node, ref);
+ }
+ };
+
+ var _insertAfter = function(/*DomNode*/node, /*DomNode*/ref){
+ // summary:
+ // Try to insert node after ref
+ var parent = ref.parentNode;
+ if(parent){
+ if(parent.lastChild == ref){
+ parent.appendChild(node);
+ }else{
+ parent.insertBefore(node, ref.nextSibling);
+ }
+ }
+ };
+
+ dojo.place = function(node, refNode, position){
+ // summary:
+ // Attempt to insert node into the DOM, choosing from various positioning options.
+ // Returns the first argument resolved to a DOM node.
+ //
+ // node: String|DomNode
+ // id or node reference, or HTML fragment starting with "<" to place relative to refNode
+ //
+ // refNode: String|DomNode
+ // id or node reference to use as basis for placement
+ //
+ // position: String|Number?
+ // string noting the position of node relative to refNode or a
+ // number indicating the location in the childNodes collection of refNode.
+ // Accepted string values are:
+ // | * before
+ // | * after
+ // | * replace
+ // | * only
+ // | * first
+ // | * last
+ // "first" and "last" indicate positions as children of refNode, "replace" replaces refNode,
+ // "only" replaces all children. position defaults to "last" if not specified
+ //
+ // returns: DomNode
+ // Returned values is the first argument resolved to a DOM node.
+ //
+ // .place() is also a method of `dojo.NodeList`, allowing `dojo.query` node lookups.
+ //
+ // example:
+ // Place a node by string id as the last child of another node by string id:
+ // | dojo.place("someNode", "anotherNode");
+ //
+ // example:
+ // Place a node by string id before another node by string id
+ // | dojo.place("someNode", "anotherNode", "before");
+ //
+ // example:
+ // Create a Node, and place it in the body element (last child):
+ // | dojo.place("<div></div>", dojo.body());
+ //
+ // example:
+ // Put a new LI as the first child of a list by id:
+ // | dojo.place("<li></li>", "someUl", "first");
+
+ refNode = byId(refNode);
+ if(typeof node == "string"){ // inline'd type check
+ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : byId(node);
+ }
+ if(typeof position == "number"){ // inline'd type check
+ var cn = refNode.childNodes;
+ if(!cn.length || cn.length <= position){
+ refNode.appendChild(node);
+ }else{
+ _insertBefore(node, cn[position < 0 ? 0 : position]);
+ }
+ }else{
+ switch(position){
+ case "before":
+ _insertBefore(node, refNode);
+ break;
+ case "after":
+ _insertAfter(node, refNode);
+ break;
+ case "replace":
+ refNode.parentNode.replaceChild(node, refNode);
+ break;
+ case "only":
+ d.empty(refNode);
+ refNode.appendChild(node);
+ break;
+ case "first":
+ if(refNode.firstChild){
+ _insertBefore(node, refNode.firstChild);
+ break;
+ }
+ // else fallthrough...
+ default: // aka: last
+ refNode.appendChild(node);
+ }
+ }
+ return node; // DomNode
+ }
+
+ // Box functions will assume this model.
+ // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
+ // Can be set to change behavior of box setters.
+
+ // can be either:
+ // "border-box"
+ // "content-box" (default)
+ dojo.boxModel = "content-box";
+
+ // We punt per-node box mode testing completely.
+ // If anybody cares, we can provide an additional (optional) unit
+ // that overrides existing code to include per-node box sensitivity.
+
+ // Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
+ // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
+ // IIRC, earlier versions of Opera did in fact use border-box.
+ // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
+
+ if(d.isIE /*|| dojo.isOpera*/){
+ // client code may have to adjust if compatMode varies across iframes
+ d.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box";
+ }
+
+ // =============================
+ // Style Functions
+ // =============================
+
+ // getComputedStyle drives most of the style code.
+ // Wherever possible, reuse the returned object.
+ //
+ // API functions below that need to access computed styles accept an
+ // optional computedStyle parameter.
+ // If this parameter is omitted, the functions will call getComputedStyle themselves.
+ // This way, calling code can access computedStyle once, and then pass the reference to
+ // multiple API functions.
+
+/*=====
+ dojo.getComputedStyle = function(node){
+ // summary:
+ // Returns a "computed style" object.
+ //
+ // description:
+ // Gets a "computed style" object which can be used to gather
+ // information about the current state of the rendered node.
+ //
+ // Note that this may behave differently on different browsers.
+ // Values may have different formats and value encodings across
+ // browsers.
+ //
+ // Note also that this method is expensive. Wherever possible,
+ // reuse the returned object.
+ //
+ // Use the dojo.style() method for more consistent (pixelized)
+ // return values.
+ //
+ // node: DOMNode
+ // A reference to a DOM node. Does NOT support taking an
+ // ID string for speed reasons.
+ // example:
+ // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
+ //
+ // example:
+ // Reusing the returned object, avoiding multiple lookups:
+ // | var cs = dojo.getComputedStyle(dojo.byId("someNode"));
+ // | var w = cs.width, h = cs.height;
+ return; // CSS2Properties
+ }
+=====*/
+
+ // Although we normally eschew argument validation at this
+ // level, here we test argument 'node' for (duck)type,
+ // by testing nodeType, ecause 'document' is the 'parentNode' of 'body'
+ // it is frequently sent to this function even
+ // though it is not Element.
+ var gcs;
+ if(d.isWebKit){
+ gcs = function(/*DomNode*/node){
+ var s;
+ if(node.nodeType == 1){
+ var dv = node.ownerDocument.defaultView;
+ s = dv.getComputedStyle(node, null);
+ if(!s && node.style){
+ node.style.display = "";
+ s = dv.getComputedStyle(node, null);
+ }
+ }
+ return s || {};
+ };
+ }else if(d.isIE){
+ gcs = function(node){
+ // IE (as of 7) doesn't expose Element like sane browsers
+ return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {};
+ };
+ }else{
+ gcs = function(node){
+ return node.nodeType == 1 ?
+ node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
+ };
+ }
+ dojo.getComputedStyle = gcs;
+
+ if(!d.isIE){
+ d._toPixelValue = function(element, value){
+ // style values can be floats, client code may want
+ // to round for integer pixels.
+ return parseFloat(value) || 0;
+ };
+ }else{
+ d._toPixelValue = function(element, avalue){
+ if(!avalue){ return 0; }
+ // on IE7, medium is usually 4 pixels
+ if(avalue == "medium"){ return 4; }
+ // style values can be floats, client code may
+ // want to round this value for integer pixels.
+ if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); }
+ with(element){
+ var sLeft = style.left;
+ var rsLeft = runtimeStyle.left;
+ runtimeStyle.left = currentStyle.left;
+ try{
+ // 'avalue' may be incompatible with style.left, which can cause IE to throw
+ // this has been observed for border widths using "thin", "medium", "thick" constants
+ // those particular constants could be trapped by a lookup
+ // but perhaps there are more
+ style.left = avalue;
+ avalue = style.pixelLeft;
+ }catch(e){
+ avalue = 0;
+ }
+ style.left = sLeft;
+ runtimeStyle.left = rsLeft;
+ }
+ return avalue;
+ }
+ }
+ var px = d._toPixelValue;
+
+ // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
+ /*=====
+ dojo._getOpacity = function(node){
+ // summary:
+ // Returns the current opacity of the passed node as a
+ // floating-point value between 0 and 1.
+ // node: DomNode
+ // a reference to a DOM node. Does NOT support taking an
+ // ID string for speed reasons.
+ // returns: Number between 0 and 1
+ return; // Number
+ }
+ =====*/
+
+ var astr = "DXImageTransform.Microsoft.Alpha";
+ var af = function(n, f){
+ try{
+ return n.filters.item(astr);
+ }catch(e){
+ return f ? {} : null;
+ }
+ };
+
+ dojo._getOpacity =
+ d.isIE ? function(node){
+ try{
+ return af(node).Opacity / 100; // Number
+ }catch(e){
+ return 1; // Number
+ }
+ } :
+ function(node){
+ return gcs(node).opacity;
+ };
+
+ /*=====
+ dojo._setOpacity = function(node, opacity){
+ // summary:
+ // set the opacity of the passed node portably. Returns the
+ // new opacity of the node.
+ // node: DOMNode
+ // a reference to a DOM node. Does NOT support taking an
+ // ID string for performance reasons.
+ // opacity: Number
+ // A Number between 0 and 1. 0 specifies transparent.
+ // returns: Number between 0 and 1
+ return; // Number
+ }
+ =====*/
+
+ dojo._setOpacity =
+ d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
+ var ov = opacity * 100, opaque = opacity == 1;
+ node.style.zoom = opaque ? "" : 1;
+
+ if(!af(node)){
+ if(opaque){
+ return opacity;
+ }
+ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")";
+ }else{
+ af(node, 1).Opacity = ov;
+ }
+
+ // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
+ //but still update the opacity value so we can get a correct reading if it is read later.
+ af(node, 1).Enabled = !opaque;
+
+ if(node.nodeName.toLowerCase() == "tr"){
+ d.query("> td", node).forEach(function(i){
+ d._setOpacity(i, opacity);
+ });
+ }
+ return opacity;
+ } :
+ function(node, opacity){
+ return node.style.opacity = opacity;
+ };
+
+ var _pixelNamesCache = {
+ left: true, top: true
+ };
+ var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
+ var _toStyleValue = function(node, type, value){
+ type = type.toLowerCase(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile!
+ if(d.isIE){
+ if(value == "auto"){
+ if(type == "height"){ return node.offsetHeight; }
+ if(type == "width"){ return node.offsetWidth; }
+ }
+ if(type == "fontweight"){
+ switch(value){
+ case 700: return "bold";
+ case 400:
+ default: return "normal";
+ }
+ }
+ }
+ if(!(type in _pixelNamesCache)){
+ _pixelNamesCache[type] = _pixelRegExp.test(type);
+ }
+ return _pixelNamesCache[type] ? px(node, value) : value;
+ };
+
+ var _floatStyle = d.isIE ? "styleFloat" : "cssFloat",
+ _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle }
+ ;
+
+ // public API
+
+ dojo.style = function( /*DomNode|String*/ node,
+ /*String?|Object?*/ style,
+ /*String?*/ value){
+ // summary:
+ // Accesses styles on a node. If 2 arguments are
+ // passed, acts as a getter. If 3 arguments are passed, acts
+ // as a setter.
+ // description:
+ // Getting the style value uses the computed style for the node, so the value
+ // will be a calculated value, not just the immediate node.style value.
+ // Also when getting values, use specific style names,
+ // like "borderBottomWidth" instead of "border" since compound values like
+ // "border" are not necessarily reflected as expected.
+ // If you want to get node dimensions, use `dojo.marginBox()`,
+ // `dojo.contentBox()` or `dojo.position()`.
+ // node:
+ // id or reference to node to get/set style for
+ // style:
+ // the style property to set in DOM-accessor format
+ // ("borderWidth", not "border-width") or an object with key/value
+ // pairs suitable for setting each property.
+ // value:
+ // If passed, sets value on the node for style, handling
+ // cross-browser concerns. When setting a pixel value,
+ // be sure to include "px" in the value. For instance, top: "200px".
+ // Otherwise, in some cases, some browsers will not apply the style.
+ // example:
+ // Passing only an ID or node returns the computed style object of
+ // the node:
+ // | dojo.style("thinger");
+ // example:
+ // Passing a node and a style property returns the current
+ // normalized, computed value for that property:
+ // | dojo.style("thinger", "opacity"); // 1 by default
+ //
+ // example:
+ // Passing a node, a style property, and a value changes the
+ // current display of the node and returns the new computed value
+ // | dojo.style("thinger", "opacity", 0.5); // == 0.5
+ //
+ // example:
+ // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
+ // | dojo.style("thinger", {
+ // | "opacity": 0.5,
+ // | "border": "3px solid black",
+ // | "height": "300px"
+ // | });
+ //
+ // example:
+ // When the CSS style property is hyphenated, the JavaScript property is camelCased.
+ // font-size becomes fontSize, and so on.
+ // | dojo.style("thinger",{
+ // | fontSize:"14pt",
+ // | letterSpacing:"1.2em"
+ // | });
+ //
+ // example:
+ // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
+ // dojo.style() on every element of the list. See: `dojo.query()` and `dojo.NodeList()`
+ // | dojo.query(".someClassName").style("visibility","hidden");
+ // | // or
+ // | dojo.query("#baz > div").style({
+ // | opacity:0.75,
+ // | fontSize:"13pt"
+ // | });
+
+ var n = byId(node), args = arguments.length, op = (style == "opacity");
+ style = _floatAliases[style] || style;
+ if(args == 3){
+ return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
+ }
+ if(args == 2 && op){
+ return d._getOpacity(n);
+ }
+ var s = gcs(n);
+ if(args == 2 && typeof style != "string"){ // inline'd type check
+ for(var x in style){
+ d.style(node, x, style[x]);
+ }
+ return s;
+ }
+ return (args == 1) ? s : _toStyleValue(n, style, s[style] || n.style[style]); /* CSS2Properties||String||Number */
+ }
+
+ // =============================
+ // Box Functions
+ // =============================
+
+ dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // Returns object with special values specifically useful for node
+ // fitting.
+ // description:
+ // Returns an object with `w`, `h`, `l`, `t` properties:
+ // | l/t = left/top padding (respectively)
+ // | w = the total of the left and right padding
+ // | h = the total of the top and bottom padding
+ // If 'node' has position, l/t forms the origin for child nodes.
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ l = px(n, s.paddingLeft),
+ t = px(n, s.paddingTop);
+ return {
+ l: l,
+ t: t,
+ w: l+px(n, s.paddingRight),
+ h: t+px(n, s.paddingBottom)
+ };
+ }
+
+ dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // returns an object with properties useful for noting the border
+ // dimensions.
+ // description:
+ // * l/t = the sum of left/top border (respectively)
+ // * w = the sum of the left and right border
+ // * h = the sum of the top and bottom border
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ ne = "none",
+ s = computedStyle||gcs(n),
+ bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
+ bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
+ return {
+ l: bl,
+ t: bt,
+ w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
+ h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
+ };
+ }
+
+ dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // Returns object with properties useful for box fitting with
+ // regards to padding.
+ // description:
+ // * l/t = the sum of left/top padding and left/top border (respectively)
+ // * w = the sum of the left and right padding and border
+ // * h = the sum of the top and bottom padding and border
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ p = d._getPadExtents(n, s),
+ b = d._getBorderExtents(n, s);
+ return {
+ l: p.l + b.l,
+ t: p.t + b.t,
+ w: p.w + b.w,
+ h: p.h + b.h
+ };
+ }
+
+ dojo._getMarginExtents = function(n, computedStyle){
+ // summary:
+ // returns object with properties useful for box fitting with
+ // regards to box margins (i.e., the outer-box).
+ //
+ // * l/t = marginLeft, marginTop, respectively
+ // * w = total width, margin inclusive
+ // * h = total height, margin inclusive
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ l = px(n, s.marginLeft),
+ t = px(n, s.marginTop),
+ r = px(n, s.marginRight),
+ b = px(n, s.marginBottom);
+ if(d.isWebKit && (s.position != "absolute")){
+ // FIXME: Safari's version of the computed right margin
+ // is the space between our right edge and the right edge
+ // of our offsetParent.
+ // What we are looking for is the actual margin value as
+ // determined by CSS.
+ // Hack solution is to assume left/right margins are the same.
+ r = l;
+ }
+ return {
+ l: l,
+ t: t,
+ w: l+r,
+ h: t+b
+ };
+ }
+
+ // Box getters work in any box context because offsetWidth/clientWidth
+ // are invariant wrt box context
+ //
+ // They do *not* work for display: inline objects that have padding styles
+ // because the user agent ignores padding (it's bogus styling in any case)
+ //
+ // Be careful with IMGs because they are inline or block depending on
+ // browser and browser mode.
+
+ // Although it would be easier to read, there are not separate versions of
+ // _getMarginBox for each browser because:
+ // 1. the branching is not expensive
+ // 2. factoring the shared code wastes cycles (function call overhead)
+ // 3. duplicating the shared code wastes bytes
+
+ dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
+ // summary:
+ // returns an object that encodes the width, height, left and top
+ // positions of the node's margin box.
+ var s = computedStyle || gcs(node), me = d._getMarginExtents(node, s);
+ var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode;
+ if(d.isMoz){
+ // Mozilla:
+ // If offsetParent has a computed overflow != visible, the offsetLeft is decreased
+ // by the parent's border.
+ // We don't want to compute the parent's style, so instead we examine node's
+ // computed left/top which is more stable.
+ var sl = parseFloat(s.left), st = parseFloat(s.top);
+ if(!isNaN(sl) && !isNaN(st)){
+ l = sl, t = st;
+ }else{
+ // If child's computed left/top are not parseable as a number (e.g. "auto"), we
+ // have no choice but to examine the parent's computed style.
+ if(p && p.style){
+ var pcs = gcs(p);
+ if(pcs.overflow != "visible"){
+ var be = d._getBorderExtents(p, pcs);
+ l += be.l, t += be.t;
+ }
+ }
+ }
+ }else if(d.isOpera || (d.isIE > 7 && !d.isQuirks)){
+ // On Opera and IE 8, offsetLeft/Top includes the parent's border
+ if(p){
+ be = d._getBorderExtents(p);
+ l -= be.l;
+ t -= be.t;
+ }
+ }
+ return {
+ l: l,
+ t: t,
+ w: node.offsetWidth + me.w,
+ h: node.offsetHeight + me.h
+ };
+ }
+
+ dojo._getContentBox = function(node, computedStyle){
+ // summary:
+ // Returns an object that encodes the width, height, left and top
+ // positions of the node's content box, irrespective of the
+ // current box model.
+
+ // clientWidth/Height are important since the automatically account for scrollbars
+ // fallback to offsetWidth/Height for special cases (see #3378)
+ var s = computedStyle || gcs(node),
+ pe = d._getPadExtents(node, s),
+ be = d._getBorderExtents(node, s),
+ w = node.clientWidth,
+ h
+ ;
+ if(!w){
+ w = node.offsetWidth, h = node.offsetHeight;
+ }else{
+ h = node.clientHeight, be.w = be.h = 0;
+ }
+ // On Opera, offsetLeft includes the parent's border
+ if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
+ return {
+ l: pe.l,
+ t: pe.t,
+ w: w - pe.w - be.w,
+ h: h - pe.h - be.h
+ };
+ }
+
+ dojo._getBorderBox = function(node, computedStyle){
+ var s = computedStyle || gcs(node),
+ pe = d._getPadExtents(node, s),
+ cb = d._getContentBox(node, s)
+ ;
+ return {
+ l: cb.l - pe.l,
+ t: cb.t - pe.t,
+ w: cb.w + pe.w,
+ h: cb.h + pe.h
+ };
+ }
+
+ // Box setters depend on box context because interpretation of width/height styles
+ // vary wrt box context.
+ //
+ // The value of dojo.boxModel is used to determine box context.
+ // dojo.boxModel can be set directly to change behavior.
+ //
+ // Beware of display: inline objects that have padding styles
+ // because the user agent ignores padding (it's a bogus setup anyway)
+ //
+ // Be careful with IMGs because they are inline or block depending on
+ // browser and browser mode.
+ //
+ // Elements other than DIV may have special quirks, like built-in
+ // margins or padding, or values not detectable via computedStyle.
+ // In particular, margins on TABLE do not seems to appear
+ // at all in computedStyle on Mozilla.
+
+ dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
+ // summary:
+ // sets width/height/left/top in the current (native) box-model
+ // dimentions. Uses the unit passed in u.
+ // node:
+ // DOM Node reference. Id string not supported for performance
+ // reasons.
+ // l:
+ // left offset from parent.
+ // t:
+ // top offset from parent.
+ // w:
+ // width in current box model.
+ // h:
+ // width in current box model.
+ // u:
+ // unit measure to use for other measures. Defaults to "px".
+ u = u || "px";
+ var s = node.style;
+ if(!isNaN(l)){ s.left = l + u; }
+ if(!isNaN(t)){ s.top = t + u; }
+ if(w >= 0){ s.width = w + u; }
+ if(h >= 0){ s.height = h + u; }
+ }
+
+ dojo._isButtonTag = function(/*DomNode*/node) {
+ // summary:
+ // True if the node is BUTTON or INPUT.type="button".
+ return node.tagName == "BUTTON"
+ || node.tagName=="INPUT" && (node.getAttribute("type")||'').toUpperCase() == "BUTTON"; // boolean
+ }
+
+ dojo._usesBorderBox = function(/*DomNode*/node){
+ // summary:
+ // True if the node uses border-box layout.
+
+ // We could test the computed style of node to see if a particular box
+ // has been specified, but there are details and we choose not to bother.
+
+ // TABLE and BUTTON (and INPUT type=button) are always border-box by default.
+ // If you have assigned a different box to either one via CSS then
+ // box functions will break.
+
+ var n = node.tagName;
+ return d.boxModel=="border-box" || n=="TABLE" || d._isButtonTag(node); // boolean
+ }
+
+ dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
+ // summary:
+ // Sets the size of the node's contents, irrespective of margins,
+ // padding, or borders.
+ if(d._usesBorderBox(node)){
+ var pb = d._getPadBorderExtents(node, computedStyle);
+ if(widthPx >= 0){ widthPx += pb.w; }
+ if(heightPx >= 0){ heightPx += pb.h; }
+ }
+ d._setBox(node, NaN, NaN, widthPx, heightPx);
+ }
+
+ dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx,
+ /*Number?*/widthPx, /*Number?*/heightPx,
+ /*Object*/computedStyle){
+ // summary:
+ // sets the size of the node's margin box and placement
+ // (left/top), irrespective of box model. Think of it as a
+ // passthrough to dojo._setBox that handles box-model vagaries for
+ // you.
+
+ var s = computedStyle || gcs(node),
+ // Some elements have special padding, margin, and box-model settings.
+ // To use box functions you may need to set padding, margin explicitly.
+ // Controlling box-model is harder, in a pinch you might set dojo.boxModel.
+ bb = d._usesBorderBox(node),
+ pb = bb ? _nilExtents : d._getPadBorderExtents(node, s)
+ ;
+ if(d.isWebKit){
+ // on Safari (3.1.2), button nodes with no explicit size have a default margin
+ // setting an explicit size eliminates the margin.
+ // We have to swizzle the width to get correct margin reading.
+ if(d._isButtonTag(node)){
+ var ns = node.style;
+ if(widthPx >= 0 && !ns.width) { ns.width = "4px"; }
+ if(heightPx >= 0 && !ns.height) { ns.height = "4px"; }
+ }
+ }
+ var mb = d._getMarginExtents(node, s);
+ if(widthPx >= 0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
+ if(heightPx >= 0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
+ d._setBox(node, leftPx, topPx, widthPx, heightPx);
+ }
+
+ var _nilExtents = { l:0, t:0, w:0, h:0 };
+
+ // public API
+
+ dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
+ // summary:
+ // Getter/setter for the margin-box of node.
+ // description:
+ // Getter/setter for the margin-box of node.
+ // Returns an object in the expected format of box (regardless
+ // if box is passed). The object might look like:
+ // `{ l: 50, t: 200, w: 300: h: 150 }`
+ // for a node offset from its parent 50px to the left, 200px from
+ // the top with a margin width of 300px and a margin-height of
+ // 150px.
+ // node:
+ // id or reference to DOM Node to get/set box for
+ // box:
+ // If passed, denotes that dojo.marginBox() should
+ // update/set the margin box for node. Box is an object in the
+ // above format. All properties are optional if passed.
+ // example:
+ // Retrieve the marginbox of a passed node
+ // | var box = dojo.marginBox("someNodeId");
+ // | console.dir(box);
+ //
+ // example:
+ // Set a node's marginbox to the size of another node
+ // | var box = dojo.marginBox("someNodeId");
+ // | dojo.marginBox("someOtherNode", box);
+
+ var n = byId(node), s = gcs(n), b = box;
+ return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
+ }
+
+ dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
+ // summary:
+ // Getter/setter for the content-box of node.
+ // description:
+ // Returns an object in the expected format of box (regardless if box is passed).
+ // The object might look like:
+ // `{ l: 50, t: 200, w: 300: h: 150 }`
+ // for a node offset from its parent 50px to the left, 200px from
+ // the top with a content width of 300px and a content-height of
+ // 150px. Note that the content box may have a much larger border
+ // or margin box, depending on the box model currently in use and
+ // CSS values set/inherited for node.
+ // While the getter will return top and left values, the
+ // setter only accepts setting the width and height.
+ // node:
+ // id or reference to DOM Node to get/set box for
+ // box:
+ // If passed, denotes that dojo.contentBox() should
+ // update/set the content box for node. Box is an object in the
+ // above format, but only w (width) and h (height) are supported.
+ // All properties are optional if passed.
+ var n = byId(node), s = gcs(n), b = box;
+ return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
+ }
+
+ // =============================
+ // Positioning
+ // =============================
+
+ var _sumAncestorProperties = function(node, prop){
+ if(!(node = (node||0).parentNode)){return 0}
+ var val, retVal = 0, _b = d.body();
+ while(node && node.style){
+ if(gcs(node).position == "fixed"){
+ return 0;
+ }
+ val = node[prop];
+ if(val){
+ retVal += val - 0;
+ // opera and khtml #body & #html has the same values, we only
+ // need one value
+ if(node == _b){ break; }
+ }
+ node = node.parentNode;
+ }
+ return retVal; // integer
+ }
+
+ dojo._docScroll = function(){
+ var n = d.global;
+ return "pageXOffset" in n? { x:n.pageXOffset, y:n.pageYOffset } :
+ (n=d.doc.documentElement, n.clientHeight? { x:d._fixIeBiDiScrollLeft(n.scrollLeft), y:n.scrollTop } :
+ (n=d.body(), { x:n.scrollLeft||0, y:n.scrollTop||0 }));
+ };
+
+ dojo._isBodyLtr = function(){
+ return "_bodyLtr" in d? d._bodyLtr :
+ d._bodyLtr = (d.body().dir || d.doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean
+ }
+
+ dojo._getIeDocumentElementOffset = function(){
+ // summary:
+ // returns the offset in x and y from the document body to the
+ // visual edge of the page
+ // description:
+ // The following values in IE contain an offset:
+ // | event.clientX
+ // | event.clientY
+ // | node.getBoundingClientRect().left
+ // | node.getBoundingClientRect().top
+ // But other position related values do not contain this offset,
+ // such as node.offsetLeft, node.offsetTop, node.style.left and
+ // node.style.top. The offset is always (2, 2) in LTR direction.
+ // When the body is in RTL direction, the offset counts the width
+ // of left scroll bar's width. This function computes the actual
+ // offset.
+
+ //NOTE: assumes we're being called in an IE browser
+
+ var de = d.doc.documentElement; // only deal with HTML element here, _abs handles body/quirks
+
+ if(d.isIE < 8){
+ var r = de.getBoundingClientRect(); // works well for IE6+
+ //console.debug('rect left,top = ' + r.left+','+r.top + ', html client left/top = ' + de.clientLeft+','+de.clientTop + ', rtl = ' + (!d._isBodyLtr()) + ', quirks = ' + d.isQuirks);
+ var l = r.left,
+ t = r.top;
+ if(d.isIE < 7){
+ l += de.clientLeft; // scrollbar size in strict/RTL, or,
+ t += de.clientTop; // HTML border size in strict
+ }
+ return {
+ x: l < 0? 0 : l, // FRAME element border size can lead to inaccurate negative values
+ y: t < 0? 0 : t
+ };
+ }else{
+ return {
+ x: 0,
+ y: 0
+ };
+ }
+
+ };
+
+ dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
+ // In RTL direction, scrollLeft should be a negative value, but IE < 8
+ // returns a positive one. All codes using documentElement.scrollLeft
+ // must call this function to fix this error, otherwise the position
+ // will offset to right when there is a horizontal scrollbar.
+
+ var dd = d.doc;
+ if(d.isIE < 8 && !d._isBodyLtr()){
+ var de = d.isQuirks ? dd.body : dd.documentElement;
+ return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
+ }
+ return scrollLeft; // Integer
+ }
+
+ // FIXME: need a setter for coords or a moveTo!!
+ dojo._abs = dojo.position = function(/*DomNode*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Gets the position and size of the passed element relative to
+ // the viewport (if includeScroll==false), or relative to the
+ // document root (if includeScroll==true).
+ //
+ // description:
+ // Returns an object of the form:
+ // { x: 100, y: 300, w: 20, h: 15 }
+ // If includeScroll==true, the x and y values will include any
+ // document offsets that may affect the position relative to the
+ // viewport.
+ // Uses the border-box model (inclusive of border and padding but
+ // not margin). Does not act as a setter.
+
+ var db = d.body(), dh = db.parentNode, ret;
+ node = byId(node);
+ if(node["getBoundingClientRect"]){
+ // IE6+, FF3+, super-modern WebKit, and Opera 9.6+ all take this branch
+ ret = node.getBoundingClientRect();
+ ret = { x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top };
+ if(d.isIE){
+ // On IE there's a 2px offset that we need to adjust for, see _getIeDocumentElementOffset()
+ var offset = d._getIeDocumentElementOffset();
+
+ // fixes the position in IE, quirks mode
+ ret.x -= offset.x + (d.isQuirks ? db.clientLeft+db.offsetLeft : 0);
+ ret.y -= offset.y + (d.isQuirks ? db.clientTop+db.offsetTop : 0);
+ }else if(d.isFF == 3){
+ // In FF3 you have to subtract the document element margins.
+ // Fixed in FF3.5 though.
+ var cs = gcs(dh);
+ ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth);
+ ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth);
+ }
+ }else{
+ // FF2 and older WebKit
+ ret = {
+ x: 0,
+ y: 0,
+ w: node.offsetWidth,
+ h: node.offsetHeight
+ };
+ if(node["offsetParent"]){
+ ret.x -= _sumAncestorProperties(node, "scrollLeft");
+ ret.y -= _sumAncestorProperties(node, "scrollTop");
+
+ var curnode = node;
+ do{
+ var n = curnode.offsetLeft,
+ t = curnode.offsetTop;
+ ret.x += isNaN(n) ? 0 : n;
+ ret.y += isNaN(t) ? 0 : t;
+
+ cs = gcs(curnode);
+ if(curnode != node){
+ if(d.isMoz){
+ // tried left+right with differently sized left/right borders
+ // it really is 2xleft border in FF, not left+right, even in RTL!
+ ret.x += 2 * px(curnode,cs.borderLeftWidth);
+ ret.y += 2 * px(curnode,cs.borderTopWidth);
+ }else{
+ ret.x += px(curnode, cs.borderLeftWidth);
+ ret.y += px(curnode, cs.borderTopWidth);
+ }
+ }
+ // static children in a static div in FF2 are affected by the div's border as well
+ // but offsetParent will skip this div!
+ if(d.isMoz && cs.position=="static"){
+ var parent=curnode.parentNode;
+ while(parent!=curnode.offsetParent){
+ var pcs=gcs(parent);
+ if(pcs.position=="static"){
+ ret.x += px(curnode,pcs.borderLeftWidth);
+ ret.y += px(curnode,pcs.borderTopWidth);
+ }
+ parent=parent.parentNode;
+ }
+ }
+ curnode = curnode.offsetParent;
+ }while((curnode != dh) && curnode);
+ }else if(node.x && node.y){
+ ret.x += isNaN(node.x) ? 0 : node.x;
+ ret.y += isNaN(node.y) ? 0 : node.y;
+ }
+ }
+ // account for document scrolling
+ // if offsetParent is used, ret value already includes scroll position
+ // so we may have to actually remove that value if !includeScroll
+ if(includeScroll){
+ var scroll = d._docScroll();
+ ret.x += scroll.x;
+ ret.y += scroll.y;
+ }
+
+ return ret; // Object
+ }
+
+ dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Deprecated: Use position() for border-box x/y/w/h
+ // or marginBox() for margin-box w/h/l/t.
+ // Returns an object representing a node's size and position.
+ //
+ // description:
+ // Returns an object that measures margin-box (w)idth/(h)eight
+ // and absolute position x/y of the border-box. Also returned
+ // is computed (l)eft and (t)op values in pixels from the
+ // node's offsetParent as returned from marginBox().
+ // Return value will be in the form:
+ //| { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }
+ // Does not act as a setter. If includeScroll is passed, the x and
+ // y params are affected as one would expect in dojo.position().
+ var n = byId(node), s = gcs(n), mb = d._getMarginBox(n, s);
+ var abs = d.position(n, includeScroll);
+ mb.x = abs.x;
+ mb.y = abs.y;
+ return mb;
+ }
+
+ // =============================
+ // Element attribute Functions
+ // =============================
+
+ // dojo.attr() should conform to http://www.w3.org/TR/DOM-Level-2-Core/
+
+ var _propNames = {
+ // properties renamed to avoid clashes with reserved words
+ "class": "className",
+ "for": "htmlFor",
+ // properties written as camelCase
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ colspan: "colSpan",
+ frameborder: "frameBorder",
+ rowspan: "rowSpan",
+ valuetype: "valueType"
+ },
+ _attrNames = {
+ // original attribute names
+ classname: "class",
+ htmlfor: "for",
+ // for IE
+ tabindex: "tabIndex",
+ readonly: "readOnly"
+ },
+ _forcePropNames = {
+ innerHTML: 1,
+ className: 1,
+ htmlFor: d.isIE,
+ value: 1
+ };
+
+ var _fixAttrName = function(/*String*/ name){
+ return _attrNames[name.toLowerCase()] || name;
+ };
+
+ var _hasAttr = function(node, name){
+ var attr = node.getAttributeNode && node.getAttributeNode(name);
+ return attr && attr.specified; // Boolean
+ };
+
+ // There is a difference in the presence of certain properties and their default values
+ // between browsers. For example, on IE "disabled" is present on all elements,
+ // but it is value is "false"; "tabIndex" of <div> returns 0 by default on IE, yet other browsers
+ // can return -1.
+
+ dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
+ // summary:
+ // Returns true if the requested attribute is specified on the
+ // given element, and false otherwise.
+ // node:
+ // id or reference to the element to check
+ // name:
+ // the name of the attribute
+ // returns:
+ // true if the requested attribute is specified on the
+ // given element, and false otherwise
+ var lc = name.toLowerCase();
+ return _forcePropNames[_propNames[lc] || name] || _hasAttr(byId(node), _attrNames[lc] || name); // Boolean
+ }
+
+ var _evtHdlrMap = {}, _ctr = 0,
+ _attrId = dojo._scopeName + "attrid",
+ // the next dictionary lists elements with read-only innerHTML on IE
+ _roInnerHtml = {col: 1, colgroup: 1,
+ // frameset: 1, head: 1, html: 1, style: 1,
+ table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1};
+
+ dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
+ // summary:
+ // Gets or sets an attribute on an HTML element.
+ // description:
+ // Handles normalized getting and setting of attributes on DOM
+ // Nodes. If 2 arguments are passed, and a the second argumnt is a
+ // string, acts as a getter.
+ //
+ // If a third argument is passed, or if the second argument is a
+ // map of attributes, acts as a setter.
+ //
+ // When passing functions as values, note that they will not be
+ // directly assigned to slots on the node, but rather the default
+ // behavior will be removed and the new behavior will be added
+ // using `dojo.connect()`, meaning that event handler properties
+ // will be normalized and that some caveats with regards to
+ // non-standard behaviors for onsubmit apply. Namely that you
+ // should cancel form submission using `dojo.stopEvent()` on the
+ // passed event object instead of returning a boolean value from
+ // the handler itself.
+ // node:
+ // id or reference to the element to get or set the attribute on
+ // name:
+ // the name of the attribute to get or set.
+ // value:
+ // The value to set for the attribute
+ // returns:
+ // when used as a getter, the value of the requested attribute
+ // or null if that attribute does not have a specified or
+ // default value;
+ //
+ // when used as a setter, the DOM node
+ //
+ // example:
+ // | // get the current value of the "foo" attribute on a node
+ // | dojo.attr(dojo.byId("nodeId"), "foo");
+ // | // or we can just pass the id:
+ // | dojo.attr("nodeId", "foo");
+ //
+ // example:
+ // | // use attr() to set the tab index
+ // | dojo.attr("nodeId", "tabIndex", 3);
+ // |
+ //
+ // example:
+ // Set multiple values at once, including event handlers:
+ // | dojo.attr("formId", {
+ // | "foo": "bar",
+ // | "tabIndex": -1,
+ // | "method": "POST",
+ // | "onsubmit": function(e){
+ // | // stop submitting the form. Note that the IE behavior
+ // | // of returning true or false will have no effect here
+ // | // since our handler is connect()ed to the built-in
+ // | // onsubmit behavior and so we need to use
+ // | // dojo.stopEvent() to ensure that the submission
+ // | // doesn't proceed.
+ // | dojo.stopEvent(e);
+ // |
+ // | // submit the form with Ajax
+ // | dojo.xhrPost({ form: "formId" });
+ // | }
+ // | });
+ //
+ // example:
+ // Style is s special case: Only set with an object hash of styles
+ // | dojo.attr("someNode",{
+ // | id:"bar",
+ // | style:{
+ // | width:"200px", height:"100px", color:"#000"
+ // | }
+ // | });
+ //
+ // example:
+ // Again, only set style as an object hash of styles:
+ // | var obj = { color:"#fff", backgroundColor:"#000" };
+ // | dojo.attr("someNode", "style", obj);
+ // |
+ // | // though shorter to use `dojo.style()` in this case:
+ // | dojo.style("someNode", obj);
+
+ node = byId(node);
+ var args = arguments.length, prop;
+ if(args == 2 && typeof name != "string"){ // inline'd type check
+ // the object form of setter: the 2nd argument is a dictionary
+ for(var x in name){
+ d.attr(node, x, name[x]);
+ }
+ return node; // DomNode
+ }
+ var lc = name.toLowerCase(),
+ propName = _propNames[lc] || name,
+ forceProp = _forcePropNames[propName],
+ attrName = _attrNames[lc] || name;
+ if(args == 3){
+ // setter
+ do{
+ if(propName == "style" && typeof value != "string"){ // inline'd type check
+ // special case: setting a style
+ d.style(node, value);
+ break;
+ }
+ if(propName == "innerHTML"){
+ // special case: assigning HTML
+ if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){
+ d.empty(node);
+ node.appendChild(d._toDom(value, node.ownerDocument));
+ }else{
+ node[propName] = value;
+ }
+ break;
+ }
+ if(d.isFunction(value)){
+ // special case: assigning an event handler
+ // clobber if we can
+ var attrId = d.attr(node, _attrId);
+ if(!attrId){
+ attrId = _ctr++;
+ d.attr(node, _attrId, attrId);
+ }
+ if(!_evtHdlrMap[attrId]){
+ _evtHdlrMap[attrId] = {};
+ }
+ var h = _evtHdlrMap[attrId][propName];
+ if(h){
+ d.disconnect(h);
+ }else{
+ try{
+ delete node[propName];
+ }catch(e){}
+ }
+ // ensure that event objects are normalized, etc.
+ _evtHdlrMap[attrId][propName] = d.connect(node, propName, value);
+ break;
+ }
+ if(forceProp || typeof value == "boolean"){
+ // special case: forcing assignment to the property
+ // special case: setting boolean to a property instead of attribute
+ node[propName] = value;
+ break;
+ }
+ // node's attribute
+ node.setAttribute(attrName, value);
+ }while(false);
+ return node; // DomNode
+ }
+ // getter
+ // should we access this attribute via a property or
+ // via getAttribute()?
+ value = node[propName];
+ if(forceProp && typeof value != "undefined"){
+ // node's property
+ return value; // Anything
+ }
+ if(propName != "href" && (typeof value == "boolean" || d.isFunction(value))){
+ // node's property
+ return value; // Anything
+ }
+ // node's attribute
+ // we need _hasAttr() here to guard against IE returning a default value
+ return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
+ }
+
+ dojo.removeAttr = function(/*DomNode|String*/ node, /*String*/ name){
+ // summary:
+ // Removes an attribute from an HTML element.
+ // node:
+ // id or reference to the element to remove the attribute from
+ // name:
+ // the name of the attribute to remove
+ byId(node).removeAttribute(_fixAttrName(name));
+ }
+
+ dojo.getNodeProp = function(/*DomNode|String*/ node, /*String*/ name){
+ // summary:
+ // Returns an effective value of a property or an attribute.
+ // node:
+ // id or reference to the element to remove the attribute from
+ // name:
+ // the name of the attribute
+ node = byId(node);
+ var lc = name.toLowerCase(),
+ propName = _propNames[lc] || name;
+ if((propName in node) && propName != "href"){
+ // node's property
+ return node[propName]; // Anything
+ }
+ // node's attribute
+ var attrName = _attrNames[lc] || name;
+ return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
+ }
+
+ dojo.create = function(tag, attrs, refNode, pos){
+ // summary:
+ // Create an element, allowing for optional attribute decoration
+ // and placement.
+ //
+ // description:
+ // A DOM Element creation function. A shorthand method for creating a node or
+ // a fragment, and allowing for a convenient optional attribute setting step,
+ // as well as an optional DOM placement reference.
+ //|
+ // Attributes are set by passing the optional object through `dojo.attr`.
+ // See `dojo.attr` for noted caveats and nuances, and API if applicable.
+ //|
+ // Placement is done via `dojo.place`, assuming the new node to be the action
+ // node, passing along the optional reference node and position.
+ //
+ // tag: String|DomNode
+ // A string of the element to create (eg: "div", "a", "p", "li", "script", "br"),
+ // or an existing DOM node to process.
+ //
+ // attrs: Object
+ // An object-hash of attributes to set on the newly created node.
+ // Can be null, if you don't want to set any attributes/styles.
+ // See: `dojo.attr` for a description of available attributes.
+ //
+ // refNode: String?|DomNode?
+ // Optional reference node. Used by `dojo.place` to place the newly created
+ // node somewhere in the dom relative to refNode. Can be a DomNode reference
+ // or String ID of a node.
+ //
+ // pos: String?
+ // Optional positional reference. Defaults to "last" by way of `dojo.place`,
+ // though can be set to "first","after","before","last", "replace" or "only"
+ // to further control the placement of the new node relative to the refNode.
+ // 'refNode' is required if a 'pos' is specified.
+ //
+ // returns: DomNode
+ //
+ // example:
+ // Create a DIV:
+ // | var n = dojo.create("div");
+ //
+ // example:
+ // Create a DIV with content:
+ // | var n = dojo.create("div", { innerHTML:"<p>hi</p>" });
+ //
+ // example:
+ // Place a new DIV in the BODY, with no attributes set
+ // | var n = dojo.create("div", null, dojo.body());
+ //
+ // example:
+ // Create an UL, and populate it with LI's. Place the list as the first-child of a
+ // node with id="someId":
+ // | var ul = dojo.create("ul", null, "someId", "first");
+ // | var items = ["one", "two", "three", "four"];
+ // | dojo.forEach(items, function(data){
+ // | dojo.create("li", { innerHTML: data }, ul);
+ // | });
+ //
+ // example:
+ // Create an anchor, with an href. Place in BODY:
+ // | dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body());
+ //
+ // example:
+ // Create a `dojo.NodeList()` from a new element (for syntatic sugar):
+ // | dojo.query(dojo.create('div'))
+ // | .addClass("newDiv")
+ // | .onclick(function(e){ console.log('clicked', e.target) })
+ // | .place("#someNode"); // redundant, but cleaner.
+
+ var doc = d.doc;
+ if(refNode){
+ refNode = byId(refNode);
+ doc = refNode.ownerDocument;
+ }
+ if(typeof tag == "string"){ // inline'd type check
+ tag = doc.createElement(tag);
+ }
+ if(attrs){ d.attr(tag, attrs); }
+ if(refNode){ d.place(tag, refNode, pos); }
+ return tag; // DomNode
+ }
+
+ /*=====
+ dojo.empty = function(node){
+ // summary:
+ // safely removes all children of the node.
+ // node: DOMNode|String
+ // a reference to a DOM node or an id.
+ // example:
+ // Destroy node's children byId:
+ // | dojo.empty("someId");
+ //
+ // example:
+ // Destroy all nodes' children in a list by reference:
+ // | dojo.query(".someNode").forEach(dojo.empty);
+ }
+ =====*/
+
+ d.empty =
+ d.isIE ? function(node){
+ node = byId(node);
+ for(var c; c = node.lastChild;){ // intentional assignment
+ d.destroy(c);
+ }
+ } :
+ function(node){
+ byId(node).innerHTML = "";
+ };
+
+ /*=====
+ dojo._toDom = function(frag, doc){
+ // summary:
+ // instantiates an HTML fragment returning the corresponding DOM.
+ // frag: String
+ // the HTML fragment
+ // doc: DocumentNode?
+ // optional document to use when creating DOM nodes, defaults to
+ // dojo.doc if not specified.
+ // returns: DocumentFragment
+ //
+ // example:
+ // Create a table row:
+ // | var tr = dojo._toDom("<tr><td>First!</td></tr>");
+ }
+ =====*/
+
+ // support stuff for dojo._toDom
+ var tagWrap = {
+ option: ["select"],
+ tbody: ["table"],
+ thead: ["table"],
+ tfoot: ["table"],
+ tr: ["table", "tbody"],
+ td: ["table", "tbody", "tr"],
+ th: ["table", "thead", "tr"],
+ legend: ["fieldset"],
+ caption: ["table"],
+ colgroup: ["table"],
+ col: ["table", "colgroup"],
+ li: ["ul"]
+ },
+ reTag = /<\s*([\w\:]+)/,
+ masterNode = {}, masterNum = 0,
+ masterName = "__" + d._scopeName + "ToDomId";
+
+ // generate start/end tag strings to use
+ // for the injection for each special tag wrap case.
+ for(var param in tagWrap){
+ var tw = tagWrap[param];
+ tw.pre = param == "option" ? '<select multiple="multiple">' : "<" + tw.join("><") + ">";
+ tw.post = "</" + tw.reverse().join("></") + ">";
+ // the last line is destructive: it reverses the array,
+ // but we don't care at this point
+ }
+
+ d._toDom = function(frag, doc){
+ // summary:
+ // converts HTML string into DOM nodes.
+
+ doc = doc || d.doc;
+ var masterId = doc[masterName];
+ if(!masterId){
+ doc[masterName] = masterId = ++masterNum + "";
+ masterNode[masterId] = doc.createElement("div");
+ }
+
+ // make sure the frag is a string.
+ frag += "";
+
+ // find the starting tag, and get node wrapper
+ var match = frag.match(reTag),
+ tag = match ? match[1].toLowerCase() : "",
+ master = masterNode[masterId],
+ wrap, i, fc, df;
+ if(match && tagWrap[tag]){
+ wrap = tagWrap[tag];
+ master.innerHTML = wrap.pre + frag + wrap.post;
+ for(i = wrap.length; i; --i){
+ master = master.firstChild;
+ }
+ }else{
+ master.innerHTML = frag;
+ }
+
+ // one node shortcut => return the node itself
+ if(master.childNodes.length == 1){
+ return master.removeChild(master.firstChild); // DOMNode
+ }
+
+ // return multiple nodes as a document fragment
+ df = doc.createDocumentFragment();
+ while(fc = master.firstChild){ // intentional assignment
+ df.appendChild(fc);
+ }
+ return df; // DOMNode
+ }
+
+ // =============================
+ // (CSS) Class Functions
+ // =============================
+ var _className = "className";
+
+ dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
+ // summary:
+ // Returns whether or not the specified classes are a portion of the
+ // class list currently applied to the node.
+ //
+ // node:
+ // String ID or DomNode reference to check the class for.
+ //
+ // classStr:
+ // A string class name to look for.
+ //
+ // example:
+ // Do something if a node with id="someNode" has class="aSillyClassName" present
+ // | if(dojo.hasClass("someNode","aSillyClassName")){ ... }
+
+ return ((" "+ byId(node)[_className] +" ").indexOf(" " + classStr + " ") >= 0); // Boolean
+ };
+
+ var spaces = /\s+/, a1 = [""],
+ str2array = function(s){
+ if(typeof s == "string" || s instanceof String){
+ if(s.indexOf(" ") < 0){
+ a1[0] = s;
+ return a1;
+ }else{
+ return s.split(spaces);
+ }
+ }
+ // assumed to be an array
+ return s || "";
+ };
+
+ dojo.addClass = function(/*DomNode|String*/node, /*String|Array*/classStr){
+ // summary:
+ // Adds the specified classes to the end of the class list on the
+ // passed node. Will not re-apply duplicate classes.
+ //
+ // node:
+ // String ID or DomNode reference to add a class string too
+ //
+ // classStr:
+ // A String class name to add, or several space-separated class names,
+ // or an array of class names.
+ //
+ // example:
+ // Add a class to some node:
+ // | dojo.addClass("someNode", "anewClass");
+ //
+ // example:
+ // Add two classes at once:
+ // | dojo.addClass("someNode", "firstClass secondClass");
+ //
+ // example:
+ // Add two classes at once (using array):
+ // | dojo.addClass("someNode", ["firstClass", "secondClass"]);
+ //
+ // example:
+ // Available in `dojo.NodeList` for multiple additions
+ // | dojo.query("ul > li").addClass("firstLevel");
+
+ node = byId(node);
+ classStr = str2array(classStr);
+ var cls = node[_className], oldLen;
+ cls = cls ? " " + cls + " " : " ";
+ oldLen = cls.length;
+ for(var i = 0, len = classStr.length, c; i < len; ++i){
+ c = classStr[i];
+ if(c && cls.indexOf(" " + c + " ") < 0){
+ cls += c + " ";
+ }
+ }
+ if(oldLen < cls.length){
+ node[_className] = cls.substr(1, cls.length - 2);
+ }
+ };
+
+ dojo.removeClass = function(/*DomNode|String*/node, /*String|Array?*/classStr){
+ // summary:
+ // Removes the specified classes from node. No `dojo.hasClass`
+ // check is required.
+ //
+ // node:
+ // String ID or DomNode reference to remove the class from.
+ //
+ // classStr:
+ // An optional String class name to remove, or several space-separated
+ // class names, or an array of class names. If omitted, all class names
+ // will be deleted.
+ //
+ // example:
+ // Remove a class from some node:
+ // | dojo.removeClass("someNode", "firstClass");
+ //
+ // example:
+ // Remove two classes from some node:
+ // | dojo.removeClass("someNode", "firstClass secondClass");
+ //
+ // example:
+ // Remove two classes from some node (using array):
+ // | dojo.removeClass("someNode", ["firstClass", "secondClass"]);
+ //
+ // example:
+ // Remove all classes from some node:
+ // | dojo.removeClass("someNode");
+ //
+ // example:
+ // Available in `dojo.NodeList()` for multiple removal
+ // | dojo.query(".foo").removeClass("foo");
+
+ node = byId(node);
+ var cls;
+ if(classStr !== undefined){
+ classStr = str2array(classStr);
+ cls = " " + node[_className] + " ";
+ for(var i = 0, len = classStr.length; i < len; ++i){
+ cls = cls.replace(" " + classStr[i] + " ", " ");
+ }
+ cls = d.trim(cls);
+ }else{
+ cls = "";
+ }
+ if(node[_className] != cls){ node[_className] = cls; }
+ };
+
+ dojo.toggleClass = function(/*DomNode|String*/node, /*String|Array*/classStr, /*Boolean?*/condition){
+ // summary:
+ // Adds a class to node if not present, or removes if present.
+ // Pass a boolean condition if you want to explicitly add or remove.
+ // condition:
+ // If passed, true means to add the class, false means to remove.
+ //
+ // example:
+ // | dojo.toggleClass("someNode", "hovered");
+ //
+ // example:
+ // Forcefully add a class
+ // | dojo.toggleClass("someNode", "hovered", true);
+ //
+ // example:
+ // Available in `dojo.NodeList()` for multiple toggles
+ // | dojo.query(".toggleMe").toggleClass("toggleMe");
+
+ if(condition === undefined){
+ condition = !d.hasClass(node, classStr);
+ }
+ d[condition ? "addClass" : "removeClass"](node, classStr);
+ };
+
})();
+
}