1/* 2--- 3 4name: Element.Dimensions 5 6description: Contains methods to work with size, scroll, or positioning of Elements and the window object. 7 8license: MIT-style license. 9 10credits: 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). 13 14requires: [Element, Element.Style] 15 16provides: [Element.Dimensions] 17 18... 19*/ 20 21(function(){ 22 23var element = document.createElement('div'), 24 child = document.createElement('div'); 25element.style.height = '0'; 26element.appendChild(child); 27var brokenOffsetParent = (child.offsetParent === element); 28element = child = null; 29 30var heightComponents = ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth'], 31 widthComponents = ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth']; 32 33var svgCalculateSize = function(el){ 34 35 var gCS = window.getComputedStyle(el), 36 bounds = {x: 0, y: 0}; 37 38 heightComponents.each(function(css){ 39 bounds.y += parseFloat(gCS[css]); 40 }); 41 widthComponents.each(function(css){ 42 bounds.x += parseFloat(gCS[css]); 43 }); 44 return bounds; 45}; 46 47var isOffset = function(el){ 48 return styleString(el, 'position') != 'static' || isBody(el); 49}; 50 51var isOffsetStatic = function(el){ 52 return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName); 53}; 54 55Element.implement({ 56 57 scrollTo: function(x, y){ 58 if (isBody(this)){ 59 this.getWindow().scrollTo(x, y); 60 } else { 61 this.scrollLeft = x; 62 this.scrollTop = y; 63 } 64 return this; 65 }, 66 67 getSize: function(){ 68 if (isBody(this)) return this.getWindow().getSize(); 69 70 //<ltIE9> 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}; 73 //</ltIE9> 74 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); 78 79 var bounds = this.getBoundingClientRect(); 80 return {x: bounds.width, y: bounds.height}; 81 }, 82 83 getScrollSize: function(){ 84 if (isBody(this)) return this.getWindow().getScrollSize(); 85 return {x: this.scrollWidth, y: this.scrollHeight}; 86 }, 87 88 getScroll: function(){ 89 if (isBody(this)) return this.getWindow().getScroll(); 90 return {x: this.scrollLeft, y: this.scrollTop}; 91 }, 92 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; 99 } 100 return position; 101 }, 102 103 getOffsetParent: brokenOffsetParent ? function(){ 104 var element = this; 105 if (isBody(element) || styleString(element, 'position') == 'fixed') return null; 106 107 var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset; 108 while ((element = element.parentNode)){ 109 if (isOffsetCheck(element)) return element; 110 } 111 return null; 112 } : function(){ 113 var element = this; 114 if (isBody(element) || styleString(element, 'position') == 'fixed') return null; 115 116 try { 117 return element.offsetParent; 118 } catch(e){} 119 return null; 120 }, 121 122 getOffsets: function(){ 123 var hasGetBoundingClientRect = this.getBoundingClientRect; 124//<1.4compat> 125 hasGetBoundingClientRect = hasGetBoundingClientRect && !Browser.Platform.ios 126//</1.4compat> 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'); 133 134 return { 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 137 }; 138 } 139 140 var element = this, position = {x: 0, y: 0}; 141 if (isBody(this)) return position; 142 143 while (element && !isBody(element)){ 144 position.x += element.offsetLeft; 145 position.y += element.offsetTop; 146//<1.4compat> 147 if (Browser.firefox){ 148 if (!borderBox(element)){ 149 position.x += leftBorder(element); 150 position.y += topBorder(element); 151 } 152 var parent = element.parentNode;
153 if (parent && styleString(parent, 'overflow') != 'visible'){ 154 position.x += leftBorder(parent); 155 position.y += topBorder(parent); 156 } 157 } else if (element != this && Browser.safari){ 158 position.x += leftBorder(element); 159 position.y += topBorder(element); 160 } 161//</1.4compat> 162 element = element.offsetParent; 163 } 164//<1.4compat> 165 if (Browser.firefox && !borderBox(this)){ 166 position.x -= leftBorder(this); 167 position.y -= topBorder(this); 168 } 169//</1.4compat> 170 return position; 171 }, 172 173 getPosition: function(relative){ 174 var offset = this.getOffsets(), 175 scroll = this.getScrolls(); 176 var position = { 177 x: offset.x - scroll.x, 178 y: offset.y - scroll.y 179 }; 180 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)}; 184 } 185 return position; 186 }, 187 188 getCoordinates: function(element){ 189 if (isBody(this)) return this.getWindow().getCoordinates(); 190 var position = this.getPosition(element), 191 size = this.getSize(); 192 var obj = { 193 left: position.x, 194 top: position.y, 195 width: size.x, 196 height: size.y 197 }; 198 obj.right = obj.left + obj.width; 199 obj.bottom = obj.top + obj.height; 200 return obj; 201 }, 202 203 computePosition: function(obj){ 204 return { 205 left: obj.x - styleNumber(this, 'margin-left'), 206 top: obj.y - styleNumber(this, 'margin-top') 207 }; 208 }, 209 210 setPosition: function(obj){ 211 return this.setStyles(this.computePosition(obj)); 212 } 213 214}); 215 216 217[Document, Window].invoke('implement', { 218 219 getSize: function(){ 220 var doc = getCompatElement(this); 221 return {x: doc.clientWidth, y: doc.clientHeight}; 222 }, 223 224 getScroll: function(){ 225 var win = this.getWindow(), doc = getCompatElement(this); 226 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; 227 }, 228 229 getScrollSize: function(){ 230 var doc = getCompatElement(this), 231 min = this.getSize(), 232 body = this.getDocument().body; 233 234 return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)}; 235 }, 236 237 getPosition: function(){ 238 return {x: 0, y: 0}; 239 }, 240 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}; 244 } 245 246}); 247 248// private methods 249
250var styleString = Element.getComputedStyle; 251 252function styleNumber(element, style){ 253 return styleString(element, style).toInt() || 0; 254} 255 256function borderBox(element){ 257 return styleString(element, '-moz-box-sizing') == 'border-box'; 258} 259 260function topBorder(element){ 261 return styleNumber(element, 'border-top-width'); 262} 263 264function leftBorder(element){ 265 return styleNumber(element, 'border-left-width'); 266} 267 268function isBody(element){ 269 return (/^(?:body|html)$/i).test(element.tagName); 270} 271 272function getCompatElement(element){ 273 var doc = element.getDocument(); 274 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 275} 276 277})(); 278 279//aliases 280Element.alias({position: 'setPosition'}); //compatability 281 282[Window, Document, Element].invoke('implement', { 283 284 getHeight: function(){ 285 return this.getSize().y; 286 }, 287 288 getWidth: function(){ 289 return this.getSize().x; 290 }, 291 292 getScrollTop: function(){ 293 return this.getScroll().y; 294 }, 295 296 getScrollLeft: function(){ 297 return this.getScroll().x; 298 }, 299 300 getScrollHeight: function(){ 301 return this.getScrollSize().y; 302 }, 303 304 getScrollWidth: function(){ 305 return this.getScrollSize().x; 306 }, 307 308 getTop: function(){ 309 return this.getPosition().y; 310 }, 311 312 getLeft: function(){ 313 return this.getPosition().x; 314 } 315 316});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.