-
-
Save mc0/03a0ac3456e2399ea3dd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* WIP */ | |
var Position = { | |
tests: {}, | |
basicOffsetTests = function() { | |
var result = Position.tests; | |
result.CLIENT_TOP_SUPPORTED = 'clientTop' in Fuse._docEl; | |
result.TABLE_TAG = return /^h/.test(Fuse._docEl.tagName) ? "table" : "TABLE"; | |
Position.basicOffsetTests = emptyFunction; | |
}, | |
offsetTests = function offsetTests(req) { | |
var body = Fuse._body, | |
result = Position.tests; | |
result.ran = true; | |
if (!body) return; | |
var marginTop = "marginTop", position = "position", padding = "padding", | |
stat = "static", | |
border = "border", s = body.style, | |
bv = '1px solid transparent', | |
z = "0", | |
one = "1px", | |
offsetTop = "offsetTop", | |
ds = Fuse._docEl.style, | |
x = Fuse._doc.createElement('div'), | |
xs = x.style, | |
table = Fuse._doc.createElement(result.TABLE_TAG), | |
bodyBackup = {padding: s.padding, marginTop: s.marginTop, | |
'top': s.top, border: s.border, position: s.position}, | |
docBackup = {padding: ds.padding, marginTop: ds.marginTop, | |
position: ds.position}; | |
table.cellSpacing = table.cellPadding = xs.margin = | |
s[padding] = s[marginTop] = s.top = z; | |
s[border] = bv; | |
ds.position = stat; | |
// Table test (relies on td not defaulting to 7px) | |
table.innerHTML = "<tbody><tr><td>x</td></tr></tbody>"; | |
table.style[border] = "7px solid"; | |
body.insertBefore(table, body.firstChild); | |
result.IS_TABLE_BORDER_INCLUDED_IN_TD_OFFSET = | |
table.getElementsByTagName("td")[0].offsetLeft === 7; | |
body.removeChild(table); | |
// Relies on marginTop of 0 | |
s.top = one; | |
result.IS_BODY_TOP_INHERITED = x[offsetTop] === 1; | |
// Now add margin to determine if body offsetTop is inherited. | |
s.top = z; | |
s[marginTop] = one; | |
s[position] = relative; | |
result.IS_BODY_MARGIN_INHERITED = (x[offsetTop] === 1); | |
result.IS_BODY_OFFSET_EXCLUDING_MARGIN = body[offsetTop] === 0; | |
result.IS_BODY_OFFSET_IGNORED_WHEN_BODY_RELATIVE_AND_LAST_CHILD_POSITIONED = x[offsetTop] === 0; | |
//IS_BODY_OFFSET_TOP_NO_OFFSETPARENT = body.offsetTop && !body.offsetParent; | |
xs[position] = "absolute"; | |
s[position] = stat; | |
if(x.offsetParent === body) { | |
xs.top = "2px"; | |
// XXX Safari gets offsetParent wrong (says 'body' when body is static, | |
// but then positions element from ICB and then subtracts body's clientWidth. | |
// Safari is half wrong. | |
// | |
// XXX Mozilla says body is offsetParent but does NOT subtract EL's offsetLeft/Top. | |
// Mozilla is completely wrong. | |
result.IS_STATIC_BODY_OFFSET_PARENT_BUT_ABSOLUTE_CHILD_SUBTRACTS_BODY_BORDER_WIDTH = x[offsetTop] === 1; | |
s[border] = z; | |
xs[position] = relative; | |
ds[padding] = one; | |
s[marginTop] = z; | |
result.IS_CONTAINER_BODY_STATIC_INCLUDING_HTML_PADDING = x[offsetTop] === 3; | |
// Opera does not respect position: relative on BODY. | |
s[position] = relative; | |
result.IS_CONTAINER_BODY_RELATIVE_INCLUDING_HTML_PADDING_REL_CHILD = x[offsetTop] === 3; | |
xs[position] = "absolute"; | |
result.IS_CONTAINER_BODY_RELATIVE_INCLUDING_HTML_PADDING_ABS_CHILD = x[offsetTop] === 3; | |
// Opera inherits HTML margin when body is relative and child is relative or absolute. | |
ds[padding] = z; | |
ds[marginTop] = one; | |
result.IS_CONTAINER_BODY_INCLUDING_HTML_MARGIN = x[offsetTop] === 3; | |
} | |
// xs.position = "fixed"; | |
// FIXED_HAS_OFFSETPARENT = x.offsetParent != null; | |
body.removeChild(x); | |
Fuse.Element.Methods(body).setStyle(bodyBackup); | |
Fuse.Element.Methods(ds).setStyle(docBackup); | |
} | |
}; | |
Position.toFloat = function toFloat(val) { return parseFloat(val) || 0 }; | |
if (Feature('ELEMENT_BOUNDING_CLIENT_RECT')) { | |
Position.getOffsets = function getOffsets(el, container) { | |
if (!el || !el.ownerDocument) { return null } | |
Position.basicOffsetTests(); | |
var toFloat = Position.toFloat | |
doc = el.ownerDocument, | |
docEl = doc.documentElement, | |
body = doc.body, | |
tests = Position.tests, | |
box = el.getBoundingClientRect(), | |
rootEl = Bug('BODY_ACTING_AS_ROOT') ? body : docEl, | |
clientTop = rootEl.clientTop || 0, | |
clientLeft = rootEl.clientLeft || 0, | |
x = box.left + max(docEl.scrollLeft, body.scrollLeft), | |
y = box.top + max(docEl.scrollTop, body.scrollTop), | |
bodyCurStyle; | |
container = container || doc; | |
if (tests.CLIENT_TOP_SUPPORTED) { | |
x -= clientTop; | |
y -= clientLeft; | |
} | |
if (container !== doc) { | |
box = Position.getOffsets(container, null); | |
x -= box.x; | |
y -= box.y; | |
if (Bug('BODY_ACTING_AS_ROOT') && | |
container === body && | |
tests.CLIENT_TOP_SUPPORTED) { | |
x -= borderLeft; | |
y -= borderTop; | |
} | |
else if (Bug('BODY_ACTING_AS_ROOT') && | |
Feature('ELEMENT_CURRENT_STYLE') && | |
container !== body) { | |
bodyCurStyle = body.currentStyle; | |
x += toFloat(bodyCurStyle.marginLeft) + toFloat(bodyCurStyle.left); | |
y += toFloat(bodyCurStyle.marginTop) + toFloat(bodyCurStyle.top); | |
} | |
} | |
return {left: x, top: y}; | |
}; | |
} | |
else { | |
Position.getOffsets = function getOffsets(el, container, coords) { | |
if (!el || !el.ownerDocument) { return null } | |
Position.offsetTests(); | |
var toFloat = Position.toFloat | |
doc = el.ownerDocument, | |
docEl = doc.documentElement, | |
body = doc.body, | |
tests = Position.tests; | |
container = container || doc; | |
if (!coords) coords = {}; | |
else coords = {left: toFloat(coords.left), top: toFloat(coords.left)}; | |
if (el === container) | |
return (coords.x = coords.y = 0) && coords; | |
// Crawling up the tree. | |
if (Feature('ELEMENT_COMPUTED_STYLE')) { | |
var offsetLeft = el.offsetLeft, | |
offsetTop = el.offsetTop, | |
defaultView = doc.defaultView, | |
cs = defaultView.getComputedStyle(el, ''); | |
if (cs.position == "fixed") { | |
coords.x = offsetLeft + documentElement.scrollLeft; | |
coords.y = offsetTop + documentElement.scrollTop; | |
return coords; | |
} | |
var bcs = defaultView.getComputedStyle(body,''), | |
isBodyStatic = !positionedExp.test(bcs.position), | |
lastOffsetParent = el, | |
parent = el.parentNode, | |
offsetParent = el.offsetParent; | |
// Main loop ----------------------------------------------------------------------- | |
// Loop up, gathering scroll offsets on parentNodes. | |
// when we get to a parent that's an offsetParent, update | |
// the current offsetParent marker. | |
for( ; parent && parent !== container; parent = parent.parentNode) { | |
if (parent !== body && parent !== documentElement) { | |
offsetLeft -= parent.scrollLeft; | |
offsetTop -= parent.scrollTop; | |
} | |
if (parent === offsetParent) { | |
// If we get to BODY and have static position, skip it. | |
if (parent === body && isBodyStatic); | |
else { | |
// XXX Mozilla; Exclude static body; if static, it's offsetTop will be wrong. | |
// Include parent border widths. This matches behavior of clientRect approach. | |
// XXX Opera <= 9.2 includes parent border widths. | |
// See Bug('BODY_OFFSETS_INHERIT_ITS_MARGINS') below. | |
if ( !Bug('BODY_OFFSETS_INHERIT_ITS_MARGINS') && | |
! (parent.tagName === tests.TABLE_TAG && tests.IS_TABLE_BORDER_INCLUDED_IN_TD_OFFSET)) { | |
var pcs = defaultView.getComputedStyle(parent, ""); | |
// Mozilla doesn't support clientTop. Add borderWidth to the sum. | |
offsetLeft += parseFloat(pcs[borderLeftWidth]) || 0; | |
offsetTop += parseFloat(pcs[borderTopWidth]) || 0; | |
} | |
if (parent !== body) { | |
offsetLeft += offsetParent.offsetLeft; | |
offsetTop += offsetParent.offsetTop; | |
lastOffsetParent = offsetParent; | |
offsetParent = parent.offsetParent; // next marker to check for offsetParent. | |
} | |
} | |
} | |
} | |
//--------Post - loop, body adjustments---------------------------------------------- | |
// Complications due to CSSOM Views - the browsers try to implement a contradictory | |
// spec: http://www.w3.org/TR/cssom-view/#offset-attributes | |
// XXX Mozilla, Safari 3, Opera: body margin is never | |
// included in body offsetLeft/offsetTop. | |
// This is wrong. Body's offsetTop should work like any other element. | |
// In Safari 2.0.4, BODY can have offsetParent, and even | |
// if it doesn't, it can still have offsetTop. | |
// But Safari 2.0.4 doubles offsetTop for relatively positioned elements | |
// and this script does not account for that. | |
// XXX Mozilla: When body has a border, body's offsetTop === negative borderWidth; | |
// Don't use body.offsetTop. | |
var bodyOffsetLeft = 0, | |
bodyOffsetTop = 0, | |
isLastElementAbsolute, | |
isLastOffsetElementPositioned, | |
isContainerDocOrDocEl = container === doc || container === documentElement, | |
dcs, | |
lastOffsetPosition; | |
// If the lastOffsetParent is document, | |
// it is not positioned (and hence, not absolute). | |
if (lastOffsetParent != doc) { | |
lastOffsetPosition = defaultView.getComputedStyle(lastOffsetParent,'').position; | |
isLastElementAbsolute = absoluteExp.test(lastOffsetPosition); | |
isLastOffsetElementPositioned = isLastElementAbsolute || | |
positionedExp.test(lastOffsetPosition); | |
} | |
// do we need to add margin? | |
if ( | |
(lastOffsetParent === el && el.offsetParent === body && !tests.IS_BODY_MARGIN_INHERITED | |
&& container !== body && !(isBodyStatic && tests.IS_BODY_OFFSET_EXCLUDING_MARGIN)) | |
|| (tests.IS_BODY_MARGIN_INHERITED && lastOffsetParent === el && !isLastOffsetElementPositioned) | |
|| !isBodyStatic | |
&& isLastOffsetElementPositioned | |
&& tests.IS_BODY_OFFSET_IGNORED_WHEN_BODY_RELATIVE_AND_LAST_CHILD_POSITIONED | |
&& isContainerDocOrDocEl) { | |
bodyOffsetTop += parseFloat(bcs.marginTop) || 0; | |
bodyOffsetLeft += parseFloat(bcs.marginLeft) || 0; | |
} | |
// Case for padding on documentElement. | |
if (container === body) { | |
dcs = defaultView.getComputedStyle(documentElement,''); | |
if ( | |
(!isBodyStatic && | |
((tests.IS_CONTAINER_BODY_RELATIVE_INCLUDING_HTML_PADDING_REL_CHILD && !isLastElementAbsolute) | |
|| | |
(tests.IS_CONTAINER_BODY_RELATIVE_INCLUDING_HTML_PADDING_ABS_CHILD && isLastElementAbsolute)) | |
) | |
|| isBodyStatic && tests.IS_CONTAINER_BODY_STATIC_INCLUDING_HTML_PADDING | |
) { | |
bodyOffsetTop -= parseFloat(dcs.paddingTop) || 0; | |
bodyOffsetLeft -= parseFloat(dcs.paddingLeft) || 0; | |
} | |
if (tests.IS_CONTAINER_BODY_INCLUDING_HTML_MARGIN){ | |
if (!isLastOffsetElementPositioned | |
|| isLastOffsetElementPositioned && !isBodyStatic) | |
bodyOffsetTop -= parseFloat(dcs.marginTop) || 0; | |
bodyOffsetLeft -= parseFloat(dcs.marginLeft) || 0; | |
} | |
} | |
if (isBodyStatic) { | |
// XXX Safari subtracts border width of body from element's offsetTop (opera does it, too) | |
if (tests.IS_STATIC_BODY_OFFSET_PARENT_BUT_ABSOLUTE_CHILD_SUBTRACTS_BODY_BORDER_WIDTH | |
// XXX: Safari will use HTML for containing block (CSS), | |
// but will subtract the body's border from the body's absolutely positioned | |
// child.offsetTop. Safari reports the child's offsetParent is BODY, but | |
// doesn't treat it that way (Safari bug). | |
|| (!isLastElementAbsolute && !Bug('BODY_OFFSETS_INHERIT_ITS_MARGINS') | |
&& isContainerDocOrDocEl)) { | |
bodyOffsetTop += parseFloat(bcs[borderTopWidth]); | |
bodyOffsetLeft += parseFloat(bcs[borderLeftWidth]); | |
} | |
} | |
// body is positioned, and if it excludes margin, | |
// it's probably partly using the AVK-CSSOM disaster. | |
else if (tests.IS_BODY_OFFSET_EXCLUDING_MARGIN) { | |
if (isContainerDocOrDocEl) { | |
if (!tests.IS_BODY_TOP_INHERITED) { | |
// If the body is positioned, add its left and top value. | |
bodyOffsetTop += parseFloat(bcs.top) || 0; | |
bodyOffsetLeft += parseFloat(bcs.left) || 0; | |
// XXX: Opera normally include the parentBorder in offsetTop. | |
// We have a preventative measure in the loop above. | |
if (isLastElementAbsolute && Bug('BODY_OFFSETS_INHERIT_ITS_MARGINS')) { | |
bodyOffsetTop += parseFloat(bcs[borderTopWidth]); | |
bodyOffsetLeft += parseFloat(bcs[borderLeftWidth]); | |
} | |
} | |
// Padding on documentElement is not included, | |
// but in this case, we're searching to documentElement, so we | |
// have to add it back in. | |
if (container === doc && !isBodyStatic | |
&& !tests.IS_CONTAINER_BODY_RELATIVE_INCLUDING_HTML_PADDING_REL_CHILD) { | |
if (!dcs) dcs = defaultView.getComputedStyle(documentElement,''); | |
bodyOffsetTop += parseFloat(dcs.paddingTop) || 0; | |
bodyOffsetLeft += parseFloat(dcs.paddingLeft) || 0; | |
} | |
} | |
else if (tests.IS_BODY_TOP_INHERITED) { | |
bodyOffsetTop -= parseFloat(bcs.top); | |
bodyOffsetLeft -= parseFloat(bcs.left); | |
} | |
if (tests.IS_BODY_MARGIN_INHERITED && (!isLastOffsetElementPositioned || container === body)) { | |
bodyOffsetTop -= parseFloat(bcs.marginTop) || 0; | |
bodyOffsetLeft -= parseFloat(bcs.marginLeft) || 0; | |
} | |
} | |
coords.x = round(offsetLeft + bodyOffsetLeft); | |
coords.y = round(offsetTop + bodyOffsetTop); | |
return coords; | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment