ui
Version:
platform agnostic ui models
92 lines (76 loc) • 3.91 kB
JavaScript
var getWindowScroll = require('./getWindowScroll')
// dom offset code adopted from jQuery JavaScript Library v1.3.2
/*!
* jQuery JavaScript Library v1.3.2
* http://jquery.com/
*
* Copyright (c) 2009 John Resig
* Dual licensed under the MIT and GPL licenses.
* http://docs.jquery.com/License
*/
module.exports = function getOffset(elem, win) {
win = win || window;
if (elem.getBoundingClientRect) {
var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
scroll = getWindowScroll(win),
top = box.top + scroll.top - clientTop,
left = box.left + scroll.left - clientLeft;
return { top:top, left:left, width:box.right - box.left, height:box.bottom - box.top };
} else {
var offset = arguments.callee.offset;
if (!offset) {
var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
for (prop in rules) container.style[prop] = rules[prop];
container.innerHTML = html;
body.insertBefore(container, body.firstChild);
innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td = innerDiv.nextSibling.firstChild.firstChild;
var offset = {};
offset.doesNotAddBorder = (checkDiv.offsetTop !== 5);
offset.doesAddBorderForTableAndCells = (td.offsetTop === 5);
innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
offset.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
body.style.marginTop = '1px';
offset.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
body.style.marginTop = bodyMarginTop;
body.removeChild(container);
arguments.callee.offset = offset;
}
var height = elem.offsetHeight;
var width = elem.offsetWidth;
var offsetParent = elem.offsetParent, prevOffsetParent = elem,
doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
body = doc.body, defaultView = doc.defaultView,
prevComputedStyle = defaultView.getComputedStyle(elem, null),
top = elem.offsetTop, left = elem.offsetLeft;
while ((elem = elem.parentNode) && elem !== body && elem !== docElem) {
computedStyle = defaultView.getComputedStyle(elem, null);
top -= elem.scrollTop, left -= elem.scrollLeft;
if (elem === offsetParent) {
top += elem.offsetTop, left += elem.offsetLeft;
if (offset.doesNotAddBorder && !(offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.tagName))) {
top += parseInt(computedStyle.borderTopWidth, 10) || 0;
left += parseInt(computedStyle.borderLeftWidth, 10) || 0;
}
prevOffsetParent = offsetParent;
offsetParent = elem.offsetParent;
}
if (offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible") {
top += parseInt(computedStyle.borderTopWidth, 10) || 0;
left += parseInt(computedStyle.borderLeftWidth, 10) || 0;
}
prevComputedStyle = computedStyle;
}
if (prevComputedStyle.position === "relative" || prevComputedStyle.position === "static") {
top += body.offsetTop;
left += body.offsetLeft;
}
if (prevComputedStyle.position === "fixed") {
top += Math.max(docElem.scrollTop, body.scrollTop);
left += Math.max(docElem.scrollLeft, body.scrollLeft);
}
return { top:top, left:left, width:width, height:height };
}
}