added Brandon's offset function
[jquery.git] / src / dimensions / dimensions.js
1 /** \r
2  * This plugin overrides jQuery's height() and width() functions and\r
3  * adds more handy stuff for cross-browser compatibility.\r
4  */\r
5 \r
6 /**\r
7  * Returns the css height value for the first matched element.\r
8  * If used on document, returns the document's height (innerHeight)\r
9  * If used on window, returns the viewport's (window) height\r
10  *\r
11  * @example $("#testdiv").height()\r
12  * @result "200px"
13  *
14  * @example $(document).height();
15  * @result 800
16  *
17  * @example $(window).height();
18  * @result 400\r
19  * \r
20  * @name height\r
21  * @type Object\r
22  * @cat Dimensions\r
23  */\r
24 $.fn.height = function() {\r
25         if ( this.get(0) == window )
26                 return self.innerHeight ||
27                         jQuery.boxModel && document.documentElement.clientHeight ||\r
28                         document.body.clientHeight;\r
29         \r
30         if ( this.get(0) == document )\r
31                 return Math.max( document.body.scrollHeight, document.body.offsetHeight );\r
32         \r
33         return this.css("height");\r
34 };
35 \r
36 /**\r
37  * Returns the css width value for the first matched element.\r
38  * If used on document, returns the document's width (innerWidth)\r
39  * If used on window, returns the viewport's (window) width\r
40  *\r
41  * @example $("#testdiv").width()\r
42  * @result "200px"
43  *
44  * @example $(document).width();
45  * @result 800
46  *
47  * @example $(window).width();
48  * @result 400\r
49  * \r
50  * @name width\r
51  * @type Object\r
52  * @cat Dimensions\r
53  */\r
54 $.fn.width = function() {\r
55         if ( this.get(0) == window )
56                 return self.innerWidth ||
57                         jQuery.boxModel && document.documentElement.clientWidth ||\r
58                         document.body.clientWidth;\r
59         \r
60         if ( this.get(0) == document )\r
61                 return Math.max( document.body.scrollWidth, document.body.offsetWidth );\r
62         \r
63         return this.css("width");\r
64 };
65 \r
66 /**\r
67  * Returns the inner height value (without border) for the first matched element.\r
68  * If used on document, returns the document's height (innerHeight)\r
69  * If used on window, returns the viewport's (window) height\r
70  *\r
71  * @example $("#testdiv").innerHeight()\r
72  * @result 800\r
73  * \r
74  * @name innerHeight\r
75  * @type Number\r
76  * @cat Dimensions\r
77  */\r
78 $.fn.innerHeight = function() {\r
79         return this.get(0) == window || this.get(0) == document ?
80                 this.height() :
81                 this.get(0).offsetHeight - parseInt(this.css("borderTop") || 0) - parseInt(this.css("borderBottom") || 0);\r
82 };
83 \r
84 /**\r
85  * Returns the inner width value (without border) for the first matched element.\r
86  * If used on document, returns the document's Width (innerWidth)\r
87  * If used on window, returns the viewport's (window) width\r
88  *\r
89  * @example $("#testdiv").innerWidth()\r
90  * @result 1000\r
91  * \r
92  * @name innerWidth\r
93  * @type Number\r
94  * @cat Dimensions\r
95  */\r
96 $.fn.innerWidth = function() {\r
97         return this.get(0) == window || this.get(0) == document ?
98                 this.width() :
99                 this.get(0).offsetWidth - parseInt(this.css("borderLeft") || 0) - parseInt(this.css("borderRight") || 0);\r
100 };
101 \r
102 /**\r
103  * Returns the outer height value (including border) for the first matched element.\r
104  * Cannot be used on document or window.\r
105  *\r
106  * @example $("#testdiv").outerHeight()\r
107  * @result 1000\r
108  * \r
109  * @name outerHeight\r
110  * @type Number\r
111  * @cat Dimensions\r
112  */\r
113 $.fn.outerHeight = function() {\r
114         return this.get(0) == window || this.get(0) == document ?
115                 this.height() :
116                 this.get(0).offsetHeight;       \r
117 };
118 \r
119 /**\r
120  * Returns the outer width value (including border) for the first matched element.\r
121  * Cannot be used on document or window.\r
122  *\r
123  * @example $("#testdiv").outerWidth()\r
124  * @result 1000\r
125  * \r
126  * @name outerWidth\r
127  * @type Number\r
128  * @cat Dimensions\r
129  */\r
130 $.fn.outerWidth = function() {\r
131         return this.get(0) == window || this.get(0) == document ?
132                 this.width() :
133                 this.get(0).offsetWidth;        \r
134 };
135 \r
136 /**\r
137  * Returns how many pixels the user has scrolled to the right (scrollLeft).\r
138  * Works on containers with overflow: auto and window/document.\r
139  *\r
140  * @example $("#testdiv").scrollLeft()\r
141  * @result 100\r
142  * \r
143  * @name scrollLeft\r
144  * @type Number\r
145  * @cat Dimensions\r
146  */\r
147 $.fn.scrollLeft = function() {\r
148         if ( this.get(0) == window || this.get(0) == document )
149                 return self.pageXOffset ||
150                         jQuery.boxModel && document.documentElement.scrollLeft ||
151                         document.body.scrollLeft;
152         \r
153         return this.get(0).scrollLeft;\r
154 };
155 \r
156 /**\r
157  * Returns how many pixels the user has scrolled to the bottom (scrollTop).\r
158  * Works on containers with overflow: auto and window/document.\r
159  *\r
160  * @example $("#testdiv").scrollTop()\r
161  * @result 100\r
162  * \r
163  * @name scrollTop\r
164  * @type Number\r
165  * @cat Dimensions\r
166  */\r
167 $.fn.scrollTop = function() {\r
168         if ( this.get(0) == window || this.get(0) == document )
169                 return self.pageYOffset ||
170                         jQuery.boxModel && document.documentElement.scrollTop ||
171                         document.body.scrollTop;
172 \r
173         return this.get(0).scrollTop;\r
174 };\r
175 \r
176 /* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)\r
177  * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) \r
178  * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\r
179  */\r
180 \r
181 /**\r
182  * This returns an object with top, left, width, height, borderLeft,\r
183  * borderTop, marginLeft, marginTop, scrollLeft, scrollTop, \r
184  * pageXOffset, pageYOffset.\r
185  *\r
186  * The top and left values include the scroll offsets but the\r
187  * scrollLeft and scrollTop properties of the returned object\r
188  * are the combined scroll offets of the parent elements \r
189  * (not including the window scroll offsets). This is not the\r
190  * same as the element's scrollTop and scrollLeft.\r
191  * \r
192  * For accurate readings make sure to use pixel values.\r
193  *\r
194  * @name offset \r
195  * @type Object\r
196  * @cat Dimensions\r
197  * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)\r
198  */\r
199 /**\r
200  * This returns an object with top, left, width, height, borderLeft,\r
201  * borderTop, marginLeft, marginTop, scrollLeft, scrollTop, \r
202  * pageXOffset, pageYOffset.\r
203  *\r
204  * The top and left values include the scroll offsets but the\r
205  * scrollLeft and scrollTop properties of the returned object\r
206  * are the combined scroll offets of the parent elements \r
207  * (not including the window scroll offsets). This is not the\r
208  * same as the element's scrollTop and scrollLeft.\r
209  * \r
210  * For accurate readings make sure to use pixel values.\r
211  *\r
212  * @name offset \r
213  * @type Object\r
214  * @param String refElement This is an expression. The offset returned will be relative to the first matched element.\r
215  * @cat Dimensions\r
216  * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)\r
217  */\r
218 /**\r
219  * This returns an object with top, left, width, height, borderLeft,\r
220  * borderTop, marginLeft, marginTop, scrollLeft, scrollTop, \r
221  * pageXOffset, pageYOffset.\r
222  *\r
223  * The top and left values include the scroll offsets but the\r
224  * scrollLeft and scrollTop properties of the returned object\r
225  * are the combined scroll offets of the parent elements \r
226  * (not including the window scroll offsets). This is not the\r
227  * same as the element's scrollTop and scrollLeft.\r
228  * \r
229  * For accurate readings make sure to use pixel values.\r
230  *\r
231  * @name offset \r
232  * @type Object\r
233  * @param jQuery refElement The offset returned will be relative to the first matched element.\r
234  * @cat Dimensions\r
235  * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)\r
236  */\r
237 /**\r
238  * This returns an object with top, left, width, height, borderLeft,\r
239  * borderTop, marginLeft, marginTop, scrollLeft, scrollTop, \r
240  * pageXOffset, pageYOffset.\r
241  *\r
242  * The top and left values include the scroll offsets but the\r
243  * scrollLeft and scrollTop properties of the returned object\r
244  * are the combined scroll offets of the parent elements \r
245  * (not including the window scroll offsets). This is not the\r
246  * same as the element's scrollTop and scrollLeft.\r
247  * \r
248  * For accurate readings make sure to use pixel values.\r
249  *\r
250  * @name offset \r
251  * @type Object\r
252  * @param HTMLElement refElement The offset returned will be relative to this element.\r
253  * @cat Dimensions\r
254  * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)\r
255  */\r
256 $.fn.offset = function(refElem) {\r
257         if (!this[0]) throw '$.fn.offset requires an element.';\r
258         \r
259         refElem = (refElem) ? $(refElem)[0] : null;\r
260         var x = 0, y = 0, elm = this[0], parent = this[0], pos = null, borders = [0,0], isElm = true, sl = 0, st = 0;\r
261         do {\r
262                 if (parent.tagName == 'BODY' || parent.tagName == 'HTML') {\r
263                         // Safari and IE don't add margin for static and relative\r
264                         if (($.browser.safari || $.browser.msie) && pos != 'absolute') {\r
265                                 x += parseInt($.css(parent, 'marginLeft')) || 0;\r
266                                 y += parseInt($.css(parent, 'marginTop'))  || 0;\r
267                         }\r
268                         break;\r
269                 }\r
270                 \r
271                 pos    = $.css(parent, 'position');\r
272                 border = [parseInt($.css(parent, 'borderLeftWidth')) || 0,\r
273                                                         parseInt($.css(parent, 'borderTopWidth'))  || 0];\r
274                 sl = parent.scrollLeft;\r
275                 st = parent.scrollTop;\r
276                 \r
277                 x += (parent.offsetLeft || 0) + border[0] - sl;\r
278                 y += (parent.offsetTop  || 0) + border[1] - st;\r
279                 \r
280                 // Safari and Opera include the border already for parents with position = absolute|relative\r
281                 if (($.browser.safari || $.browser.opera) && !isElm && (pos == 'absolute' || pos == 'relative')) {\r
282                         x -= border[0];\r
283                         y -= border[1];\r
284                 }\r
285                 \r
286                 parent = parent.offsetParent;\r
287                 isElm  = false;\r
288         } while(parent);\r
289         \r
290         if (refElem) {\r
291                 var offset = $(refElem).offset();\r
292                 x  = x  - offset.left;\r
293                 y  = y  - offset.top;\r
294                 sl = sl - offset.scrollLeft;\r
295                 st = st - offset.scrollTop;\r
296         }\r
297         \r
298         return {\r
299                 top:  y,\r
300                 left: x,\r
301                 width:  elm.offsetWidth,\r
302                 height: elm.offsetHeight,\r
303                 borderTop:  parseInt($.css(elm, 'borderTopWidth'))  || 0,\r
304                 borderLeft: parseInt($.css(elm, 'borderLeftWidth')) || 0,\r
305                 marginTop:  parseInt($.css(elm, 'marginTopWidth'))  || 0,\r
306                 marginLeft: parseInt($.css(elm, 'marginLeftWidth')) || 0,\r
307                 scrollTop:  st,\r
308                 scrollLeft: sl,\r
309                 pageYOffset: window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop  || 0,\r
310                 pageXOffset: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0\r
311         };\r
312 };