[256] | 1 | define(["./_base/sniff", "./_base/window","./dom", "./dom-style"], |
---|
| 2 | function(has, win, dom, style){ |
---|
| 3 | // module: |
---|
| 4 | // dojo/dom-geometry |
---|
| 5 | // summary: |
---|
| 6 | // This module defines the core dojo DOM geometry API. |
---|
| 7 | |
---|
| 8 | var geom = {}; // the result object |
---|
| 9 | |
---|
| 10 | // Box functions will assume this model. |
---|
| 11 | // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode. |
---|
| 12 | // Can be set to change behavior of box setters. |
---|
| 13 | |
---|
| 14 | // can be either: |
---|
| 15 | // "border-box" |
---|
| 16 | // "content-box" (default) |
---|
| 17 | geom.boxModel = "content-box"; |
---|
| 18 | |
---|
| 19 | // We punt per-node box mode testing completely. |
---|
| 20 | // If anybody cares, we can provide an additional (optional) unit |
---|
| 21 | // that overrides existing code to include per-node box sensitivity. |
---|
| 22 | |
---|
| 23 | // Opera documentation claims that Opera 9 uses border-box in BackCompat mode. |
---|
| 24 | // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box. |
---|
| 25 | // IIRC, earlier versions of Opera did in fact use border-box. |
---|
| 26 | // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault. |
---|
| 27 | |
---|
| 28 | //>>excludeStart("webkitMobile", kwArgs.webkitMobile); |
---|
| 29 | if(has("ie") /*|| has("opera")*/){ |
---|
| 30 | // client code may have to adjust if compatMode varies across iframes |
---|
| 31 | geom.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box"; |
---|
| 32 | } |
---|
| 33 | //>>excludeEnd("webkitMobile"); |
---|
| 34 | |
---|
| 35 | // ============================= |
---|
| 36 | // Box Functions |
---|
| 37 | // ============================= |
---|
| 38 | |
---|
| 39 | /*===== |
---|
| 40 | dojo.getPadExtents = function(node, computedStyle){ |
---|
| 41 | // summary: |
---|
| 42 | // Returns object with special values specifically useful for node |
---|
| 43 | // fitting. |
---|
| 44 | // description: |
---|
| 45 | // Returns an object with `w`, `h`, `l`, `t` properties: |
---|
| 46 | // | l/t/r/b = left/top/right/bottom padding (respectively) |
---|
| 47 | // | w = the total of the left and right padding |
---|
| 48 | // | h = the total of the top and bottom padding |
---|
| 49 | // If 'node' has position, l/t forms the origin for child nodes. |
---|
| 50 | // The w/h are used for calculating boxes. |
---|
| 51 | // Normally application code will not need to invoke this |
---|
| 52 | // directly, and will use the ...box... functions instead. |
---|
| 53 | // node: DOMNode |
---|
| 54 | // computedStyle: Object? |
---|
| 55 | // This parameter accepts computed styles object. |
---|
| 56 | // If this parameter is omitted, the functions will call |
---|
| 57 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 58 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 59 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 60 | // object of dojo.getComputedStyle. |
---|
| 61 | |
---|
| 62 | |
---|
| 63 | }; |
---|
| 64 | =====*/ |
---|
| 65 | |
---|
| 66 | /*===== |
---|
| 67 | dojo._getPadExtents = function(node, computedStyle){ |
---|
| 68 | // summary: |
---|
| 69 | // Existing alias for `dojo.getPadExtents`. Deprecated, will be removed in 2.0. |
---|
| 70 | }; |
---|
| 71 | =====*/ |
---|
| 72 | |
---|
| 73 | /*===== |
---|
| 74 | dojo.getBorderExtents = function(node, computedStyle){ |
---|
| 75 | // summary: |
---|
| 76 | // returns an object with properties useful for noting the border |
---|
| 77 | // dimensions. |
---|
| 78 | // description: |
---|
| 79 | // * l/t/r/b = the sum of left/top/right/bottom border (respectively) |
---|
| 80 | // * w = the sum of the left and right border |
---|
| 81 | // * h = the sum of the top and bottom border |
---|
| 82 | // |
---|
| 83 | // The w/h are used for calculating boxes. |
---|
| 84 | // Normally application code will not need to invoke this |
---|
| 85 | // directly, and will use the ...box... functions instead. |
---|
| 86 | // node: DOMNode |
---|
| 87 | // computedStyle: Object? |
---|
| 88 | // This parameter accepts computed styles object. |
---|
| 89 | // If this parameter is omitted, the functions will call |
---|
| 90 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 91 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 92 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 93 | // object of dojo.getComputedStyle. |
---|
| 94 | |
---|
| 95 | |
---|
| 96 | }; |
---|
| 97 | =====*/ |
---|
| 98 | |
---|
| 99 | /*===== |
---|
| 100 | dojo._getBorderExtents = function(node, computedStyle){ |
---|
| 101 | // summary: |
---|
| 102 | // Existing alias for `dojo.getBorderExtents`. Deprecated, will be removed in 2.0. |
---|
| 103 | }; |
---|
| 104 | =====*/ |
---|
| 105 | |
---|
| 106 | /*===== |
---|
| 107 | dojo.getPadBorderExtents = function(node, computedStyle){ |
---|
| 108 | // summary: |
---|
| 109 | // Returns object with properties useful for box fitting with |
---|
| 110 | // regards to padding. |
---|
| 111 | // description: |
---|
| 112 | // * l/t/r/b = the sum of left/top/right/bottom padding and left/top/right/bottom border (respectively) |
---|
| 113 | // * w = the sum of the left and right padding and border |
---|
| 114 | // * h = the sum of the top and bottom padding and border |
---|
| 115 | // |
---|
| 116 | // The w/h are used for calculating boxes. |
---|
| 117 | // Normally application code will not need to invoke this |
---|
| 118 | // directly, and will use the ...box... functions instead. |
---|
| 119 | // node: DOMNode |
---|
| 120 | // computedStyle: Object? |
---|
| 121 | // This parameter accepts computed styles object. |
---|
| 122 | // If this parameter is omitted, the functions will call |
---|
| 123 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 124 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 125 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 126 | // object of dojo.getComputedStyle. |
---|
| 127 | |
---|
| 128 | |
---|
| 129 | }; |
---|
| 130 | =====*/ |
---|
| 131 | |
---|
| 132 | /*===== |
---|
| 133 | dojo._getPadBorderExtents = function(node, computedStyle){ |
---|
| 134 | // summary: |
---|
| 135 | // Existing alias for `dojo.getPadBorderExtents`. Deprecated, will be removed in 2.0. |
---|
| 136 | }; |
---|
| 137 | =====*/ |
---|
| 138 | |
---|
| 139 | /*===== |
---|
| 140 | dojo.getMarginExtents = function(node, computedStyle){ |
---|
| 141 | // summary: |
---|
| 142 | // returns object with properties useful for box fitting with |
---|
| 143 | // regards to box margins (i.e., the outer-box). |
---|
| 144 | // |
---|
| 145 | // * l/t = marginLeft, marginTop, respectively |
---|
| 146 | // * w = total width, margin inclusive |
---|
| 147 | // * h = total height, margin inclusive |
---|
| 148 | // |
---|
| 149 | // The w/h are used for calculating boxes. |
---|
| 150 | // Normally application code will not need to invoke this |
---|
| 151 | // directly, and will use the ...box... functions instead. |
---|
| 152 | // node: DOMNode |
---|
| 153 | // computedStyle: Object? |
---|
| 154 | // This parameter accepts computed styles object. |
---|
| 155 | // If this parameter is omitted, the functions will call |
---|
| 156 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 157 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 158 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 159 | // object of dojo.getComputedStyle. |
---|
| 160 | }; |
---|
| 161 | =====*/ |
---|
| 162 | |
---|
| 163 | /*===== |
---|
| 164 | dojo._getMarginExtents = function(node, computedStyle){ |
---|
| 165 | // summary: |
---|
| 166 | // Existing alias for `dojo.getMarginExtents`. Deprecated, will be removed in 2.0. |
---|
| 167 | }; |
---|
| 168 | =====*/ |
---|
| 169 | |
---|
| 170 | /*===== |
---|
| 171 | dojo.getMarginSize = function(node, computedStyle){ |
---|
| 172 | // summary: |
---|
| 173 | // returns an object that encodes the width and height of |
---|
| 174 | // the node's margin box |
---|
| 175 | // node: DOMNode|String |
---|
| 176 | // computedStyle: Object? |
---|
| 177 | // This parameter accepts computed styles object. |
---|
| 178 | // If this parameter is omitted, the functions will call |
---|
| 179 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 180 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 181 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 182 | // object of dojo.getComputedStyle. |
---|
| 183 | }; |
---|
| 184 | =====*/ |
---|
| 185 | |
---|
| 186 | /*===== |
---|
| 187 | dojo._getMarginSize = function(node, computedStyle){ |
---|
| 188 | // summary: |
---|
| 189 | // Existing alias for `dojo.getMarginSize`. Deprecated, will be removed in 2.0. |
---|
| 190 | }; |
---|
| 191 | =====*/ |
---|
| 192 | |
---|
| 193 | /*===== |
---|
| 194 | dojo.getMarginBox = function(node, computedStyle){ |
---|
| 195 | // summary: |
---|
| 196 | // returns an object that encodes the width, height, left and top |
---|
| 197 | // positions of the node's margin box. |
---|
| 198 | // node: DOMNode |
---|
| 199 | // computedStyle: Object? |
---|
| 200 | // This parameter accepts computed styles object. |
---|
| 201 | // If this parameter is omitted, the functions will call |
---|
| 202 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 203 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 204 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 205 | // object of dojo.getComputedStyle. |
---|
| 206 | }; |
---|
| 207 | =====*/ |
---|
| 208 | |
---|
| 209 | /*===== |
---|
| 210 | dojo._getMarginBox = function(node, computedStyle){ |
---|
| 211 | // summary: |
---|
| 212 | // Existing alias for `dojo.getMarginBox`. Deprecated, will be removed in 2.0. |
---|
| 213 | }; |
---|
| 214 | =====*/ |
---|
| 215 | |
---|
| 216 | /*===== |
---|
| 217 | dojo.setMarginBox = function(node, box, computedStyle){ |
---|
| 218 | // summary: |
---|
| 219 | // sets the size of the node's margin box and placement |
---|
| 220 | // (left/top), irrespective of box model. Think of it as a |
---|
| 221 | // passthrough to setBox that handles box-model vagaries for |
---|
| 222 | // you. |
---|
| 223 | // node: DOMNode |
---|
| 224 | // box: Object |
---|
| 225 | // hash with optional "l", "t", "w", and "h" properties for "left", "right", "width", and "height" |
---|
| 226 | // respectively. All specified properties should have numeric values in whole pixels. |
---|
| 227 | // computedStyle: Object? |
---|
| 228 | // This parameter accepts computed styles object. |
---|
| 229 | // If this parameter is omitted, the functions will call |
---|
| 230 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 231 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 232 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 233 | // object of dojo.getComputedStyle. |
---|
| 234 | }; |
---|
| 235 | =====*/ |
---|
| 236 | |
---|
| 237 | /*===== |
---|
| 238 | dojo.getContentBox = function(node, computedStyle){ |
---|
| 239 | // summary: |
---|
| 240 | // Returns an object that encodes the width, height, left and top |
---|
| 241 | // positions of the node's content box, irrespective of the |
---|
| 242 | // current box model. |
---|
| 243 | // node: DOMNode |
---|
| 244 | // computedStyle: Object? |
---|
| 245 | // This parameter accepts computed styles object. |
---|
| 246 | // If this parameter is omitted, the functions will call |
---|
| 247 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 248 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 249 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 250 | // object of dojo.getComputedStyle. |
---|
| 251 | }; |
---|
| 252 | =====*/ |
---|
| 253 | |
---|
| 254 | /*===== |
---|
| 255 | dojo._getContentBox = function(node, computedStyle){ |
---|
| 256 | // summary: |
---|
| 257 | // Existing alias for `dojo.getContentBox`. Deprecated, will be removed in 2.0. |
---|
| 258 | }; |
---|
| 259 | =====*/ |
---|
| 260 | |
---|
| 261 | /*===== |
---|
| 262 | dojo.setContentSize = function(node, box, computedStyle){ |
---|
| 263 | // summary: |
---|
| 264 | // Sets the size of the node's contents, irrespective of margins, |
---|
| 265 | // padding, or borders. |
---|
| 266 | // node: DOMNode |
---|
| 267 | // box: Object |
---|
| 268 | // hash with optional "w", and "h" properties for "width", and "height" |
---|
| 269 | // respectively. All specified properties should have numeric values in whole pixels. |
---|
| 270 | // computedStyle: Object? |
---|
| 271 | // This parameter accepts computed styles object. |
---|
| 272 | // If this parameter is omitted, the functions will call |
---|
| 273 | // dojo.getComputedStyle to get one. It is a better way, calling |
---|
| 274 | // dojo.computedStyle once, and then pass the reference to this |
---|
| 275 | // computedStyle parameter. Wherever possible, reuse the returned |
---|
| 276 | // object of dojo.getComputedStyle. |
---|
| 277 | }; |
---|
| 278 | =====*/ |
---|
| 279 | |
---|
| 280 | /*===== |
---|
| 281 | dojo.isBodyLtr = function(){ |
---|
| 282 | // summary: |
---|
| 283 | // Returns true if the current language is left-to-right, and false otherwise. |
---|
| 284 | // returns: Boolean |
---|
| 285 | }; |
---|
| 286 | =====*/ |
---|
| 287 | |
---|
| 288 | /*===== |
---|
| 289 | dojo._isBodyLtr = function(){ |
---|
| 290 | // summary: |
---|
| 291 | // Existing alias for `dojo.isBodyLtr`. Deprecated, will be removed in 2.0. |
---|
| 292 | }; |
---|
| 293 | =====*/ |
---|
| 294 | |
---|
| 295 | /*===== |
---|
| 296 | dojo.docScroll = function(){ |
---|
| 297 | // summary: |
---|
| 298 | // Returns an object with {node, x, y} with corresponding offsets. |
---|
| 299 | // returns: Object |
---|
| 300 | }; |
---|
| 301 | =====*/ |
---|
| 302 | |
---|
| 303 | /*===== |
---|
| 304 | dojo._docScroll = function(){ |
---|
| 305 | // summary: |
---|
| 306 | // Existing alias for `dojo.docScroll`. Deprecated, will be removed in 2.0. |
---|
| 307 | }; |
---|
| 308 | =====*/ |
---|
| 309 | |
---|
| 310 | /*===== |
---|
| 311 | dojo.getIeDocumentElementOffset = function(){ |
---|
| 312 | // summary: |
---|
| 313 | // returns the offset in x and y from the document body to the |
---|
| 314 | // visual edge of the page for IE |
---|
| 315 | // description: |
---|
| 316 | // The following values in IE contain an offset: |
---|
| 317 | // | event.clientX |
---|
| 318 | // | event.clientY |
---|
| 319 | // | node.getBoundingClientRect().left |
---|
| 320 | // | node.getBoundingClientRect().top |
---|
| 321 | // But other position related values do not contain this offset, |
---|
| 322 | // such as node.offsetLeft, node.offsetTop, node.style.left and |
---|
| 323 | // node.style.top. The offset is always (2, 2) in LTR direction. |
---|
| 324 | // When the body is in RTL direction, the offset counts the width |
---|
| 325 | // of left scroll bar's width. This function computes the actual |
---|
| 326 | // offset. |
---|
| 327 | }; |
---|
| 328 | =====*/ |
---|
| 329 | |
---|
| 330 | /*===== |
---|
| 331 | dojo._getIeDocumentElementOffset = function(){ |
---|
| 332 | // summary: |
---|
| 333 | // Existing alias for `dojo.getIeDocumentElementOffset`. Deprecated, will be removed in 2.0. |
---|
| 334 | }; |
---|
| 335 | =====*/ |
---|
| 336 | |
---|
| 337 | /*===== |
---|
| 338 | dojo.fixIeBiDiScrollLeft = function(scrollLeft){ |
---|
| 339 | // summary: |
---|
| 340 | // In RTL direction, scrollLeft should be a negative value, but IE |
---|
| 341 | // returns a positive one. All codes using documentElement.scrollLeft |
---|
| 342 | // must call this function to fix this error, otherwise the position |
---|
| 343 | // will offset to right when there is a horizontal scrollbar. |
---|
| 344 | // scrollLeft: NUmber |
---|
| 345 | // returns: Number |
---|
| 346 | }; |
---|
| 347 | =====*/ |
---|
| 348 | |
---|
| 349 | /*===== |
---|
| 350 | dojo._fixIeBiDiScrollLeft = function(scrollLeft){ |
---|
| 351 | // summary: |
---|
| 352 | // Existing alias for `dojo.fixIeBiDiScrollLeft`. Deprecated, will be removed in 2.0. |
---|
| 353 | }; |
---|
| 354 | =====*/ |
---|
| 355 | |
---|
| 356 | /*===== |
---|
| 357 | dojo.position = function(node, includeScroll){ |
---|
| 358 | // summary: |
---|
| 359 | // Gets the position and size of the passed element relative to |
---|
| 360 | // the viewport (if includeScroll==false), or relative to the |
---|
| 361 | // document root (if includeScroll==true). |
---|
| 362 | // |
---|
| 363 | // description: |
---|
| 364 | // Returns an object of the form: |
---|
| 365 | // { x: 100, y: 300, w: 20, h: 15 } |
---|
| 366 | // If includeScroll==true, the x and y values will include any |
---|
| 367 | // document offsets that may affect the position relative to the |
---|
| 368 | // viewport. |
---|
| 369 | // Uses the border-box model (inclusive of border and padding but |
---|
| 370 | // not margin). Does not act as a setter. |
---|
| 371 | // node: DOMNode|String |
---|
| 372 | // includeScroll: Boolean? |
---|
| 373 | // returns: Object |
---|
| 374 | }; |
---|
| 375 | =====*/ |
---|
| 376 | |
---|
| 377 | geom.getPadExtents = function getPadExtents(/*DomNode*/node, /*Object*/computedStyle){ |
---|
| 378 | node = dom.byId(node); |
---|
| 379 | var s = computedStyle || style.getComputedStyle(node), px = style.toPixelValue, |
---|
| 380 | l = px(node, s.paddingLeft), t = px(node, s.paddingTop), r = px(node, s.paddingRight), b = px(node, s.paddingBottom); |
---|
| 381 | return {l: l, t: t, r: r, b: b, w: l + r, h: t + b}; |
---|
| 382 | }; |
---|
| 383 | |
---|
| 384 | var none = "none"; |
---|
| 385 | |
---|
| 386 | geom.getBorderExtents = function getBorderExtents(/*DomNode*/node, /*Object*/computedStyle){ |
---|
| 387 | node = dom.byId(node); |
---|
| 388 | var px = style.toPixelValue, s = computedStyle || style.getComputedStyle(node), |
---|
| 389 | l = s.borderLeftStyle != none ? px(node, s.borderLeftWidth) : 0, |
---|
| 390 | t = s.borderTopStyle != none ? px(node, s.borderTopWidth) : 0, |
---|
| 391 | r = s.borderRightStyle != none ? px(node, s.borderRightWidth) : 0, |
---|
| 392 | b = s.borderBottomStyle != none ? px(node, s.borderBottomWidth) : 0; |
---|
| 393 | return {l: l, t: t, r: r, b: b, w: l + r, h: t + b}; |
---|
| 394 | }; |
---|
| 395 | |
---|
| 396 | geom.getPadBorderExtents = function getPadBorderExtents(/*DomNode*/node, /*Object*/computedStyle){ |
---|
| 397 | node = dom.byId(node); |
---|
| 398 | var s = computedStyle || style.getComputedStyle(node), |
---|
| 399 | p = geom.getPadExtents(node, s), |
---|
| 400 | b = geom.getBorderExtents(node, s); |
---|
| 401 | return { |
---|
| 402 | l: p.l + b.l, |
---|
| 403 | t: p.t + b.t, |
---|
| 404 | r: p.r + b.r, |
---|
| 405 | b: p.b + b.b, |
---|
| 406 | w: p.w + b.w, |
---|
| 407 | h: p.h + b.h |
---|
| 408 | }; |
---|
| 409 | }; |
---|
| 410 | |
---|
| 411 | geom.getMarginExtents = function getMarginExtents(node, computedStyle){ |
---|
| 412 | node = dom.byId(node); |
---|
| 413 | var s = computedStyle || style.getComputedStyle(node), px = style.toPixelValue, |
---|
| 414 | l = px(node, s.marginLeft), t = px(node, s.marginTop), r = px(node, s.marginRight), b = px(node, s.marginBottom); |
---|
| 415 | if(has("webkit") && (s.position != "absolute")){ |
---|
| 416 | // FIXME: Safari's version of the computed right margin |
---|
| 417 | // is the space between our right edge and the right edge |
---|
| 418 | // of our offsetParent. |
---|
| 419 | // What we are looking for is the actual margin value as |
---|
| 420 | // determined by CSS. |
---|
| 421 | // Hack solution is to assume left/right margins are the same. |
---|
| 422 | r = l; |
---|
| 423 | } |
---|
| 424 | return {l: l, t: t, r: r, b: b, w: l + r, h: t + b}; |
---|
| 425 | }; |
---|
| 426 | |
---|
| 427 | // Box getters work in any box context because offsetWidth/clientWidth |
---|
| 428 | // are invariant wrt box context |
---|
| 429 | // |
---|
| 430 | // They do *not* work for display: inline objects that have padding styles |
---|
| 431 | // because the user agent ignores padding (it's bogus styling in any case) |
---|
| 432 | // |
---|
| 433 | // Be careful with IMGs because they are inline or block depending on |
---|
| 434 | // browser and browser mode. |
---|
| 435 | |
---|
| 436 | // Although it would be easier to read, there are not separate versions of |
---|
| 437 | // _getMarginBox for each browser because: |
---|
| 438 | // 1. the branching is not expensive |
---|
| 439 | // 2. factoring the shared code wastes cycles (function call overhead) |
---|
| 440 | // 3. duplicating the shared code wastes bytes |
---|
| 441 | |
---|
| 442 | geom.getMarginBox = function getMarginBox(/*DomNode*/node, /*Object*/computedStyle){ |
---|
| 443 | // summary: |
---|
| 444 | // returns an object that encodes the width, height, left and top |
---|
| 445 | // positions of the node's margin box. |
---|
| 446 | node = dom.byId(node); |
---|
| 447 | var s = computedStyle || style.getComputedStyle(node), me = geom.getMarginExtents(node, s), |
---|
| 448 | l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode, px = style.toPixelValue, pcs; |
---|
| 449 | //>>excludeStart("webkitMobile", kwArgs.webkitMobile); |
---|
| 450 | if(has("mozilla")){ |
---|
| 451 | // Mozilla: |
---|
| 452 | // If offsetParent has a computed overflow != visible, the offsetLeft is decreased |
---|
| 453 | // by the parent's border. |
---|
| 454 | // We don't want to compute the parent's style, so instead we examine node's |
---|
| 455 | // computed left/top which is more stable. |
---|
| 456 | var sl = parseFloat(s.left), st = parseFloat(s.top); |
---|
| 457 | if(!isNaN(sl) && !isNaN(st)){ |
---|
| 458 | l = sl, t = st; |
---|
| 459 | }else{ |
---|
| 460 | // If child's computed left/top are not parseable as a number (e.g. "auto"), we |
---|
| 461 | // have no choice but to examine the parent's computed style. |
---|
| 462 | if(p && p.style){ |
---|
| 463 | pcs = style.getComputedStyle(p); |
---|
| 464 | if(pcs.overflow != "visible"){ |
---|
| 465 | l += pcs.borderLeftStyle != none ? px(node, pcs.borderLeftWidth) : 0; |
---|
| 466 | t += pcs.borderTopStyle != none ? px(node, pcs.borderTopWidth) : 0; |
---|
| 467 | } |
---|
| 468 | } |
---|
| 469 | } |
---|
| 470 | }else if(has("opera") || (has("ie") == 8 && !has("quirks"))){ |
---|
| 471 | // On Opera and IE 8, offsetLeft/Top includes the parent's border |
---|
| 472 | if(p){ |
---|
| 473 | pcs = style.getComputedStyle(p); |
---|
| 474 | l -= pcs.borderLeftStyle != none ? px(node, pcs.borderLeftWidth) : 0; |
---|
| 475 | t -= pcs.borderTopStyle != none ? px(node, pcs.borderTopWidth) : 0; |
---|
| 476 | } |
---|
| 477 | } |
---|
| 478 | //>>excludeEnd("webkitMobile"); |
---|
| 479 | return {l: l, t: t, w: node.offsetWidth + me.w, h: node.offsetHeight + me.h}; |
---|
| 480 | }; |
---|
| 481 | |
---|
| 482 | geom.getContentBox = function getContentBox(node, computedStyle){ |
---|
| 483 | // clientWidth/Height are important since the automatically account for scrollbars |
---|
| 484 | // fallback to offsetWidth/Height for special cases (see #3378) |
---|
| 485 | node = dom.byId(node); |
---|
| 486 | var s = computedStyle || style.getComputedStyle(node), w = node.clientWidth, h, |
---|
| 487 | pe = geom.getPadExtents(node, s), be = geom.getBorderExtents(node, s); |
---|
| 488 | if(!w){ |
---|
| 489 | w = node.offsetWidth; |
---|
| 490 | h = node.offsetHeight; |
---|
| 491 | }else{ |
---|
| 492 | h = node.clientHeight; |
---|
| 493 | be.w = be.h = 0; |
---|
| 494 | } |
---|
| 495 | // On Opera, offsetLeft includes the parent's border |
---|
| 496 | //>>excludeStart("webkitMobile", kwArgs.webkitMobile); |
---|
| 497 | if(has("opera")){ |
---|
| 498 | pe.l += be.l; |
---|
| 499 | pe.t += be.t; |
---|
| 500 | } |
---|
| 501 | //>>excludeEnd("webkitMobile"); |
---|
| 502 | return {l: pe.l, t: pe.t, w: w - pe.w - be.w, h: h - pe.h - be.h}; |
---|
| 503 | }; |
---|
| 504 | |
---|
| 505 | // Box setters depend on box context because interpretation of width/height styles |
---|
| 506 | // vary wrt box context. |
---|
| 507 | // |
---|
| 508 | // The value of dojo.boxModel is used to determine box context. |
---|
| 509 | // dojo.boxModel can be set directly to change behavior. |
---|
| 510 | // |
---|
| 511 | // Beware of display: inline objects that have padding styles |
---|
| 512 | // because the user agent ignores padding (it's a bogus setup anyway) |
---|
| 513 | // |
---|
| 514 | // Be careful with IMGs because they are inline or block depending on |
---|
| 515 | // browser and browser mode. |
---|
| 516 | // |
---|
| 517 | // Elements other than DIV may have special quirks, like built-in |
---|
| 518 | // margins or padding, or values not detectable via computedStyle. |
---|
| 519 | // In particular, margins on TABLE do not seems to appear |
---|
| 520 | // at all in computedStyle on Mozilla. |
---|
| 521 | |
---|
| 522 | function setBox(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){ |
---|
| 523 | // summary: |
---|
| 524 | // sets width/height/left/top in the current (native) box-model |
---|
| 525 | // dimensions. Uses the unit passed in u. |
---|
| 526 | // node: |
---|
| 527 | // DOM Node reference. Id string not supported for performance |
---|
| 528 | // reasons. |
---|
| 529 | // l: |
---|
| 530 | // left offset from parent. |
---|
| 531 | // t: |
---|
| 532 | // top offset from parent. |
---|
| 533 | // w: |
---|
| 534 | // width in current box model. |
---|
| 535 | // h: |
---|
| 536 | // width in current box model. |
---|
| 537 | // u: |
---|
| 538 | // unit measure to use for other measures. Defaults to "px". |
---|
| 539 | u = u || "px"; |
---|
| 540 | var s = node.style; |
---|
| 541 | if(!isNaN(l)){ |
---|
| 542 | s.left = l + u; |
---|
| 543 | } |
---|
| 544 | if(!isNaN(t)){ |
---|
| 545 | s.top = t + u; |
---|
| 546 | } |
---|
| 547 | if(w >= 0){ |
---|
| 548 | s.width = w + u; |
---|
| 549 | } |
---|
| 550 | if(h >= 0){ |
---|
| 551 | s.height = h + u; |
---|
| 552 | } |
---|
| 553 | } |
---|
| 554 | |
---|
| 555 | function isButtonTag(/*DomNode*/node){ |
---|
| 556 | // summary: |
---|
| 557 | // True if the node is BUTTON or INPUT.type="button". |
---|
| 558 | return node.tagName.toLowerCase() == "button" || |
---|
| 559 | node.tagName.toLowerCase() == "input" && (node.getAttribute("type") || "").toLowerCase() == "button"; // boolean |
---|
| 560 | } |
---|
| 561 | |
---|
| 562 | function usesBorderBox(/*DomNode*/node){ |
---|
| 563 | // summary: |
---|
| 564 | // True if the node uses border-box layout. |
---|
| 565 | |
---|
| 566 | // We could test the computed style of node to see if a particular box |
---|
| 567 | // has been specified, but there are details and we choose not to bother. |
---|
| 568 | |
---|
| 569 | // TABLE and BUTTON (and INPUT type=button) are always border-box by default. |
---|
| 570 | // If you have assigned a different box to either one via CSS then |
---|
| 571 | // box functions will break. |
---|
| 572 | |
---|
| 573 | return geom.boxModel == "border-box" || node.tagName.toLowerCase() == "table" || isButtonTag(node); // boolean |
---|
| 574 | } |
---|
| 575 | |
---|
| 576 | geom.setContentSize = function setContentSize(/*DomNode*/node, /*Object*/box, /*Object*/computedStyle){ |
---|
| 577 | // summary: |
---|
| 578 | // Sets the size of the node's contents, irrespective of margins, |
---|
| 579 | // padding, or borders. |
---|
| 580 | |
---|
| 581 | node = dom.byId(node); |
---|
| 582 | var w = box.w, h = box.h; |
---|
| 583 | if(usesBorderBox(node)){ |
---|
| 584 | var pb = geom.getPadBorderExtents(node, computedStyle); |
---|
| 585 | if(w >= 0){ |
---|
| 586 | w += pb.w; |
---|
| 587 | } |
---|
| 588 | if(h >= 0){ |
---|
| 589 | h += pb.h; |
---|
| 590 | } |
---|
| 591 | } |
---|
| 592 | setBox(node, NaN, NaN, w, h); |
---|
| 593 | }; |
---|
| 594 | |
---|
| 595 | var nilExtents = {l: 0, t: 0, w: 0, h: 0}; |
---|
| 596 | |
---|
| 597 | geom.setMarginBox = function setMarginBox(/*DomNode*/node, /*Object*/box, /*Object*/computedStyle){ |
---|
| 598 | node = dom.byId(node); |
---|
| 599 | var s = computedStyle || style.getComputedStyle(node), w = box.w, h = box.h, |
---|
| 600 | // Some elements have special padding, margin, and box-model settings. |
---|
| 601 | // To use box functions you may need to set padding, margin explicitly. |
---|
| 602 | // Controlling box-model is harder, in a pinch you might set dojo.boxModel. |
---|
| 603 | pb = usesBorderBox(node) ? nilExtents : geom.getPadBorderExtents(node, s), |
---|
| 604 | mb = geom.getMarginExtents(node, s); |
---|
| 605 | if(has("webkit")){ |
---|
| 606 | // on Safari (3.1.2), button nodes with no explicit size have a default margin |
---|
| 607 | // setting an explicit size eliminates the margin. |
---|
| 608 | // We have to swizzle the width to get correct margin reading. |
---|
| 609 | if(isButtonTag(node)){ |
---|
| 610 | var ns = node.style; |
---|
| 611 | if(w >= 0 && !ns.width){ |
---|
| 612 | ns.width = "4px"; |
---|
| 613 | } |
---|
| 614 | if(h >= 0 && !ns.height){ |
---|
| 615 | ns.height = "4px"; |
---|
| 616 | } |
---|
| 617 | } |
---|
| 618 | } |
---|
| 619 | if(w >= 0){ |
---|
| 620 | w = Math.max(w - pb.w - mb.w, 0); |
---|
| 621 | } |
---|
| 622 | if(h >= 0){ |
---|
| 623 | h = Math.max(h - pb.h - mb.h, 0); |
---|
| 624 | } |
---|
| 625 | setBox(node, box.l, box.t, w, h); |
---|
| 626 | }; |
---|
| 627 | |
---|
| 628 | // ============================= |
---|
| 629 | // Positioning |
---|
| 630 | // ============================= |
---|
| 631 | |
---|
| 632 | geom.isBodyLtr = function isBodyLtr(){ |
---|
| 633 | return (win.body().dir || win.doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean |
---|
| 634 | }; |
---|
| 635 | |
---|
| 636 | geom.docScroll = function docScroll(){ |
---|
| 637 | var node = win.doc.parentWindow || win.doc.defaultView; // use UI window, not dojo.global window |
---|
| 638 | return "pageXOffset" in node ? {x: node.pageXOffset, y: node.pageYOffset } : |
---|
| 639 | (node = has("quirks") ? win.body() : win.doc.documentElement, |
---|
| 640 | {x: geom.fixIeBiDiScrollLeft(node.scrollLeft || 0), y: node.scrollTop || 0 }); |
---|
| 641 | }; |
---|
| 642 | |
---|
| 643 | //>>excludeStart("webkitMobile", kwArgs.webkitMobile); |
---|
| 644 | geom.getIeDocumentElementOffset = function getIeDocumentElementOffset(){ |
---|
| 645 | //NOTE: assumes we're being called in an IE browser |
---|
| 646 | |
---|
| 647 | var de = win.doc.documentElement; // only deal with HTML element here, position() handles body/quirks |
---|
| 648 | |
---|
| 649 | if(has("ie") < 8){ |
---|
| 650 | var r = de.getBoundingClientRect(), // works well for IE6+ |
---|
| 651 | l = r.left, t = r.top; |
---|
| 652 | if(has("ie") < 7){ |
---|
| 653 | l += de.clientLeft; // scrollbar size in strict/RTL, or, |
---|
| 654 | t += de.clientTop; // HTML border size in strict |
---|
| 655 | } |
---|
| 656 | return { |
---|
| 657 | x: l < 0 ? 0 : l, // FRAME element border size can lead to inaccurate negative values |
---|
| 658 | y: t < 0 ? 0 : t |
---|
| 659 | }; |
---|
| 660 | }else{ |
---|
| 661 | return { |
---|
| 662 | x: 0, |
---|
| 663 | y: 0 |
---|
| 664 | }; |
---|
| 665 | } |
---|
| 666 | }; |
---|
| 667 | //>>excludeEnd("webkitMobile"); |
---|
| 668 | |
---|
| 669 | geom.fixIeBiDiScrollLeft = function fixIeBiDiScrollLeft(/*Integer*/ scrollLeft){ |
---|
| 670 | // In RTL direction, scrollLeft should be a negative value, but IE |
---|
| 671 | // returns a positive one. All codes using documentElement.scrollLeft |
---|
| 672 | // must call this function to fix this error, otherwise the position |
---|
| 673 | // will offset to right when there is a horizontal scrollbar. |
---|
| 674 | |
---|
| 675 | //>>excludeStart("webkitMobile", kwArgs.webkitMobile); |
---|
| 676 | var ie = has("ie"); |
---|
| 677 | if(ie && !geom.isBodyLtr()){ |
---|
| 678 | var qk = has("quirks"), |
---|
| 679 | de = qk ? win.body() : win.doc.documentElement; |
---|
| 680 | if(ie == 6 && !qk && win.global.frameElement && de.scrollHeight > de.clientHeight){ |
---|
| 681 | scrollLeft += de.clientLeft; // workaround ie6+strict+rtl+iframe+vertical-scrollbar bug where clientWidth is too small by clientLeft pixels |
---|
| 682 | } |
---|
| 683 | return (ie < 8 || qk) ? (scrollLeft + de.clientWidth - de.scrollWidth) : -scrollLeft; // Integer |
---|
| 684 | } |
---|
| 685 | //>>excludeEnd("webkitMobile"); |
---|
| 686 | return scrollLeft; // Integer |
---|
| 687 | }; |
---|
| 688 | |
---|
| 689 | geom.position = function(/*DomNode*/node, /*Boolean?*/includeScroll){ |
---|
| 690 | node = dom.byId(node); |
---|
| 691 | var db = win.body(), |
---|
| 692 | dh = db.parentNode, |
---|
| 693 | ret = node.getBoundingClientRect(); |
---|
| 694 | ret = {x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top}; |
---|
| 695 | //>>excludeStart("webkitMobile", kwArgs.webkitMobile); |
---|
| 696 | if(has("ie")){ |
---|
| 697 | // On IE there's a 2px offset that we need to adjust for, see dojo.getIeDocumentElementOffset() |
---|
| 698 | var offset = geom.getIeDocumentElementOffset(); |
---|
| 699 | |
---|
| 700 | // fixes the position in IE, quirks mode |
---|
| 701 | ret.x -= offset.x + (has("quirks") ? db.clientLeft + db.offsetLeft : 0); |
---|
| 702 | ret.y -= offset.y + (has("quirks") ? db.clientTop + db.offsetTop : 0); |
---|
| 703 | }else if(has("ff") == 3){ |
---|
| 704 | // In FF3 you have to subtract the document element margins. |
---|
| 705 | // Fixed in FF3.5 though. |
---|
| 706 | var cs = style.getComputedStyle(dh), px = style.toPixelValue; |
---|
| 707 | ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth); |
---|
| 708 | ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth); |
---|
| 709 | } |
---|
| 710 | //>>excludeEnd("webkitMobile"); |
---|
| 711 | // account for document scrolling |
---|
| 712 | // if offsetParent is used, ret value already includes scroll position |
---|
| 713 | // so we may have to actually remove that value if !includeScroll |
---|
| 714 | if(includeScroll){ |
---|
| 715 | var scroll = geom.docScroll(); |
---|
| 716 | ret.x += scroll.x; |
---|
| 717 | ret.y += scroll.y; |
---|
| 718 | } |
---|
| 719 | |
---|
| 720 | return ret; // Object |
---|
| 721 | }; |
---|
| 722 | |
---|
| 723 | // random "private" functions wildly used throughout the toolkit |
---|
| 724 | |
---|
| 725 | geom.getMarginSize = function getMarginSize(/*DomNode*/node, /*Object*/computedStyle){ |
---|
| 726 | node = dom.byId(node); |
---|
| 727 | var me = geom.getMarginExtents(node, computedStyle || style.getComputedStyle(node)); |
---|
| 728 | var size = node.getBoundingClientRect(); |
---|
| 729 | return { |
---|
| 730 | w: (size.right - size.left) + me.w, |
---|
| 731 | h: (size.bottom - size.top) + me.h |
---|
| 732 | } |
---|
| 733 | }; |
---|
| 734 | |
---|
| 735 | geom.normalizeEvent = function(event){ |
---|
| 736 | // summary: |
---|
| 737 | // Normalizes the geometry of a DOM event, normalizing the pageX, pageY, |
---|
| 738 | // offsetX, offsetY, layerX, and layerX properties |
---|
| 739 | // event: Object |
---|
| 740 | if(!("layerX" in event)){ |
---|
| 741 | event.layerX = event.offsetX; |
---|
| 742 | event.layerY = event.offsetY; |
---|
| 743 | } |
---|
| 744 | if(!has("dom-addeventlistener")){ |
---|
| 745 | // old IE version |
---|
| 746 | // FIXME: scroll position query is duped from dojo.html to |
---|
| 747 | // avoid dependency on that entire module. Now that HTML is in |
---|
| 748 | // Base, we should convert back to something similar there. |
---|
| 749 | var se = event.target; |
---|
| 750 | var doc = (se && se.ownerDocument) || document; |
---|
| 751 | // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used |
---|
| 752 | // here rather than document.body |
---|
| 753 | var docBody = has("quirks") ? doc.body : doc.documentElement; |
---|
| 754 | var offset = geom.getIeDocumentElementOffset(); |
---|
| 755 | event.pageX = event.clientX + geom.fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x; |
---|
| 756 | event.pageY = event.clientY + (docBody.scrollTop || 0) - offset.y; |
---|
| 757 | } |
---|
| 758 | }; |
---|
| 759 | |
---|
| 760 | // TODO: evaluate separate getters/setters for position and sizes? |
---|
| 761 | |
---|
| 762 | return geom; |
---|
| 763 | }); |
---|