UNPKG

3.38 kBJavaScriptView Raw
1"use strict";
2
3// defined by w3c
4var DOCUMENT_NODE = 9;
5/**
6 * Returns `true` if `w` is a Document object, or `false` otherwise.
7 *
8 * @param {?} d - Document object, maybe
9 * @return {Boolean}
10 * @private
11 */
12
13function isDocument(d) {
14 return d && d.nodeType === DOCUMENT_NODE;
15}
16/**
17 * Returns the `document` object associated with the given `node`, which may be
18 * a DOM element, the Window object, a Selection, a Range. Basically any DOM
19 * object that references the Document in some way, this function will find it.
20 *
21 * @param {Mixed} node - DOM node, selection, or range in which to find the `document` object
22 * @return {Document} the `document` object associated with `node`
23 * @public
24 */
25
26
27function getDocument(node) {
28 if (isDocument(node)) {
29 return node;
30 } else if (isDocument(node.ownerDocument)) {
31 return node.ownerDocument;
32 } else if (isDocument(node.document)) {
33 return node.document;
34 } else if (node.parentNode) {
35 return getDocument(node.parentNode); // Range support
36 } else if (node.commonAncestorContainer) {
37 return getDocument(node.commonAncestorContainer);
38 } else if (node.startContainer) {
39 return getDocument(node.startContainer); // Selection support
40 } else if (node.anchorNode) {
41 return getDocument(node.anchorNode);
42 }
43}
44
45function withinElement(child, parent) {
46 // don't throw if `child` is null
47 if (!child) return false; // Range support
48
49 if (child.commonAncestorContainer) child = child.commonAncestorContainer;else if (child.endContainer) child = child.endContainer; // ask the browser if parent contains child
50
51 if (child === window) return true;
52 return parent.contains(child);
53}
54
55module.exports = function offset(el) {
56 var doc = getDocument(el);
57 if (!doc) return; // Make sure it's not a disconnected DOM node
58
59 if (!withinElement(el, doc)) return;
60 var body = doc.body;
61
62 if (body === el) {
63 return bodyOffset(el);
64 }
65
66 var box = {
67 top: 0,
68 left: 0
69 };
70
71 if (typeof el.getBoundingClientRect !== "undefined") {
72 // If we don't have gBCR, just use 0,0 rather than error
73 // BlackBerry 5, iOS 3 (original iPhone)
74 box = el.getBoundingClientRect();
75
76 if (el.collapsed && box.left === 0 && box.top === 0) {
77 // collapsed Range instances sometimes report 0, 0
78 // see: http://stackoverflow.com/a/6847328/376773
79 var span = doc.createElement("span"); // Ensure span has dimensions and position by
80 // adding a zero-width space character
81
82 span.appendChild(doc.createTextNode("\u200B"));
83 el.insertNode(span);
84 box = span.getBoundingClientRect(); // Remove temp SPAN and glue any broken text nodes back together
85
86 var spanParent = span.parentNode;
87 spanParent.removeChild(span);
88 spanParent.normalize();
89 }
90 }
91
92 var docEl = doc.documentElement;
93 var clientTop = docEl.clientTop || body.clientTop || 0;
94 var clientLeft = docEl.clientLeft || body.clientLeft || 0;
95 var scrollTop = window.pageYOffset || docEl.scrollTop;
96 var scrollLeft = window.pageXOffset || docEl.scrollLeft;
97 return {
98 top: box.top + scrollTop - clientTop,
99 left: box.left + scrollLeft - clientLeft
100 };
101};
102
103function bodyOffset(body) {
104 var top = body.offsetTop;
105 var left = body.offsetLeft;
106 top += parseFloat(body.style.marginTop || 0);
107 left += parseFloat(body.style.marginLeft || 0);
108 return {
109 top: top,
110 left: left
111 };
112}
\No newline at end of file