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