1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090 |
- if (!dojo._hasResource["dojo._base.html"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dojo._base.html"] = true;
- dojo.require("dojo._base.lang");
- dojo.provide("dojo._base.html");
- // FIXME: need to add unit tests for all the semi-public methods
- try {
- document.execCommand("BackgroundImageCache", false, true);
- } catch (e) {
- // sane browsers don't have cache "issues"
- }
- // =============================
- // DOM Functions
- // =============================
- /*
- * ===== dojo.byId = function(id, doc){ // summary: // similar to other
- * library's "$" function, takes a // string representing a DOM id or a
- * DomNode // and returns the corresponding DomNode. If a Node is // passed,
- * this function is a no-op. Returns a // single DOM node or null, working
- * around several // browser-specific bugs to do so. // id: String|DOMNode //
- * DOM id or DOM Node // doc: DocumentElement // Document to work in.
- * Defaults to the current value of // dojo.doc. Can be used to retreive //
- * node references from other documents. =====
- */
- 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) {
- return te;
- } else {
- var eles = _d.all[id];
- if (!eles) {
- return;
- }
- if (!eles.length) {
- return eles;
- }
- // if more than 1, choose first with the correct id
- var i = 0;
- while ((te = eles[i++])) {
- if (te.attributes.id.value == id) {
- return te;
- }
- }
- }
- } else {
- return id; // DomNode
- }
- }
- } else {
- dojo.byId = function(id, doc) {
- if (dojo.isString(id)) {
- return (doc || dojo.doc).getElementById(id);
- } else {
- return id; // DomNode
- }
- }
- }
- /*
- * ===== } =====
- */
- (function() {
- /*
- * dojo.createElement = function(obj, parent, position){ // TODO: need
- * to finish this! }
- */
- var _destroyContainer = null;
- dojo._destroyElement = function(/* String||DomNode */node) {
- // summary:
- // removes node from its parent, clobbers it and all of its
- // children.
- // node:
- // the element to be destroyed, either as an ID or a reference
- node = dojo.byId(node);
- try {
- if (!_destroyContainer) {
- _destroyContainer = document.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: id or node reference to test
- // ancestor: id or node reference of potential parent to test
- // against
- try {
- node = dojo.byId(node);
- ancestor = dojo.byId(ancestor);
- while (node) {
- if (node === ancestor) {
- return true; // Boolean
- }
- node = node.parentNode;
- }
- } catch (e) {
- return -1; /* squelch */
- }
- 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:
- node = dojo.byId(node);
- if (dojo.isMozilla) {
- node.style.MozUserSelect = selectable ? "" : "none";
- } else if (dojo.isKhtml) {
- node.style.KhtmlUserSelect = selectable ? "auto" : "none";
- } else if (dojo.isIE) {
- node.unselectable = selectable ? "" : "on";
- dojo.query("*", node).forEach(function(descendant) {
- descendant.unselectable = selectable ? "" : "on";
- });
- }
- // FIXME: else? Opera?
- };
- var _insertBefore = function(/* Node */node, /* Node */ref) {
- ref.parentNode.insertBefore(node, ref);
- return true; // boolean
- }
- var _insertAfter = function(/* Node */node, /* Node */ref) {
- // summary:
- // Try to insert node after ref
- var pn = ref.parentNode;
- if (ref == pn.lastChild) {
- pn.appendChild(node);
- } else {
- return _insertBefore(node, ref.nextSibling); // boolean
- }
- return true; // boolean
- }
- dojo.place = function(/* String|DomNode */node, /* String|DomNode */
- refNode, /* String|Number */position) {
- // summary:
- // attempt to insert node in relation to ref based on position
- // node:
- // id or reference to node to place relative to refNode
- // refNode:
- // id or reference of node to use as basis for placement
- // position:
- // 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
- // * first
- // * last
- // "first" and "last" indicate positions as children of refNode.
- // FIXME: need to write tests for this!!!!
- if (!node || !refNode || position === undefined) {
- return false; // boolean
- }
- node = dojo.byId(node);
- refNode = dojo.byId(refNode);
- if (typeof position == "number") {
- var cn = refNode.childNodes;
- if ((position == 0 && cn.length == 0) || cn.length == position) {
- refNode.appendChild(node);
- return true;
- }
- if (position == 0) {
- return _insertBefore(node, refNode.firstChild);
- }
- return _insertAfter(node, cn[position - 1]);
- }
- switch (position.toLowerCase()) {
- case "before" :
- return _insertBefore(node, refNode); // boolean
- case "after" :
- return _insertAfter(node, refNode); // boolean
- case "first" :
- if (refNode.firstChild) {
- return _insertBefore(node, refNode.firstChild); // boolean
- } else {
- refNode.appendChild(node);
- return true; // boolean
- }
- break;
- default : // aka: last
- refNode.appendChild(node);
- return true; // boolean
- }
- }
- // Box functions will assume this model.
- // On IE/Opera, BORDER_BOX will be set if the primary document is in
- // quirks mode.
- // Can be set to change behavior of box setters.
- // can be either:
- // "border-box"
- // "content-box" (default)
- dojo.boxModel = "content-box";
- // We punt per-node box mode testing completely.
- // If anybody cares, we can provide an additional (optional) unit
- // that overrides existing code to include per-node box sensitivity.
- // Opera documentation claims that Opera 9 uses border-box in BackCompat
- // mode.
- // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it
- // actually continues to use content-box.
- // IIRC, earlier versions of Opera did in fact use border-box.
- // Opera guys, this is really confusing. Opera being broken in quirks
- // mode is not our fault.
- if (dojo.isIE /* || dojo.isOpera */) {
- var _dcm = document.compatMode;
- // client code may have to adjust if compatMode varies across
- // iframes
- dojo.boxModel = (_dcm == "BackCompat") || (_dcm == "QuirksMode")
- || (dojo.isIE < 6) ? "border-box" : "content-box";
- }
- // =============================
- // Style Functions
- // =============================
- // getComputedStyle drives most of the style code.
- // Wherever possible, reuse the returned object.
- //
- // API functions below that need to access computed styles accept an
- // optional computedStyle parameter.
- //
- // If this parameter is omitted, the functions will call
- // getComputedStyle themselves.
- //
- // This way, calling code can access computedStyle once, and then pass
- // the reference to
- // multiple API functions.
- //
- // This is a faux declaration to take pity on the doc tool
- /*
- * ===== dojo.getComputedStyle = function(node){ // summary: // Returns
- * a "computed style" object. // description: // get "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. // // 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; return; //
- * CSS2Properties } =====
- */
- var gcs, dv = document.defaultView;
- if (dojo.isSafari) {
- gcs = function(/* DomNode */node) {
- var s = dv.getComputedStyle(node, null);
- if (!s && node.style) {
- node.style.display = "";
- s = dv.getComputedStyle(node, null);
- }
- return s || {};
- };
- } else if (dojo.isIE) {
- gcs = function(node) {
- return node.currentStyle;
- };
- } else {
- gcs = function(node) {
- return dv.getComputedStyle(node, null);
- };
- }
- dojo.getComputedStyle = gcs;
- if (!dojo.isIE) {
- dojo._toPixelValue = function(element, value) {
- // style values can be floats, client code may want
- // to round for integer pixels.
- return parseFloat(value) || 0;
- }
- } else {
- dojo._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;
- }
- }
- // 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. // return:
- * Number between 0 and 1 } =====
- */
- dojo._getOpacity = (dojo.isIE ? function(node) {
- try {
- return (node.filters.alpha.opacity / 100); // Number
- } catch (e) {
- return 1; // Number
- }
- } : function(node) {
- return dojo.getComputedStyle(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. //
- * return: Number between 0 and 1 } =====
- */
- dojo._setOpacity = (dojo.isIE ? function(/* DomNode */node, /* Number */
- opacity) {
- if (opacity == 1) {
- // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so
- // remove it altogether (bug #2661)
- node.style.cssText = node.style.cssText.replace(
- /FILTER:[^;]*;/i, "");
- if (node.nodeName.toLowerCase() == "tr") {
- dojo.query("> td", node).forEach(function(i) {
- i.style.cssText = i.style.cssText.replace(
- /FILTER:[^;]*;/i, "");
- });
- }
- } else {
- var o = "Alpha(Opacity=" + (opacity * 100) + ")";
- node.style.filter = o;
- }
- if (node.nodeName.toLowerCase() == "tr") {
- dojo.query("> td", node).forEach(function(i) {
- i.style.filter = o;
- });
- }
- return opacity;
- } : function(node, opacity) {
- return node.style.opacity = opacity;
- });
- var _pixelNamesCache = {
- width : true,
- height : true,
- left : true,
- top : true
- };
- var _toStyleValue = function(node, type, value) {
- type = type.toLowerCase();
- if (_pixelNamesCache[type] === true) {
- return dojo._toPixelValue(node, value)
- } else if (_pixelNamesCache[type] === false) {
- return value;
- } else {
- if (dojo.isOpera && type == "cssText") {
- // FIXME: add workaround for #2855 here
- }
- if ((type.indexOf("margin") >= 0)
- ||
- // (type.indexOf("border") >= 0) ||
- (type.indexOf("padding") >= 0)
- || (type.indexOf("width") >= 0)
- || (type.indexOf("height") >= 0)
- || (type.indexOf("max") >= 0)
- || (type.indexOf("min") >= 0)
- || (type.indexOf("offset") >= 0)) {
- _pixelNamesCache[type] = true;
- return dojo._toPixelValue(node, value)
- } else {
- _pixelNamesCache[type] = false;
- return value;
- }
- }
- }
- // public API
- dojo.style = function(/* DomNode|String */node, /* String */style, /* String? */
- value) {
- // summary:
- // gets or sets a style property on node. If 2 arguments are
- // passed, acts as a getter. If value is passed, acts as a setter
- // for the property.
- // 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").
- // value:
- // optional. If passed, sets value on the node for style, handling
- // cross-browser concerns.
- var n = dojo.byId(node), args = arguments.length, op = (style == "opacity");
- if (args == 3) {
- return op ? dojo._setOpacity(n, value) : n.style[style] = value; /* Number */
- }
- if (args == 2 && op) {
- return dojo._getOpacity(n);
- }
- var s = dojo.getComputedStyle(n);
- return (args == 1) ? s : _toStyleValue(n, style, s[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), px = dojo._toPixelValue, 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', px = dojo._toPixelValue, 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 = dojo._getPadExtents(n, s), b = dojo
- ._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), px = dojo._toPixelValue, l = px(n,
- s.marginLeft), t = px(n, s.marginTop), r = px(n,
- s.marginRight), b = px(n, s.marginBottom);
- if (dojo.isSafari && (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 = dojo._getMarginExtents(
- node, s);
- var l = node.offsetLeft - me.l, t = node.offsetTop - me.t;
- if (dojo.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.
- var p = node.parentNode;
- if (p && p.style) {
- var pcs = gcs(p);
- if (pcs.overflow != "visible") {
- var be = dojo._getBorderExtents(p, pcs);
- l += be.l, t += be.t;
- }
- }
- }
- } else if (dojo.isOpera) {
- // On Opera, offsetLeft includes the parent's border
- var p = node.parentNode;
- if (p) {
- var be = dojo._getBorderExtents(p);
- l -= be.l, t -= be.t;
- }
- }
- return {
- l : l,
- t : t,
- w : node.offsetWidth + me.w,
- h : node.offsetHeight + me.h
- };
- }
- dojo._getContentBox = function(node, computedStyle) {
- // summary:
- // Returns an object that encodes the width, height, left and top
- // positions of the node's content box, irrespective of the
- // current box model.
- // clientWidth/Height are important since the automatically account
- // for scrollbars
- // fallback to offsetWidth/Height for special cases (see #3378)
- var s = computedStyle || gcs(node), pe = dojo._getPadExtents(node,
- s), be = dojo._getBorderExtents(node, s), w = node.clientWidth, h;
- if (!w) {
- w = node.offsetWidth, h = node.offsetHeight;
- } else {
- h = node.clientHeight, be.w = be.h = 0;
- }
- // On Opera, offsetLeft includes the parent's border
- if (dojo.isOpera) {
- pe.l += be.l;
- pe.t += be.t;
- };
- return {
- l : pe.l,
- t : pe.t,
- w : w - pe.w - be.w,
- h : h - pe.h - be.h
- };
- }
- dojo._getBorderBox = function(node, computedStyle) {
- var s = computedStyle || gcs(node), pe = dojo._getPadExtents(node,
- s), cb = dojo._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";
- with (node.style) {
- if (!isNaN(l)) {
- left = l + u;
- }
- if (!isNaN(t)) {
- top = t + u;
- }
- if (w >= 0) {
- width = w + u;
- }
- if (h >= 0) {
- height = h + u;
- }
- }
- }
- 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.
- var n = node.tagName;
- // For whatever reason, TABLE and BUTTON are always border-box by
- // default.
- // If you have assigned a different box to either one via CSS then
- // box functions will break.
- return dojo.boxModel == "border-box" || n == "TABLE"
- || n == "BUTTON"; // 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.
- var bb = dojo._usesBorderBox(node);
- if (bb) {
- var pb = dojo._getPadBorderExtents(node, computedStyle);
- if (widthPx >= 0) {
- widthPx += pb.w;
- }
- if (heightPx >= 0) {
- heightPx += pb.h;
- }
- }
- dojo._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 palcement
- // (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 || dojo.getComputedStyle(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.
- var bb = dojo._usesBorderBox(node), pb = bb ? _nilExtents : dojo
- ._getPadBorderExtents(node, s), mb = dojo
- ._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);
- }
- dojo._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:
- // optional. 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 = dojo.byId(node), s = gcs(n), b = box;
- return !b ? dojo._getMarginBox(n, s) : dojo._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:
- // optional. 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 = dojo.byId(node), s = gcs(n), b = box;
- return !b ? dojo._getContentBox(n, s) : dojo._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 = dojo.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 = dojo.body();
- var _w = dojo.global;
- var de = dojo.doc.documentElement;
- return {
- y : (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
- x : (_w.pageXOffset || dojo._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 dojo)
- ? dojo._bodyLtr = dojo.getComputedStyle(dojo.body()).direction == "ltr"
- : dojo._bodyLtr; // Boolean
- }
- 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 = dojo.doc.documentElement;
- if (dojo.isIE >= 7) {
- return {
- x : de.getBoundingClientRect().left,
- y : de.getBoundingClientRect().top
- }; // Object
- } else {
- // IE 6.0
- return {
- x : dojo._isBodyLtr() || window.parent == window
- ? de.clientLeft
- : de.offsetWidth - de.clientWidth - de.clientLeft,
- y : de.clientTop
- }; // Object
- }
- };
- dojo._fixIeBiDiScrollLeft = function(/* Integer */scrollLeft) {
- // In RTL direction, scrollLeft should be a negative value, but IE
- // 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 horizonal scrollbar.
- if (dojo.isIE && !dojo._isBodyLtr()) {
- var de = dojo.doc.documentElement;
- return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
- }
- return scrollLeft; // Integer
- }
- dojo._abs = function(/* DomNode */node, /* Boolean? */includeScroll) {
- // summary:
- // Gets the absolute position of the passed element based on the
- // document itself. 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.
- var ownerDocument = node.ownerDocument;
- var ret = {
- x : 0,
- y : 0
- };
- var hasScroll = false;
- // targetBoxType == "border-box"
- var db = dojo.body();
- if (dojo.isIE) {
- var client = node.getBoundingClientRect();
- var offset = dojo._getIeDocumentElementOffset();
- ret.x = client.left - offset.x;
- ret.y = client.top - offset.y;
- } else if (ownerDocument["getBoxObjectFor"]) {
- // mozilla
- var bo = ownerDocument.getBoxObjectFor(node);
- ret.x = bo.x - _sumAncestorProperties(node, "scrollLeft");
- ret.y = bo.y - _sumAncestorProperties(node, "scrollTop");
- } else {
- if (node["offsetParent"]) {
- hasScroll = true;
- var endNode;
- // in Safari, if the node is an absolutely positioned child
- // of
- // the body and the body has a margin the offset of the
- // child
- // and the body contain the body's margins, so we need to
- // end
- // at the body
- // FIXME: getting contrary results to the above in latest
- // WebKit.
- if (dojo.isSafari
- &&
- // (node.style.getPropertyValue("position") ==
- // "absolute") &&
- (gcs(node).position == "absolute")
- && (node.parentNode == db)) {
- endNode = db;
- } else {
- endNode = db.parentNode;
- }
- if (node.parentNode != db) {
- var nd = node;
- if (dojo.isOpera || (dojo.isSafari >= 3)) {
- nd = db;
- }
- ret.x -= _sumAncestorProperties(nd, "scrollLeft");
- ret.y -= _sumAncestorProperties(nd, "scrollTop");
- }
- var curnode = node;
- do {
- var n = curnode["offsetLeft"];
- // FIXME: ugly hack to workaround the submenu in
- // popupmenu2 does not shown up correctly in opera.
- // Someone have a better workaround?
- if (!dojo.isOpera || n > 0) {
- ret.x += isNaN(n) ? 0 : n;
- }
- var m = curnode["offsetTop"];
- ret.y += isNaN(m) ? 0 : m;
- curnode = curnode.offsetParent;
- } while ((curnode != endNode) && curnode);
- } 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 (hasScroll || includeScroll) {
- var scroll = dojo._docScroll();
- var m = hasScroll ? (!includeScroll ? -1 : 0) : 1;
- ret.y += m * scroll.y;
- ret.x += m * scroll.x;
- }
- 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(). 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 = dojo.byId(node), s = gcs(n), mb = dojo._getMarginBox(n, s);
- var abs = dojo._abs(n, includeScroll);
- mb.x = abs.x;
- mb.y = abs.y;
- return mb;
- }
- })();
- // =============================
- // (CSS) Class Functions
- // =============================
- dojo.hasClass = function(/* DomNode|String */node, /* String */classStr) {
- // summary:
- // Returns whether or not the specified classes are a portion of the
- // class list currently applied to the node.
- return ((" " + dojo.byId(node).className + " ").indexOf(" " + classStr
- + " ") >= 0); // Boolean
- };
- dojo.addClass = function(/* DomNode|String */node, /* String */classStr) {
- // summary:
- // Adds the specified classes to the end of the class list on the
- // passed node.
- node = dojo.byId(node);
- var cls = node.className;
- if ((" " + cls + " ").indexOf(" " + classStr + " ") < 0) {
- node.className = cls + (cls ? ' ' : '') + classStr;
- }
- };
- dojo.removeClass = function(/* DomNode|String */node, /* String */classStr) {
- // summary: Removes the specified classes from node.
- node = dojo.byId(node);
- var t = dojo.trim((" " + node.className + " ").replace(" " + classStr
- + " ", " "));
- if (node.className != t) {
- node.className = t;
- }
- };
- dojo.toggleClass = function(/* DomNode|String */node, /* String */classStr, /* Boolean? */
- condition) {
- // summary:
- // Adds a class to node if not present, or removes if present.
- // Pass a boolean condition if you want to explicitly add or remove.
- // condition:
- // If passed, true means to add the class, false means to remove.
- if (condition === undefined) {
- condition = !dojo.hasClass(node, classStr);
- }
- dojo[condition ? "addClass" : "removeClass"](node, classStr);
- };
- }
|