a:59:{s:9:"#provides";s:4:"dojo";s:9:"#resource";s:13:"_base/html.js";s:9:"#requires";a:1:{i:0;a:2:{i:0;s:6:"common";i:1;s:15:"dojo._base.lang";}}s:9:"dojo.byId";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:2:"id";a:2:{s:4:"type";s:14:"String|DOMNode";s:7:"summary";s:67:"A string to match an HTML id attribute or a reference to a DOM Node";}s:3:"doc";a:3:{s:4:"type";s:8:"Document";s:8:"optional";b:1;s:7:"summary";s:126:"Document to work in. Defaults to the current value of dojo.doc. Can be used to retrieve node references from other documents.";}}s:6:"source";s:2289:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile");";s:7:"summary";s:171:"Returns DOM node with matching `id` attribute or `null` if not found, similar to "$" function in another library. If `id` is a DomNode, this function is a no-op.";s:7:"returns";s:7:"DomNode";s:8:"examples";a:2:{i:0;s:49:"Look up a node by ID: var n = dojo.byId("foo");";i:1;s:53:"Check if a node exists. if(dojo.byId("bar")){ ... }";}}s:20:"dojo._destroyElement";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"node";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:83:" // summary: Existing alias for `dojo.destroy`. Deprecated, will be removed in 2.0";s:7:"summary";s:69:"Existing alias for `dojo.destroy`. Deprecated, will be removed in 2.0";s:7:"private";b:1;}s:13:"dojo.boxModel";a:1:{s:7:"summary";s:0:"";}s:21:"dojo.getComputedStyle";a:7:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"node";a:2:{s:4:"type";s:7:"DOMNode";s:7:"summary";s:82:"A reference to a DOM node. Does NOT support taking an ID string for speed reasons.";}}s:6:"source";s:27:" return; // CSS2Properties";s:7:"summary";s:44:"Returns a "computed style" object.";s:11:"description";s:414:"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.";s:7:"returns";s:14:"CSS2Properties";s:8:"examples";a:2:{i:0;s:55:" dojo.getComputedStyle(dojo.byId('foo')).borderWidth;";i:1;s:146:"Reusing the returned object, avoiding multiple lookups: var cs = dojo.getComputedStyle(dojo.byId("someNode")); var w = cs.width, h = cs.height;";}}s:16:"dojo._getOpacity";a:7:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"node";a:2:{s:4:"type";s:7:"DomNode";s:7:"summary";s:82:"a reference to a DOM node. Does NOT support taking an ID string for speed reasons.";}}s:6:"source";s:20:" return; // Number";s:7:"summary";s:89:"Returns the current opacity of the passed node as a floating-point value between 0 and 1.";s:14:"return_summary";s:22:"Number between 0 and 1";s:7:"returns";s:6:"Number";s:7:"private";b:1;}s:16:"dojo._setOpacity";a:7:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:2:{s:4:"type";s:7:"DOMNode";s:7:"summary";s:88:"a reference to a DOM node. Does NOT support taking an ID string for performance reasons.";}s:7:"opacity";a:2:{s:4:"type";s:6:"Number";s:7:"summary";s:50:"A Number between 0 and 1. 0 specifies transparent.";}}s:6:"source";s:20:" return; // Number";s:7:"summary";s:81:"set the opacity of the passed node portably. Returns the new opacity of the node.";s:14:"return_summary";s:22:"Number between 0 and 1";s:7:"returns";s:6:"Number";s:7:"private";b:1;}s:13:"_floatAliases";a:3:{s:4:"type";s:6:"Object";s:7:"private";b:1;s:7:"summary";s:0:"";}s:12:"_roInnerHtml";a:3:{s:4:"type";s:6:"Object";s:7:"private";b:1;s:7:"summary";s:0:"";}s:10:"dojo.empty";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"node";a:2:{s:4:"type";s:14:"DOMNode|String";s:7:"summary";s:35:"a reference to a DOM node or an id.";}}s:6:"source";s:345:" // 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);";s:7:"summary";s:40:"safely removes all children of the node.";s:8:"examples";a:2:{i:0;s:53:"Destroy node's children byId: dojo.empty("someId");";i:1;s:98:"Destroy all nodes' children in a list by reference: dojo.query(".someNode").forEach(dojo.empty);";}}s:5:"reTag";a:1:{s:7:"summary";s:0:"";}s:10:"masterNode";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:0:"";}s:10:"masterName";a:1:{s:7:"summary";s:0:"";}s:6:"tw.pre";a:1:{s:7:"summary";s:0:"";}s:7:"tw.post";a:1:{s:7:"summary";s:0:"";}s:12:"dojo.destroy";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"node";a:2:{s:4:"type";s:14:"String|DomNode";s:7:"summary";s:63:"A String ID or DomNode reference of the element to be destroyed";}}s:6:"source";s:442:" node = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ }";s:7:"summary";s:70:"Removes a node from its parent, clobbering it and all of its children.";s:11:"description";s:126:"Removes a node from its parent, clobbering it and all of its children. Function only works with DomNodes, and returns nothing.";s:8:"examples";a:2:{i:0;s:46:"Destroy a node byId: dojo.destroy("someId");";i:1;s:90:"Destroy all nodes in a list by reference: dojo.query(".someNode").forEach(dojo.destroy);";}}s:17:"dojo.isDescendant";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:35:"string id or node reference to test";}s:8:"ancestor";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:63:"string id or node reference of potential parent to test against";}}s:6:"source";s:243:" try{ node = d.byId(node); ancestor = d.byId(ancestor); while(node){ if(node === ancestor){ return true; // Boolean } node = node.parentNode; } }catch(e){ /* squelch, return false */ } return false; // Boolean";s:7:"summary";s:48:"Returns true if node is a descendant of ancestor";s:7:"returns";s:7:"Boolean";}s:18:"dojo.setSelectable";a:4:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:23:"id or reference to node";}s:10:"selectable";a:2:{s:4:"type";s:7:"Boolean";s:7:"summary";s:78:"state to put the node in. false indicates unselectable, true allows selection.";}}s:6:"source";s:546:" node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //FIXME: else? Opera?";s:7:"summary";s:37:"enable or disable selection on a node";}s:10:"dojo.place";a:7:{s:4:"type";s:8:"Function";s:10:"parameters";a:3:{s:4:"node";a:2:{s:4:"type";s:14:"String|DomNode";s:7:"summary";s:98:"id or node reference, or HTML fragment starting with "<" to place relative to refNode";}s:7:"refNode";a:2:{s:4:"type";s:14:"String|DomNode";s:7:"summary";s:50:"id or node reference to use as basis for placement";}s:8:"position";a:3:{s:4:"type";s:13:"String|Number";s:8:"optional";b:1;s:7:"summary";s:431:"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";}}s:6:"source";s:924:" refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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";s:7:"summary";s:124:"Attempt to insert node into the DOM, choosing from various positioning options. Returns true if successful, false otherwise.";s:14:"return_summary";s:152:"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.";s:7:"returns";s:7:"DomNode";s:8:"examples";a:4:{i:0;s:115:"Place a node by string id as the last child of another node by string id: dojo.place("someNode", "anotherNode");";i:1;s:110:"Place a node by string id before another node by string id dojo.place("someNode", "anotherNode", "before");";i:2;s:109:"Create a Node, and place it in the body element (last child): dojo.place(dojo.create('div'), dojo.body());";i:3;s:101:"Put a new LI as the first child of a list by id: dojo.place(dojo.create('li'), "someUl", "first");";}}s:18:"dojo._toPixelValue";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:3:{s:7:"element";a:1:{s:4:"type";s:0:"";}s:5:"value";a:1:{s:4:"type";s:0:"";}s:6:"avalue";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:866:" 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;";s:7:"returns";s:30:"DomNode|Boolean|CSS2Properties";s:7:"private";b:1;s:7:"summary";s:0:"";}s:10:"dojo.style";a:7:{s:4:"type";s:8:"Function";s:10:"parameters";a:3:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:44:"id or reference to node to get/set style for";}s:5:"style";a:3:{s:8:"optional";b:1;s:4:"type";s:14:"String?|Object";s:7:"summary";s:174:"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.";}s:5:"value";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"String";s:7:"summary";s:258:"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.";}}s:6:"source";s:520:" var n = d.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 && !d.isString(style)){ 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 */";s:7:"summary";s:116:"Accesses styles on a node. If 2 arguments are passed, acts as a getter. If 3 arguments are passed, acts as a setter.";s:11:"description";s:398:"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() or dojo.contentBox().";s:7:"returns";s:37:"Number|CSS2Properties||String||Number";s:8:"examples";a:6:{i:0;s:98:"Passing only an ID or node returns the computed style object of the node: dojo.style("thinger");";i:1;s:153:"Passing a node and a style property returns the current normalized, computed value for that property: dojo.style("thinger", "opacity"); // 1 by default";i:2;s:171:"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";i:3;s:229:"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" });";i:4;s:193:"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" });";i:5;s:313:"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" });";}}s:19:"dojo._getPadExtents";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:1:"n";a:1:{s:4:"type";s:7:"DomNode";}s:13:"computedStyle";a:1:{s:4:"type";s:6:"Object";}}s:6:"source";s:192:" 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) };";s:7:"summary";s:419:"Returns object with special values specifically useful for node fitting. * l/t = left/top padding (respectively) * w = the total of the left and right padding * h = the total of the top and bottom padding If 'node' has position, l/t forms the origin for child nodes. The w/h are used for calculating boxes. Normally application code will not need to invoke this directly, and will use the ...box... functions instead.";s:7:"private";b:1;}s:22:"dojo._getBorderExtents";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:1:"n";a:1:{s:4:"type";s:7:"DomNode";}s:13:"computedStyle";a:1:{s:4:"type";s:6:"Object";}}s:6:"source";s:359:" 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) };";s:7:"summary";s:363:"returns an object with properties useful for noting the border dimensions. * l/t = the sum of left/top border (respectively) * w = the sum of the left and right border * h = the sum of the top and bottom border The w/h are used for calculating boxes. Normally application code will not need to invoke this directly, and will use the ...box... functions instead.";s:7:"private";b:1;}s:25:"dojo._getPadBorderExtents";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:1:"n";a:1:{s:4:"type";s:7:"DomNode";}s:13:"computedStyle";a:1:{s:4:"type";s:6:"Object";}}s:6:"source";s:186:" 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 };";s:7:"summary";s:412:"Returns object with properties useful for box fitting with regards to padding. * l/t = the sum of left/top padding and left/top border (respectively) * w = the sum of the left and right padding and border * h = the sum of the top and bottom padding and border The w/h are used for calculating boxes. Normally application code will not need to invoke this directly, and will use the ...box... functions instead.";s:7:"private";b:1;}s:22:"dojo._getMarginExtents";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:1:"n";a:1:{s:4:"type";s:0:"";}s:13:"computedStyle";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:570:" 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 };";s:7:"summary";s:374:"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.";s:7:"private";b:1;}s:18:"dojo._getMarginBox";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:1:{s:4:"type";s:7:"DomNode";}s:13:"computedStyle";a:1:{s:4:"type";s:6:"Object";}}s:6:"source";s:1263:" var s = computedStyle || gcs(node), me = d._getMarginExtents(node, s); var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); return { l: l, t: t, w: node.offsetWidth + me.w, h: node.offsetHeight + me.h };";s:7:"summary";s:98:"returns an object that encodes the width, height, left and top positions of the node's margin box.";s:7:"private";b:1;}s:19:"dojo._getContentBox";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:1:{s:4:"type";s:0:"";}s:13:"computedStyle";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:26488:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); (function(){ var d = dojo; //>>excludeEnd("webkitMobile"); var _destroyContainer = null; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); //>>excludeEnd("webkitMobile"); 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 = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ } }; dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: string id or node reference to test // ancestor: string id or node reference of potential parent to test against try{ node = d.byId(node); ancestor = d.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. node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //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 true if successful, false otherwise. // // 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(dojo.create('div'), dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place(dojo.create('li'), "someUl", "first"); refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE /*|| dojo.isOpera*/){ var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE < 6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support? } //>>excludeEnd("webkitMobile"); // ============================= // 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isWebKit){ //>>excludeEnd("webkitMobile"); 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 || {}; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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) : {}; }; } //>>excludeEnd("webkitMobile"); dojo.getComputedStyle = gcs; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(!d.isIE){ //>>excludeEnd("webkitMobile"); d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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; } } //>>excludeEnd("webkitMobile"); 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 } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } } //>>excludeEnd("webkitMobile"); dojo._getOpacity = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : //>>excludeEnd("webkitMobile"); 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(/*DomNode*/node, /*Number*/opacity){ var ov = opacity * 100; node.style.zoom = 1.0; // 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 = !(opacity == 1); if(!af(node)){ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : //>>excludeEnd("webkitMobile"); 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! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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"; } } } //>>excludeEnd("webkitMobile"); 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() or // dojo.contentBox(). // 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 = d.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 && !d.isString(style)){ 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. // // * 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. // // * 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. // // * 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); 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 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; //>>excludeEnd("webkitMobile"); return { l: pe.l, t: pe.t, w: w - pe.w - be.w, h: h - pe.h - be.h };";s:7:"returns";s:68:"DomNode|Boolean|CSS2Properties|Number|CSS2Properties||String||Number";s:7:"private";b:1;s:7:"summary";s:0:"";}s:18:"dojo._getBorderBox";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:1:{s:4:"type";s:0:"";}s:13:"computedStyle";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:206:" 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 };";s:7:"private";b:1;s:7:"summary";s:0:"";}s:12:"dojo._setBox";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:6:{s:4:"node";a:2:{s:4:"type";s:7:"DomNode";s:7:"summary";s:68:"DOM Node reference. Id string not supported for performance reasons.";}s:1:"l";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"Number";s:7:"summary";s:34:"optional. left offset from parent.";}s:1:"t";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"Number";s:7:"summary";s:33:"optional. top offset from parent.";}s:1:"w";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"Number";s:7:"summary";s:37:"optional. width in current box model.";}s:1:"h";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"Number";s:7:"summary";s:37:"optional. width in current box model.";}s:1:"u";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"String";s:7:"summary";s:77:"optional. unit measure to use for other measures. Defaults to "px".";}}s:6:"source";s:174:" 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; }";s:7:"summary";s:99:"sets width/height/left/top in the current (native) box-model dimentions. Uses the unit passed in u.";s:7:"private";b:1;}s:17:"dojo._isButtonTag";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"node";a:1:{s:4:"type";s:7:"DomNode";}}s:6:"source";s:129:" return node.tagName == "BUTTON" || node.tagName=="INPUT" && node.getAttribute("type").toUpperCase() == "BUTTON"; // boolean";s:7:"summary";s:60:"True if the node is BUTTON or INPUT.type="button".";s:7:"private";b:1;}s:19:"dojo._usesBorderBox";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"node";a:1:{s:4:"type";s:7:"DomNode";}}s:6:"source";s:29049:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); (function(){ var d = dojo; //>>excludeEnd("webkitMobile"); var _destroyContainer = null; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); //>>excludeEnd("webkitMobile"); 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 = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ } }; dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: string id or node reference to test // ancestor: string id or node reference of potential parent to test against try{ node = d.byId(node); ancestor = d.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. node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //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 true if successful, false otherwise. // // 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(dojo.create('div'), dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place(dojo.create('li'), "someUl", "first"); refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE /*|| dojo.isOpera*/){ var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE < 6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support? } //>>excludeEnd("webkitMobile"); // ============================= // 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isWebKit){ //>>excludeEnd("webkitMobile"); 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 || {}; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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) : {}; }; } //>>excludeEnd("webkitMobile"); dojo.getComputedStyle = gcs; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(!d.isIE){ //>>excludeEnd("webkitMobile"); d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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; } } //>>excludeEnd("webkitMobile"); 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 } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } } //>>excludeEnd("webkitMobile"); dojo._getOpacity = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : //>>excludeEnd("webkitMobile"); 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(/*DomNode*/node, /*Number*/opacity){ var ov = opacity * 100; node.style.zoom = 1.0; // 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 = !(opacity == 1); if(!af(node)){ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : //>>excludeEnd("webkitMobile"); 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! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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"; } } } //>>excludeEnd("webkitMobile"); 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() or // dojo.contentBox(). // 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 = d.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 && !d.isString(style)){ 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. // // * 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. // // * 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. // // * 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); 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 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; //>>excludeEnd("webkitMobile"); 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: optional. left offset from parent. // t: optional. top offset from parent. // w: optional. width in current box model. // h: optional. width in current box model. // u: optional. unit measure to use for other measures. Defaults to "px". u = u || "px"; 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";s:7:"returns";s:76:"DomNode|Boolean|CSS2Properties|Number|CSS2Properties||String||Number|boolean";s:7:"private";b:1;s:7:"summary";s:0:"";}s:20:"dojo._setContentSize";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:4:{s:4:"node";a:1:{s:4:"type";s:7:"DomNode";}s:7:"widthPx";a:1:{s:4:"type";s:6:"Number";}s:8:"heightPx";a:1:{s:4:"type";s:6:"Number";}s:13:"computedStyle";a:1:{s:4:"type";s:6:"Object";}}s:6:"source";s:220:" 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);";s:7:"summary";s:83:"Sets the size of the node's contents, irrespective of margins, padding, or borders.";s:7:"private";b:1;}s:18:"dojo._setMarginBox";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:6:{s:4:"node";a:1:{s:4:"type";s:7:"DomNode";}s:6:"leftPx";a:2:{s:8:"optional";b:1;s:4:"type";s:6:"Number";}s:5:"topPx";a:2:{s:8:"optional";b:1;s:4:"type";s:6:"Number";}s:7:"widthPx";a:2:{s:8:"optional";b:1;s:4:"type";s:6:"Number";}s:8:"heightPx";a:2:{s:8:"optional";b:1;s:4:"type";s:6:"Number";}s:13:"computedStyle";a:1:{s:4:"type";s:6:"Object";}}s:6:"source";s:989:" 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);";s:7:"summary";s:177:"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.";s:7:"private";b:1;}s:14:"dojo.marginBox";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:46:"id or reference to DOM Node to get/set box for";}s:3:"box";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"Object";s:7:"summary";s:160:"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.";}}s:6:"source";s:135:" var n = d.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";s:7:"summary";s:41:"Getter/setter for the margin-box of node.";s:11:"description";s:272:"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.";s:7:"returns";s:6:"Object";}s:15:"dojo.contentBox";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:46:"id or reference to DOM Node to get/set box for";}s:3:"box";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"Object";s:7:"summary";s:162:"If passed, denotes that dojo.contentBox() should update/set the content box for node. Box is an object in the above format. All properties are optional if passed.";}}s:6:"source";s:128:" var n = d.byId(node), s = gcs(n), b = box; return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object";s:7:"summary";s:42:"Getter/setter for the content-box of node.";s:11:"description";s:428:"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.";s:7:"returns";s:6:"Object";}s:15:"dojo._docScroll";a:4:{s:4:"type";s:8:"Function";s:6:"source";s:236:" var _b = d.body(), _w = d.global, de = d.doc.documentElement; return { y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0), x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0) };";s:7:"private";b:1;s:7:"summary";s:0:"";}s:15:"dojo._isBodyLtr";a:5:{s:4:"type";s:8:"Function";s:6:"source";s:33917:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); (function(){ var d = dojo; //>>excludeEnd("webkitMobile"); var _destroyContainer = null; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); //>>excludeEnd("webkitMobile"); 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 = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ } }; dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: string id or node reference to test // ancestor: string id or node reference of potential parent to test against try{ node = d.byId(node); ancestor = d.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. node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //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 true if successful, false otherwise. // // 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(dojo.create('div'), dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place(dojo.create('li'), "someUl", "first"); refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE /*|| dojo.isOpera*/){ var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE < 6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support? } //>>excludeEnd("webkitMobile"); // ============================= // 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isWebKit){ //>>excludeEnd("webkitMobile"); 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 || {}; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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) : {}; }; } //>>excludeEnd("webkitMobile"); dojo.getComputedStyle = gcs; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(!d.isIE){ //>>excludeEnd("webkitMobile"); d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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; } } //>>excludeEnd("webkitMobile"); 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 } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } } //>>excludeEnd("webkitMobile"); dojo._getOpacity = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : //>>excludeEnd("webkitMobile"); 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(/*DomNode*/node, /*Number*/opacity){ var ov = opacity * 100; node.style.zoom = 1.0; // 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 = !(opacity == 1); if(!af(node)){ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : //>>excludeEnd("webkitMobile"); 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! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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"; } } } //>>excludeEnd("webkitMobile"); 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() or // dojo.contentBox(). // 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 = d.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 && !d.isString(style)){ 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. // // * 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. // // * 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. // // * 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); 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 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; //>>excludeEnd("webkitMobile"); 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: optional. left offset from parent. // t: optional. top offset from parent. // w: optional. width in current box model. // h: optional. width in current box model. // u: optional. unit measure to use for other measures. Defaults to "px". u = u || "px"; 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: // 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. var n = d.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. // 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. All properties are optional if passed. var n = d.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 _b = d.body(), _w = d.global, de = d.doc.documentElement; return { y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0), x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0) }; }; dojo._isBodyLtr = function(){ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values return ("_bodyLtr" in d) ? d._bodyLtr : d._bodyLtr = gcs(d.body()).direction == "ltr"; // Boolean ";s:7:"returns";s:91:"DomNode|Boolean|CSS2Properties|Number|CSS2Properties||String||Number|boolean|Object|integer";s:7:"private";b:1;s:7:"summary";s:0:"";}s:32:"dojo._getIeDocumentElementOffset";a:5:{s:4:"type";s:8:"Function";s:6:"source";s:35095:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); (function(){ var d = dojo; //>>excludeEnd("webkitMobile"); var _destroyContainer = null; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); //>>excludeEnd("webkitMobile"); 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 = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ } }; dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: string id or node reference to test // ancestor: string id or node reference of potential parent to test against try{ node = d.byId(node); ancestor = d.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. node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //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 true if successful, false otherwise. // // 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(dojo.create('div'), dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place(dojo.create('li'), "someUl", "first"); refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE /*|| dojo.isOpera*/){ var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE < 6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support? } //>>excludeEnd("webkitMobile"); // ============================= // 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isWebKit){ //>>excludeEnd("webkitMobile"); 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 || {}; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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) : {}; }; } //>>excludeEnd("webkitMobile"); dojo.getComputedStyle = gcs; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(!d.isIE){ //>>excludeEnd("webkitMobile"); d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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; } } //>>excludeEnd("webkitMobile"); 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 } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } } //>>excludeEnd("webkitMobile"); dojo._getOpacity = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : //>>excludeEnd("webkitMobile"); 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(/*DomNode*/node, /*Number*/opacity){ var ov = opacity * 100; node.style.zoom = 1.0; // 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 = !(opacity == 1); if(!af(node)){ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : //>>excludeEnd("webkitMobile"); 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! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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"; } } } //>>excludeEnd("webkitMobile"); 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() or // dojo.contentBox(). // 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 = d.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 && !d.isString(style)){ 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. // // * 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. // // * 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. // // * 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); 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 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; //>>excludeEnd("webkitMobile"); 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: optional. left offset from parent. // t: optional. top offset from parent. // w: optional. width in current box model. // h: optional. width in current box model. // u: optional. unit measure to use for other measures. Defaults to "px". u = u || "px"; 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: // 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. var n = d.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. // 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. All properties are optional if passed. var n = d.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 _b = d.body(), _w = d.global, de = d.doc.documentElement; return { y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0), x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0) }; }; dojo._isBodyLtr = function(){ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values return ("_bodyLtr" in d) ? d._bodyLtr : d._bodyLtr = gcs(d.body()).direction == "ltr"; // Boolean } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); dojo._getIeDocumentElementOffset = function(){ // summary // The following values in IE contain an offset: // event.clientX // event.clientY // node.getBoundingClientRect().left // node.getBoundingClientRect().top // But other position related values do not contain this offset, such as // node.offsetLeft, node.offsetTop, node.style.left and node.style.top. // The offset is always (2, 2) in LTR direction. When the body is in RTL // direction, the offset counts the width of left scroll bar's width. // This function computes the actual offset. //NOTE: assumes we're being called in an IE browser var de = d.doc.documentElement; //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement; if(d.isIE < 7){ return { x: d._isBodyLtr() || window.parent == window ? de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft, y: de.clientTop }; // Object }else if(d.isIE < 8){ return {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}; }else{ return { x: 0, y: 0 }; }";s:7:"returns";s:91:"DomNode|Boolean|CSS2Properties|Number|CSS2Properties||String||Number|boolean|Object|integer";s:7:"private";b:1;s:7:"summary";s:0:"";}s:25:"dojo._fixIeBiDiScrollLeft";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:10:"scrollLeft";a:1:{s:4:"type";s:7:"Integer";}}s:6:"source";s:35805:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); (function(){ var d = dojo; //>>excludeEnd("webkitMobile"); var _destroyContainer = null; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); //>>excludeEnd("webkitMobile"); 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 = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ } }; dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: string id or node reference to test // ancestor: string id or node reference of potential parent to test against try{ node = d.byId(node); ancestor = d.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. node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //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 true if successful, false otherwise. // // 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(dojo.create('div'), dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place(dojo.create('li'), "someUl", "first"); refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE /*|| dojo.isOpera*/){ var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE < 6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support? } //>>excludeEnd("webkitMobile"); // ============================= // 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isWebKit){ //>>excludeEnd("webkitMobile"); 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 || {}; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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) : {}; }; } //>>excludeEnd("webkitMobile"); dojo.getComputedStyle = gcs; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(!d.isIE){ //>>excludeEnd("webkitMobile"); d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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; } } //>>excludeEnd("webkitMobile"); 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 } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } } //>>excludeEnd("webkitMobile"); dojo._getOpacity = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : //>>excludeEnd("webkitMobile"); 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(/*DomNode*/node, /*Number*/opacity){ var ov = opacity * 100; node.style.zoom = 1.0; // 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 = !(opacity == 1); if(!af(node)){ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : //>>excludeEnd("webkitMobile"); 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! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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"; } } } //>>excludeEnd("webkitMobile"); 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() or // dojo.contentBox(). // 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 = d.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 && !d.isString(style)){ 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. // // * 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. // // * 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. // // * 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); 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 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; //>>excludeEnd("webkitMobile"); 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: optional. left offset from parent. // t: optional. top offset from parent. // w: optional. width in current box model. // h: optional. width in current box model. // u: optional. unit measure to use for other measures. Defaults to "px". u = u || "px"; 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: // 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. var n = d.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. // 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. All properties are optional if passed. var n = d.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 _b = d.body(), _w = d.global, de = d.doc.documentElement; return { y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0), x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0) }; }; dojo._isBodyLtr = function(){ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values return ("_bodyLtr" in d) ? d._bodyLtr : d._bodyLtr = gcs(d.body()).direction == "ltr"; // Boolean } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); dojo._getIeDocumentElementOffset = function(){ // summary // The following values in IE contain an offset: // event.clientX // event.clientY // node.getBoundingClientRect().left // node.getBoundingClientRect().top // But other position related values do not contain this offset, such as // node.offsetLeft, node.offsetTop, node.style.left and node.style.top. // The offset is always (2, 2) in LTR direction. When the body is in RTL // direction, the offset counts the width of left scroll bar's width. // This function computes the actual offset. //NOTE: assumes we're being called in an IE browser var de = d.doc.documentElement; //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement; if(d.isIE < 7){ return { x: d._isBodyLtr() || window.parent == window ? de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft, y: de.clientTop }; // Object }else if(d.isIE < 8){ return {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}; }else{ return { x: 0, y: 0 }; } }; //>>excludeEnd("webkitMobile"); 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var dd = d.doc; if(d.isIE < 8 && !d._isBodyLtr()){ var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement; return scrollLeft + de.clientWidth - de.scrollWidth; // Integer } //>>excludeEnd("webkitMobile"); return scrollLeft; // Integer";s:7:"returns";s:99:"DomNode|Boolean|CSS2Properties|Number|CSS2Properties||String||Number|boolean|Object|integer|Integer";s:7:"private";b:1;s:7:"summary";s:0:"";}s:9:"dojo._abs";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:1:{s:4:"type";s:7:"DomNode";}s:13:"includeScroll";a:2:{s:8:"optional";b:1;s:4:"type";s:7:"Boolean";}}s:6:"source";s:39399:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); (function(){ var d = dojo; //>>excludeEnd("webkitMobile"); var _destroyContainer = null; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); //>>excludeEnd("webkitMobile"); 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 = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ } }; dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: string id or node reference to test // ancestor: string id or node reference of potential parent to test against try{ node = d.byId(node); ancestor = d.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. node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //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 true if successful, false otherwise. // // 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(dojo.create('div'), dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place(dojo.create('li'), "someUl", "first"); refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE /*|| dojo.isOpera*/){ var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE < 6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support? } //>>excludeEnd("webkitMobile"); // ============================= // 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isWebKit){ //>>excludeEnd("webkitMobile"); 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 || {}; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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) : {}; }; } //>>excludeEnd("webkitMobile"); dojo.getComputedStyle = gcs; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(!d.isIE){ //>>excludeEnd("webkitMobile"); d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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; } } //>>excludeEnd("webkitMobile"); 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 } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } } //>>excludeEnd("webkitMobile"); dojo._getOpacity = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : //>>excludeEnd("webkitMobile"); 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(/*DomNode*/node, /*Number*/opacity){ var ov = opacity * 100; node.style.zoom = 1.0; // 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 = !(opacity == 1); if(!af(node)){ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : //>>excludeEnd("webkitMobile"); 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! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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"; } } } //>>excludeEnd("webkitMobile"); 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() or // dojo.contentBox(). // 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 = d.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 && !d.isString(style)){ 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. // // * 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. // // * 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. // // * 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); 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 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; //>>excludeEnd("webkitMobile"); 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: optional. left offset from parent. // t: optional. top offset from parent. // w: optional. width in current box model. // h: optional. width in current box model. // u: optional. unit measure to use for other measures. Defaults to "px". u = u || "px"; 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: // 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. var n = d.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. // 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. All properties are optional if passed. var n = d.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 _b = d.body(), _w = d.global, de = d.doc.documentElement; return { y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0), x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0) }; }; dojo._isBodyLtr = function(){ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values return ("_bodyLtr" in d) ? d._bodyLtr : d._bodyLtr = gcs(d.body()).direction == "ltr"; // Boolean } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); dojo._getIeDocumentElementOffset = function(){ // summary // The following values in IE contain an offset: // event.clientX // event.clientY // node.getBoundingClientRect().left // node.getBoundingClientRect().top // But other position related values do not contain this offset, such as // node.offsetLeft, node.offsetTop, node.style.left and node.style.top. // The offset is always (2, 2) in LTR direction. When the body is in RTL // direction, the offset counts the width of left scroll bar's width. // This function computes the actual offset. //NOTE: assumes we're being called in an IE browser var de = d.doc.documentElement; //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement; if(d.isIE < 7){ return { x: d._isBodyLtr() || window.parent == window ? de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft, y: de.clientTop }; // Object }else if(d.isIE < 8){ return {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}; }else{ return { x: 0, y: 0 }; } }; //>>excludeEnd("webkitMobile"); 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var dd = d.doc; if(d.isIE < 8 && !d._isBodyLtr()){ var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement; return scrollLeft + de.clientWidth - de.scrollWidth; // Integer } //>>excludeEnd("webkitMobile"); return scrollLeft; // Integer } dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){ // summary: // Gets the position of the passed element relative to // the viewport (if includeScroll==false), or relative to the // document root (if includeScroll==true). // // Returns an object of the form: // { x: 100, y: 300 } // if includeScroll is passed, the x and y values will include any // document offsets that may affect the position relative to the // viewport. // FIXME: need to decide in the brave-new-world if we're going to be // margin-box or border-box. // targetBoxType == "border-box" var db = d.body(), dh = d.body().parentNode, ret; if(node["getBoundingClientRect"]){ // IE6+, FF3+, super-modern WebKit, and Opera 9.6+ all take this branch var client = node.getBoundingClientRect(); ret = { x: client.left, y: client.top }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isFF >= 3){ // in FF3 you have to subtract the document element margins var cs = gcs(dh); ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth); ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth); } 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 : 0); ret.y -= offset.y + (d.isQuirks ? db.clientTop : 0); } //>>excludeEnd("webkitMobile"); }else{ // FF2 and Safari ret = { x: 0, y: 0 }; 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){ //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isFF){ // 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{ //>>excludeEnd("webkitMobile"); ret.x += px(curnode, cs.borderLeftWidth); ret.y += px(curnode, cs.borderTopWidth); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } // static children in a static div in FF2 are affected by the div's border as well // but offsetParent will skip this div! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isFF && 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; } } //>>excludeEnd("webkitMobile"); 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";s:7:"returns";s:99:"DomNode|Boolean|CSS2Properties|Number|CSS2Properties||String||Number|boolean|Object|integer|Integer";s:7:"private";b:1;s:7:"summary";s:0:"";}s:11:"dojo.coords";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:1:{s:4:"type";s:14:"DomNode|String";}s:13:"includeScroll";a:2:{s:8:"optional";b:1;s:4:"type";s:7:"Boolean";}}s:6:"source";s:146:" var n = d.byId(node), s = gcs(n), mb = d._getMarginBox(n, s); var abs = d._abs(n, includeScroll); mb.x = abs.x; mb.y = abs.y; return mb;";s:7:"summary";s:103:"Returns an object that measures margin box width/height and absolute positioning data from dojo._abs().";s:11:"description";s:311:"Returns an object that measures margin box width/height and absolute positioning data from dojo._abs(). Return value will be in the form: `{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }` Does not act as a setter. If includeScroll is passed, the x and y params are affected as one would expect in dojo._abs().";}s:12:"dojo.hasAttr";a:6:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:39:"id or reference to the element to check";}s:4:"name";a:2:{s:4:"type";s:6:"String";s:7:"summary";s:25:"the name of the attribute";}}s:6:"source";s:271:" node = d.byId(node); var fixName = _fixAttrName(name); fixName = fixName == "htmlFor" ? "for" : fixName; //IE<8 uses htmlFor except in this case var attr = node.getAttributeNode && node.getAttributeNode(fixName); return attr ? attr.specified : false; // Boolean";s:7:"summary";s:95:"Returns true if the requested attribute is specified on the given element, and false otherwise.";s:14:"return_summary";s:86:"true if the requested attribute is specified on the given element, and false otherwise";s:7:"returns";s:7:"Boolean";}s:9:"dojo.attr";a:7:{s:4:"type";s:8:"Function";s:10:"parameters";a:3:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:61:"id or reference to the element to get or set the attribute on";}s:4:"name";a:2:{s:4:"type";s:13:"String|Object";s:7:"summary";s:40:"the name of the attribute to get or set.";}s:5:"value";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"String";s:7:"summary";s:34:"The value to set for the attribute";}}s:6:"source";s:1978:" node = d.byId(node); var args = arguments.length; if(args == 2 && !d.isString(name)){ // the object form of setter: the 2nd argument is a dictionary for(var x in name){ d.attr(node, x, name[x]); } // FIXME: return the node in this case? could be useful. return; } name = _fixAttrName(name); if(args == 3){ // setter if(d.isFunction(value)){ // 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][name]; if(h){ d.disconnect(h); }else{ try{ delete node[name]; }catch(e){} } // ensure that event objects are normalized, etc. _evtHdlrMap[attrId][name] = d.connect(node, name, value); }else if(typeof value == "boolean"){ // e.g. onsubmit, disabled node[name] = value; }else if(name === "style" && !d.isString(value)){ // when the name is "style" and value is an object, pass along d.style(node, value); }else if(name == "className"){ node.className = value; }else if(name === "innerHTML"){ //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){ d.empty(node); node.appendChild(d._toDom(value, node.ownerDocument)); }else{ //>>excludeEnd("webkitMobile"); node[name] = value; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); }else{ node.setAttribute(name, value); } }else{ // getter // should we access this attribute via a property or // via getAttribute()? var prop = _attrProps[name.toLowerCase()]; if(prop){ return node[prop]; } var attrValue = node[name]; return (typeof attrValue == 'boolean' || typeof attrValue == 'function') ? attrValue : (d.hasAttr(node, name) ? node.getAttribute(name) : null); }";s:7:"summary";s:45:"Gets or sets an attribute on an HTML element.";s:11:"description";s:755:"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 argumnt 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.";s:14:"return_summary";s:163:"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, undefined";s:8:"examples";a:5:{i:0;s:161:" // 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");";i:1;s:75:" // use attr() to set the tab index dojo.attr("nodeId", "tabindex", 3); ";i:2;s:553:"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" }); } });";i:3;s:166:"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" } });";i:4;s:226:"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);";}}s:15:"dojo.removeAttr";a:4:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"node";a:2:{s:4:"type";s:14:"DomNode|String";s:7:"summary";s:59:"id or reference to the element to remove the attribute from";}s:4:"name";a:2:{s:4:"type";s:6:"String";s:7:"summary";s:35:"the name of the attribute to remove";}}s:6:"source";s:51:" d.byId(node).removeAttribute(_fixAttrName(name));";s:7:"summary";s:42:"Removes an attribute from an HTML element.";}s:11:"dojo.create";a:8:{s:4:"type";s:8:"Function";s:10:"parameters";a:4:{s:3:"tag";a:2:{s:4:"type";s:14:"String|DomNode";s:7:"summary";s:174:"A string of the element to create (eg: "div", "a", "p", "li", "script", "br"), or an existing DOM node to process.";}s:5:"attrs";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:183:"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.";}s:7:"refNode";a:3:{s:4:"type";s:15:"String?|DomNode";s:8:"optional";b:1;s:7:"summary";s:170:"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.";}s:3:"pos";a:3:{s:4:"type";s:6:"String";s:8:"optional";b:1;s:7:"summary";s:338:"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.";}}s:6:"source";s:266:" var doc = d.doc; if(refNode){ refNode = d.byId(refNode); doc = refNode.ownerDocument; } if(d.isString(tag)){ tag = doc.createElement(tag); } if(attrs){ d.attr(tag, attrs); } if(refNode){ d.place(tag, refNode, pos); } return tag; // DomNode";s:7:"summary";s:76:"Create an element, allowing for optional attribute decoration and placement.";s:11:"description";s:479:"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.";s:14:"return_summary";s:7:"DomNode";s:7:"returns";s:7:"DomNode";s:8:"examples";a:6:{i:0;s:43:"Create a DIV: var n = dojo.create("div");";i:1;s:83:"Create a DIV with content: var n = dojo.create("div", { innerHTML:"
hi
" });";i:2;s:100:"Place a new DIV in the BODY, with no attributes set var n = dojo.create("div", null, dojo.body());";i:3;s:290:"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); });";i:4;s:119:"Create an anchor, with an href. Place in BODY: dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body());";i:5;s:230:"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.";}}s:11:"dojo._toDom";a:8:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"frag";a:2:{s:4:"type";s:6:"String";s:7:"summary";s:17:"the HTML fragment";}s:3:"doc";a:3:{s:4:"type";s:12:"DocumentNode";s:8:"optional";b:1;s:7:"summary";s:88:"optional document to use when creating DOM nodes, defaults to dojo.doc if not specified.";}}s:6:"source";s:54141:"dojo.require("dojo._base.lang"); dojo.provide("dojo._base.html"); // FIXME: need to add unit tests for all the semi-public methods //>>excludeStart("webkitMobile", kwArgs.webkitMobile); try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } //>>excludeEnd("webkitMobile"); // ============================= // DOM Functions // ============================= dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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. // | if(dojo.byId("bar")){ ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(dojo.isString(id)){ var _d = doc || dojo.doc; var te = _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te && (te.attributes.id.value == id || 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{ return id; // DomNode } }; }else{ //>>excludeEnd("webkitMobile"); dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); (function(){ var d = dojo; //>>excludeEnd("webkitMobile"); var _destroyContainer = null; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); //>>excludeEnd("webkitMobile"); 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 = d.byId(node); try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){ _destroyContainer = node.ownerDocument.createElement("div"); } _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature _destroyContainer.innerHTML = ""; }catch(e){ /* squelch */ } }; dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: string id or node reference to test // ancestor: string id or node reference of potential parent to test against try{ node = d.byId(node); ancestor = d.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. node = d.byId(node); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ //>>excludeEnd("webkitMobile"); node.style.KhtmlUserSelect = selectable ? "auto" : "none"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //>>excludeEnd("webkitMobile"); //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 true if successful, false otherwise. // // 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(dojo.create('div'), dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place(dojo.create('li'), "someUl", "first"); refNode = d.byId(refNode); if(d.isString(node)){ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : d.byId(node); } if(typeof position == "number"){ 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE /*|| dojo.isOpera*/){ var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE < 6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support? } //>>excludeEnd("webkitMobile"); // ============================= // 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isWebKit){ //>>excludeEnd("webkitMobile"); 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 || {}; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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) : {}; }; } //>>excludeEnd("webkitMobile"); dojo.getComputedStyle = gcs; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(!d.isIE){ //>>excludeEnd("webkitMobile"); d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); }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; } } //>>excludeEnd("webkitMobile"); 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 } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } } //>>excludeEnd("webkitMobile"); dojo._getOpacity = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : //>>excludeEnd("webkitMobile"); 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(/*DomNode*/node, /*Number*/opacity){ var ov = opacity * 100; node.style.zoom = 1.0; // 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 = !(opacity == 1); if(!af(node)){ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : //>>excludeEnd("webkitMobile"); 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! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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"; } } } //>>excludeEnd("webkitMobile"); 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() or // dojo.contentBox(). // 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 = d.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 && !d.isString(style)){ 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. // // * 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. // // * 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. // // * 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; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 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; } } //>>excludeEnd("webkitMobile"); 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 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; //>>excludeEnd("webkitMobile"); 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: optional. left offset from parent. // t: optional. top offset from parent. // w: optional. width in current box model. // h: optional. width in current box model. // u: optional. unit measure to use for other measures. Defaults to "px". u = u || "px"; 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: // 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. var n = d.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. // 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. All properties are optional if passed. var n = d.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 _b = d.body(), _w = d.global, de = d.doc.documentElement; return { y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0), x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0) }; }; dojo._isBodyLtr = function(){ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values return ("_bodyLtr" in d) ? d._bodyLtr : d._bodyLtr = gcs(d.body()).direction == "ltr"; // Boolean } //>>excludeStart("webkitMobile", kwArgs.webkitMobile); dojo._getIeDocumentElementOffset = function(){ // summary // The following values in IE contain an offset: // event.clientX // event.clientY // node.getBoundingClientRect().left // node.getBoundingClientRect().top // But other position related values do not contain this offset, such as // node.offsetLeft, node.offsetTop, node.style.left and node.style.top. // The offset is always (2, 2) in LTR direction. When the body is in RTL // direction, the offset counts the width of left scroll bar's width. // This function computes the actual offset. //NOTE: assumes we're being called in an IE browser var de = d.doc.documentElement; //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement; if(d.isIE < 7){ return { x: d._isBodyLtr() || window.parent == window ? de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft, y: de.clientTop }; // Object }else if(d.isIE < 8){ return {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}; }else{ return { x: 0, y: 0 }; } }; //>>excludeEnd("webkitMobile"); 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. //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var dd = d.doc; if(d.isIE < 8 && !d._isBodyLtr()){ var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement; return scrollLeft + de.clientWidth - de.scrollWidth; // Integer } //>>excludeEnd("webkitMobile"); return scrollLeft; // Integer } dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){ // summary: // Gets the position of the passed element relative to // the viewport (if includeScroll==false), or relative to the // document root (if includeScroll==true). // // Returns an object of the form: // { x: 100, y: 300 } // if includeScroll is passed, the x and y values will include any // document offsets that may affect the position relative to the // viewport. // FIXME: need to decide in the brave-new-world if we're going to be // margin-box or border-box. // targetBoxType == "border-box" var db = d.body(), dh = d.body().parentNode, ret; if(node["getBoundingClientRect"]){ // IE6+, FF3+, super-modern WebKit, and Opera 9.6+ all take this branch var client = node.getBoundingClientRect(); ret = { x: client.left, y: client.top }; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isFF >= 3){ // in FF3 you have to subtract the document element margins var cs = gcs(dh); ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth); ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth); } 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 : 0); ret.y -= offset.y + (d.isQuirks ? db.clientTop : 0); } //>>excludeEnd("webkitMobile"); }else{ // FF2 and Safari ret = { x: 0, y: 0 }; 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){ //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isFF){ // 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{ //>>excludeEnd("webkitMobile"); ret.x += px(curnode, cs.borderLeftWidth); ret.y += px(curnode, cs.borderTopWidth); //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); } // static children in a static div in FF2 are affected by the div's border as well // but offsetParent will skip this div! //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isFF && 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; } } //>>excludeEnd("webkitMobile"); 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 } // FIXME: need a setter for coords or a moveTo!! dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){ // summary: // Returns an object that measures margin box width/height and // absolute positioning data from dojo._abs(). // // description: // Returns an object that measures margin box width/height and // absolute positioning data from dojo._abs(). // Return value will be in the form: // `{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }` // Does not act as a setter. If includeScroll is passed, the x and // y params are affected as one would expect in dojo._abs(). var n = d.byId(node), s = gcs(n), mb = d._getMarginBox(n, s); var abs = d._abs(n, includeScroll); mb.x = abs.x; mb.y = abs.y; return mb; } // ============================= // Element attribute Functions // ============================= //>>excludeStart("webkitMobile", kwArgs.webkitMobile); var ieLT8 = d.isIE < 8; //>>excludeEnd("webkitMobile"); var _fixAttrName = function(/*String*/name){ switch(name.toLowerCase()){ // Internet Explorer will only set or remove tabindex/readonly // if it is spelled "tabIndex"/"readOnly" //>>excludeStart("webkitMobile", kwArgs.webkitMobile); case "tabindex": return ieLT8 ? "tabIndex" : "tabindex"; //>>excludeEnd("webkitMobile"); case "readonly": return "readOnly"; case "class": return "className"; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); case "for": case "htmlfor": // to pick up for attrib set in markup via getAttribute() IE<8 uses "htmlFor" and others use "for" // get/setAttribute works in all as long use same value for both get/set return ieLT8 ? "htmlFor" : "for"; //>>excludeEnd("webkitMobile"); default: return name; } } // non-deprecated HTML4 attributes with default values // http://www.w3.org/TR/html401/index/attributes.html // FF and Safari will return the default values if you // access the attributes via a property but not // via getAttribute() var _attrProps = { colspan: "colSpan", enctype: "enctype", frameborder: "frameborder", method: "method", rowspan: "rowSpan", scrolling: "scrolling", shape: "shape", span: "span", type: "type", valuetype: "valueType", // the following attributes don't have the default but should be treated like properties classname: "className", innerhtml: "innerHTML" } 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 node = d.byId(node); var fixName = _fixAttrName(name); fixName = fixName == "htmlFor" ? "for" : fixName; //IE<8 uses htmlFor except in this case var attr = node.getAttributeNode && node.getAttributeNode(fixName); return attr ? attr.specified : false; // 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 argumnt 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, undefined // // 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 = d.byId(node); var args = arguments.length; if(args == 2 && !d.isString(name)){ // the object form of setter: the 2nd argument is a dictionary for(var x in name){ d.attr(node, x, name[x]); } // FIXME: return the node in this case? could be useful. return; } name = _fixAttrName(name); if(args == 3){ // setter if(d.isFunction(value)){ // 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][name]; if(h){ d.disconnect(h); }else{ try{ delete node[name]; }catch(e){} } // ensure that event objects are normalized, etc. _evtHdlrMap[attrId][name] = d.connect(node, name, value); }else if(typeof value == "boolean"){ // e.g. onsubmit, disabled node[name] = value; }else if(name === "style" && !d.isString(value)){ // when the name is "style" and value is an object, pass along d.style(node, value); }else if(name == "className"){ node.className = value; }else if(name === "innerHTML"){ //>>excludeStart("webkitMobile", kwArgs.webkitMobile); if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){ d.empty(node); node.appendChild(d._toDom(value, node.ownerDocument)); }else{ //>>excludeEnd("webkitMobile"); node[name] = value; //>>excludeStart("webkitMobile", kwArgs.webkitMobile); } //>>excludeEnd("webkitMobile"); }else{ node.setAttribute(name, value); } }else{ // getter // should we access this attribute via a property or // via getAttribute()? var prop = _attrProps[name.toLowerCase()]; if(prop){ return node[prop]; } var attrValue = node[name]; return (typeof attrValue == 'boolean' || typeof attrValue == 'function') ? attrValue : (d.hasAttr(node, name) ? node.getAttribute(name) : null); } } dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){ // summary: // Removes an attribute from an HTML element. // node: // id or reference to the element to remove the attribute from // name: // the name of the attribute to remove d.byId(node).removeAttribute(_fixAttrName(name)); } 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:"hi
" }); // // 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 = d.byId(refNode); doc = refNode.ownerDocument; } if(d.isString(tag)){ 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 = //>>excludeStart("webkitMobile", kwArgs.webkitMobile); d.isIE ? function(node){ node = d.byId(node); for(var c; c = node.lastChild;){ // intentional assignment d.destroy(c); } } : //>>excludeEnd("webkitMobile"); function(node){ d.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("