source: Dev/branches/rest-dojo-ui/client/dojo/dom-geometry.js @ 263

Last change on this file since 263 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 26.8 KB
RevLine 
[256]1define(["./_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});
Note: See TracBrowser for help on using the repository browser.