4 name: Element.Dimensions
6 description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
8 license: MIT-style license.
11 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
12 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
14 requires: [Element, Element.Style]
16 provides: [Element.Dimensions]
23 var element = document.createElement('div'),
24 child = document.createElement('div');
25 element.style.height = '0';
26 element.appendChild(child);
27 var brokenOffsetParent = (child.offsetParent === element);
28 element = child = null;
30 var heightComponents = ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth'],
31 widthComponents = ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'];
33 var svgCalculateSize = function(el){
35 var gCS = window.getComputedStyle(el),
36 bounds = {x: 0, y: 0};
38 heightComponents.each(function(css){
39 bounds.y += parseFloat(gCS[css]);
41 widthComponents.each(function(css){
42 bounds.x += parseFloat(gCS[css]);
47 var isOffset = function(el){
48 return styleString(el, 'position') != 'static' || isBody(el);
51 var isOffsetStatic = function(el){
52 return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName);
57 scrollTo: function(x, y){
59 this.getWindow().scrollTo(x, y);
68 if (isBody(this)) return this.getWindow().getSize();
71 // This if clause is because IE8- cannot calculate getBoundingClientRect of elements with visibility hidden.
72 if (!window.getComputedStyle) return {x: this.offsetWidth, y: this.offsetHeight};
75 // This svg section under, calling `svgCalculateSize()`, can be removed when FF fixed the svg size bug.
76 // Bug info: https://bugzilla.mozilla.org/show_bug.cgi?id=530985
77 if (this.get('tag') == 'svg') return svgCalculateSize(this);
79 var bounds = this.getBoundingClientRect();
80 return {x: bounds.width, y: bounds.height};
83 getScrollSize: function(){
84 if (isBody(this)) return this.getWindow().getScrollSize();
85 return {x: this.scrollWidth, y: this.scrollHeight};
88 getScroll: function(){
89 if (isBody(this)) return this.getWindow().getScroll();
90 return {x: this.scrollLeft, y: this.scrollTop};
93 getScrolls: function(){
94 var element = this.parentNode, position = {x: 0, y: 0};
95 while (element && !isBody(element)){
96 position.x += element.scrollLeft;
97 position.y += element.scrollTop;
98 element = element.parentNode;
103 getOffsetParent: brokenOffsetParent ? function(){
105 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
107 var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset;
108 while ((element = element.parentNode)){
109 if (isOffsetCheck(element)) return element;
114 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
117 return element.offsetParent;
122 getOffsets: function(){
123 var hasGetBoundingClientRect = this.getBoundingClientRect;
125 hasGetBoundingClientRect = hasGetBoundingClientRect && !Browser.Platform.ios
127 if (hasGetBoundingClientRect){
128 var bound = this.getBoundingClientRect(),
129 html = document.id(this.getDocument().documentElement),
130 htmlScroll = html.getScroll(),
131 elemScrolls = this.getScrolls(),
132 isFixed = (styleString(this, 'position') == 'fixed');
135 x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
136 y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
140 var element = this, position = {x: 0, y: 0};
141 if (isBody(this)) return position;
143 while (element && !isBody(element)){
144 position.x += element.offsetLeft;
145 position.y += element.offsetTop;
147 if (Browser.firefox){
148 if (!borderBox(element)){
149 position.x += leftBorder(element);
150 position.y += topBorder(element);
152 var parent = element.parentNode;
153 if (parent && styleString(parent, 'overflow') != 'visible'){
154 position.x += leftBorder(parent);
155 position.y += topBorder(parent);
157 } else if (element != this && Browser.safari){
158 position.x += leftBorder(element);
159 position.y += topBorder(element);
162 element = element.offsetParent;
165 if (Browser.firefox && !borderBox(this)){
166 position.x -= leftBorder(this);
167 position.y -= topBorder(this);
173 getPosition: function(relative){
174 var offset = this.getOffsets(),
175 scroll = this.getScrolls();
177 x: offset.x - scroll.x,
178 y: offset.y - scroll.y
181 if (relative && (relative = document.id(relative))){
182 var relativePosition = relative.getPosition();
183 return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)};
188 getCoordinates: function(element){
189 if (isBody(this)) return this.getWindow().getCoordinates();
190 var position = this.getPosition(element),
191 size = this.getSize();
198 obj.right = obj.left + obj.width;
199 obj.bottom = obj.top + obj.height;
203 computePosition: function(obj){
205 left: obj.x - styleNumber(this, 'margin-left'),
206 top: obj.y - styleNumber(this, 'margin-top')
210 setPosition: function(obj){
211 return this.setStyles(this.computePosition(obj));
217 [Document, Window].invoke('implement', {
220 var doc = getCompatElement(this);
221 return {x: doc.clientWidth, y: doc.clientHeight};
224 getScroll: function(){
225 var win = this.getWindow(), doc = getCompatElement(this);
226 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
229 getScrollSize: function(){
230 var doc = getCompatElement(this),
231 min = this.getSize(),
232 body = this.getDocument().body;
234 return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)};
237 getPosition: function(){
241 getCoordinates: function(){
242 var size = this.getSize();
243 return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
250 var styleString = Element.getComputedStyle;
252 function styleNumber(element, style){
253 return styleString(element, style).toInt() || 0;
256 function borderBox(element){
257 return styleString(element, '-moz-box-sizing') == 'border-box';
260 function topBorder(element){
261 return styleNumber(element, 'border-top-width');
264 function leftBorder(element){
265 return styleNumber(element, 'border-left-width');
268 function isBody(element){
269 return (/^(?:body|html)$/i).test(element.tagName);
272 function getCompatElement(element){
273 var doc = element.getDocument();
274 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
280 Element.alias({position: 'setPosition'}); //compatability
282 [Window, Document, Element].invoke('implement', {
284 getHeight: function(){
285 return this.getSize().y;
288 getWidth: function(){
289 return this.getSize().x;
292 getScrollTop: function(){
293 return this.getScroll().y;
296 getScrollLeft: function(){
297 return this.getScroll().x;
300 getScrollHeight: function(){
301 return this.getScrollSize().y;
304 getScrollWidth: function(){
305 return this.getScrollSize().x;
309 return this.getPosition().y;
313 return this.getPosition().x;