Skip to content

Instantly share code, notes, and snippets.

@ibolmo
Created March 29, 2009 22:29
Show Gist options
  • Save ibolmo/87544 to your computer and use it in GitHub Desktop.
Save ibolmo/87544 to your computer and use it in GitHub Desktop.
/*
Script: Element.Dimensions.js
Contains methods to work with size, scroll, or positioning of Elements and the window object.
License:
MIT-style license.
Credits:
- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
*/
(function(){
var quirks, compute = Element.getComputedStyle;
var checkQuirks = function(){
var temp = document.createElement('div');
temp.style.cssText = 'position:absolute;width:1px;height:1px;left:0;top:0;margin:0;border:0;visibility:hidden';
temp.innerHTML = '<div style="position:absolute;width:1px;height:1px;left:0;top:0;margin:0;border:5px solid #000;padding:0"><div></div></div><table style="position:absolute;width:1px;height:1px;top:0;left:0;margin:0;border:5px solid #000;padding:0" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
var body = document.body, bodyCssText = body.style.cssText, inner = temp.firstChild, div = inner.firstChild, td = inner.nextSibling.firstChild.firstChild;
body.insertBefore(temp, body.firstChild);
Browser.Quirks = quirks = {
addsBorder: div.offsetType == 5,
addsBorderForTableAndCells: td.offsetTop == 5,
supportsFixedPosition: (div.style.cssText = 'position:fixed;top:20px;') && div.offsetTop >= 15,
substractsBorderForOverflowHidden: (div.style.cssText = 'overflow:hidden;position:relative') && div.offsetTop == -5,
includesMarginInBody: (body.style.marginTop = '1px') && body.offsetTop == 0
};
body.style.cssText = bodyCssText;
body.removeChild(temp);
checkQuirks = null;
};
var computeFloat = function(element, style){
return parseFloat(compute(element, style) || 0);
};
var getCompatElement = function(obj){
var doc = obj.getDocument();
return doc.compatElement || (doc.compatElement = doc.standardMode ? doc.html : doc.body);
};
var getPosition = document.documentElement.getBoundingClientRect ? function(){
var box = this.getBoundingClientRect(), scroll = this.getScroll(), pos = {x: box.left + scroll.x, y: box.top + scroll.y};
if (Browser.ie){
var doc = this.ownerDocument, std = doc.compatMode == 'CSS1Compat', html = doc.documentElement;
pos.x -= std ? html.clientLeft : parseInt(html.currentStyle.borderLeftWidth, 10) || 2;
pos.y -= std ? html.clientTop : parseInt(html.currentStyle.borderTopWidth, 10) || 2;
}
return pos;
} : function(){
var el = this, offsetParent = el.offsetParent, doc = el.ownerDocument, html = doc.documentElement, body = doc.body;
var defaultView = doc.defaultView, computed = defaultView.getComputedStyle(el, null), x = el.offsetLeft, y = el.offsetTop;
while (!quirks.supportsFixedPosition || computed.position != 'fixed' && (el = el.parentNode) && el !== body && el !== html){
computed = defaultView.getComputedStyle(el, null);
x -= el.scrollLeft, y -= el.scrollTop;
if (el == offsetParent){
x += el.offsetLeft, y += el.offsetTop;
if (!quirks.addsBorder && !(quirks.addsBorderForTableAndCells && /^t(able|d|h)$/i.test(el.tagName))){
x += parseFloat(computed.borderLeftWidth) || 0;
y += parseFloat(computed.borderTopWidth) || 0;
}
offsetParent = el.offsetParent;
}
if (quirks.subtractBorderForOverflowHidden && computed.overflow != 'visible'){
x += parseFloat(computed.borderLeftWidth) || 0;
y += parseFloat(computed.borderTopWidth) || 0;
}
}
if (/^relative|static$/.test(prevComputed.position)) x += body.offsetLeft, y += body.offsetTop;
if (quirks.supportsFixedPosition && prevComputed.position == 'fixed'){
x += Math.max(html.scrollLeft, body.scrollLeft);
y += Math.max(html.scrollTop, body.scrollTop);
}
return {x: x, y: y};
};
var getBodyPosition = function(body){
if (checkQuirks) checkQuirks();
var x = body.offsetLeft, y = body.offsetTop;
if (!Browser.includesMarginInBody) x += computeFloat(body, 'margin-left'), y += computeFloat(body, 'margin-top');
return {x: x, y: y};
};
Element.implement({
scrollTo: function(x, y){
if (this == this.ownerDocument.body){
this.getWindow().scrollTo(x, y);
} else {
this.scrollLeft = x;
this.scrollTop = y;
}
return this;
},
getSize: function(){
return {x: this.offsetWidth, y: this.offsetHeight};
},
getScrollSize: function(){
return {x: this.scrollWidth, y: this.scrollHeight};
},
getScroll: function(){
return (/^input$/i).test(this.tagName) ? {x: 0, y: 0} : {x: this.scrollLeft, y: this.scrollTop};
},
getPosition: function(relative) {
if (checkQuirks) checkQuirks();
var position = (this == this.ownerDocument.body) ? getBodyPosition(this) : getPosition.call(this);
if (relative && (relative = $(relative)) {
relative = relative.getPosition();
position.x -= relative.x;
position.y -= relative.y;
}
return {x: position.x, y: position.y};
},
getCoordinates: function(element){
var position = this.getPosition(element), size = this.getSize();
return {left: position.x, right: position.x + size.x, top: position.y, bottom: position.y + size.y, width: size.x, height: size.y};
},
// why this?
computePosition: function(obj){
//return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
},
position: function(obj){
//return this.setStyles(this.computePosition(obj));
}
});
Document.implement({
getSize: function(){
var el = getCompatElement(this), winSize = this.getWindow().getSize();
return {x: Math.max(el.scrollWidth, winSize.x), y: Math.max(el.scrollHeight, winSize.y)};
}
});
Window.implement({
getSize: function(){
var el = getCompatElement(this);
return {x: el.clientWidth, y: el.clientHeight};
}
});
Native.implement([Document, Window], {
getScrollSize: function(){
return this.getDocument().getSize();
},
getScroll: $defined(window.pageYOffset) ? function(){
var win = this.getWindow();
return {x: win.pageXOffset, y: win.pageYOffset};
} : function(){
return $(getCompatElement(this)).getScroll();
}
});
})();
//aliases
Native.implement([Window, Document, Element], {
getHeight: function(){
return this.getSize().y;
},
getWidth: function(){
return this.getSize().x;
},
getScrollTop: function(){
return this.getScroll().y;
},
getScrollLeft: function(){
return this.getScroll().x;
},
getScrollHeight: function(){
return this.getScrollSize().y;
},
getScrollWidth: function(){
return this.getScrollSize().x;
},
getTop: function(){
return this.getPosition().y;
},
getLeft: function(){
return this.getPosition().x;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment