1 | (function (global, factory) {
|
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
3 | typeof define === 'function' && define.amd ? define(factory) :
|
4 | (global = global || self, global.computeScrollIntoView = factory());
|
5 | }(this, (function () { 'use strict';
|
6 |
|
7 | function isElement(el) {
|
8 | return el != null && typeof el === 'object' && el.nodeType === 1;
|
9 | }
|
10 |
|
11 | function canOverflow(overflow, skipOverflowHiddenElements) {
|
12 | if (skipOverflowHiddenElements && overflow === 'hidden') {
|
13 | return false;
|
14 | }
|
15 |
|
16 | return overflow !== 'visible' && overflow !== 'clip';
|
17 | }
|
18 |
|
19 | function getFrameElement(el) {
|
20 | if (!el.ownerDocument || !el.ownerDocument.defaultView) {
|
21 | return null;
|
22 | }
|
23 |
|
24 | return el.ownerDocument.defaultView.frameElement;
|
25 | }
|
26 |
|
27 | function isHiddenByFrame(el) {
|
28 | var frame = getFrameElement(el);
|
29 |
|
30 | if (!frame) {
|
31 | return false;
|
32 | }
|
33 |
|
34 | return frame.clientHeight < el.scrollHeight || frame.clientWidth < el.scrollWidth;
|
35 | }
|
36 |
|
37 | function isScrollable(el, skipOverflowHiddenElements) {
|
38 | if (el.clientHeight < el.scrollHeight || el.clientWidth < el.scrollWidth) {
|
39 | var style = getComputedStyle(el, null);
|
40 | return canOverflow(style.overflowY, skipOverflowHiddenElements) || canOverflow(style.overflowX, skipOverflowHiddenElements) || isHiddenByFrame(el);
|
41 | }
|
42 |
|
43 | return false;
|
44 | }
|
45 |
|
46 | function alignNearest(scrollingEdgeStart, scrollingEdgeEnd, scrollingSize, scrollingBorderStart, scrollingBorderEnd, elementEdgeStart, elementEdgeEnd, elementSize) {
|
47 | if (elementEdgeStart < scrollingEdgeStart && elementEdgeEnd > scrollingEdgeEnd || elementEdgeStart > scrollingEdgeStart && elementEdgeEnd < scrollingEdgeEnd) {
|
48 | return 0;
|
49 | }
|
50 |
|
51 | if (elementEdgeStart <= scrollingEdgeStart && elementSize <= scrollingSize || elementEdgeEnd >= scrollingEdgeEnd && elementSize >= scrollingSize) {
|
52 | return elementEdgeStart - scrollingEdgeStart - scrollingBorderStart;
|
53 | }
|
54 |
|
55 | if (elementEdgeEnd > scrollingEdgeEnd && elementSize < scrollingSize || elementEdgeStart < scrollingEdgeStart && elementSize > scrollingSize) {
|
56 | return elementEdgeEnd - scrollingEdgeEnd + scrollingBorderEnd;
|
57 | }
|
58 |
|
59 | return 0;
|
60 | }
|
61 |
|
62 | var index = (function (target, options) {
|
63 | var scrollMode = options.scrollMode,
|
64 | block = options.block,
|
65 | inline = options.inline,
|
66 | boundary = options.boundary,
|
67 | skipOverflowHiddenElements = options.skipOverflowHiddenElements;
|
68 | var checkBoundary = typeof boundary === 'function' ? boundary : function (node) {
|
69 | return node !== boundary;
|
70 | };
|
71 |
|
72 | if (!isElement(target)) {
|
73 | throw new TypeError('Invalid target');
|
74 | }
|
75 |
|
76 | var scrollingElement = document.scrollingElement || document.documentElement;
|
77 | var frames = [];
|
78 | var cursor = target;
|
79 |
|
80 | while (isElement(cursor) && checkBoundary(cursor)) {
|
81 | cursor = cursor.parentNode;
|
82 |
|
83 | if (cursor === scrollingElement) {
|
84 | frames.push(cursor);
|
85 | break;
|
86 | }
|
87 |
|
88 | if (cursor === document.body && isScrollable(cursor) && !isScrollable(document.documentElement)) {
|
89 | continue;
|
90 | }
|
91 |
|
92 | if (isScrollable(cursor, skipOverflowHiddenElements)) {
|
93 | frames.push(cursor);
|
94 | }
|
95 | }
|
96 |
|
97 | var viewportWidth = window.visualViewport ? visualViewport.width : innerWidth;
|
98 | var viewportHeight = window.visualViewport ? visualViewport.height : innerHeight;
|
99 | var viewportX = window.scrollX || pageXOffset;
|
100 | var viewportY = window.scrollY || pageYOffset;
|
101 |
|
102 | var _target$getBoundingCl = target.getBoundingClientRect(),
|
103 | targetHeight = _target$getBoundingCl.height,
|
104 | targetWidth = _target$getBoundingCl.width,
|
105 | targetTop = _target$getBoundingCl.top,
|
106 | targetRight = _target$getBoundingCl.right,
|
107 | targetBottom = _target$getBoundingCl.bottom,
|
108 | targetLeft = _target$getBoundingCl.left;
|
109 |
|
110 | var targetBlock = block === 'start' || block === 'nearest' ? targetTop : block === 'end' ? targetBottom : targetTop + targetHeight / 2;
|
111 | var targetInline = inline === 'center' ? targetLeft + targetWidth / 2 : inline === 'end' ? targetRight : targetLeft;
|
112 | var computations = [];
|
113 |
|
114 | for (var index = 0; index < frames.length; index++) {
|
115 | var frame = frames[index];
|
116 |
|
117 | var _frame$getBoundingCli = frame.getBoundingClientRect(),
|
118 | height = _frame$getBoundingCli.height,
|
119 | width = _frame$getBoundingCli.width,
|
120 | top = _frame$getBoundingCli.top,
|
121 | right = _frame$getBoundingCli.right,
|
122 | bottom = _frame$getBoundingCli.bottom,
|
123 | left = _frame$getBoundingCli.left;
|
124 |
|
125 | if (scrollMode === 'if-needed' && targetTop >= 0 && targetLeft >= 0 && targetBottom <= viewportHeight && targetRight <= viewportWidth && targetTop >= top && targetBottom <= bottom && targetLeft >= left && targetRight <= right) {
|
126 | return computations;
|
127 | }
|
128 |
|
129 | var frameStyle = getComputedStyle(frame);
|
130 | var borderLeft = parseInt(frameStyle.borderLeftWidth, 10);
|
131 | var borderTop = parseInt(frameStyle.borderTopWidth, 10);
|
132 | var borderRight = parseInt(frameStyle.borderRightWidth, 10);
|
133 | var borderBottom = parseInt(frameStyle.borderBottomWidth, 10);
|
134 | var blockScroll = 0;
|
135 | var inlineScroll = 0;
|
136 | var scrollbarWidth = 'offsetWidth' in frame ? frame.offsetWidth - frame.clientWidth - borderLeft - borderRight : 0;
|
137 | var scrollbarHeight = 'offsetHeight' in frame ? frame.offsetHeight - frame.clientHeight - borderTop - borderBottom : 0;
|
138 |
|
139 | if (scrollingElement === frame) {
|
140 | if (block === 'start') {
|
141 | blockScroll = targetBlock;
|
142 | } else if (block === 'end') {
|
143 | blockScroll = targetBlock - viewportHeight;
|
144 | } else if (block === 'nearest') {
|
145 | blockScroll = alignNearest(viewportY, viewportY + viewportHeight, viewportHeight, borderTop, borderBottom, viewportY + targetBlock, viewportY + targetBlock + targetHeight, targetHeight);
|
146 | } else {
|
147 | blockScroll = targetBlock - viewportHeight / 2;
|
148 | }
|
149 |
|
150 | if (inline === 'start') {
|
151 | inlineScroll = targetInline;
|
152 | } else if (inline === 'center') {
|
153 | inlineScroll = targetInline - viewportWidth / 2;
|
154 | } else if (inline === 'end') {
|
155 | inlineScroll = targetInline - viewportWidth;
|
156 | } else {
|
157 | inlineScroll = alignNearest(viewportX, viewportX + viewportWidth, viewportWidth, borderLeft, borderRight, viewportX + targetInline, viewportX + targetInline + targetWidth, targetWidth);
|
158 | }
|
159 |
|
160 | blockScroll = Math.max(0, blockScroll + viewportY);
|
161 | inlineScroll = Math.max(0, inlineScroll + viewportX);
|
162 | } else {
|
163 | if (block === 'start') {
|
164 | blockScroll = targetBlock - top - borderTop;
|
165 | } else if (block === 'end') {
|
166 | blockScroll = targetBlock - bottom + borderBottom + scrollbarHeight;
|
167 | } else if (block === 'nearest') {
|
168 | blockScroll = alignNearest(top, bottom, height, borderTop, borderBottom + scrollbarHeight, targetBlock, targetBlock + targetHeight, targetHeight);
|
169 | } else {
|
170 | blockScroll = targetBlock - (top + height / 2) + scrollbarHeight / 2;
|
171 | }
|
172 |
|
173 | if (inline === 'start') {
|
174 | inlineScroll = targetInline - left - borderLeft;
|
175 | } else if (inline === 'center') {
|
176 | inlineScroll = targetInline - (left + width / 2) + scrollbarWidth / 2;
|
177 | } else if (inline === 'end') {
|
178 | inlineScroll = targetInline - right + borderRight + scrollbarWidth;
|
179 | } else {
|
180 | inlineScroll = alignNearest(left, right, width, borderLeft, borderRight + scrollbarWidth, targetInline, targetInline + targetWidth, targetWidth);
|
181 | }
|
182 |
|
183 | var scrollLeft = frame.scrollLeft,
|
184 | scrollTop = frame.scrollTop;
|
185 | blockScroll = Math.max(0, Math.min(scrollTop + blockScroll, frame.scrollHeight - height + scrollbarHeight));
|
186 | inlineScroll = Math.max(0, Math.min(scrollLeft + inlineScroll, frame.scrollWidth - width + scrollbarWidth));
|
187 | targetBlock += scrollTop - blockScroll;
|
188 | targetInline += scrollLeft - inlineScroll;
|
189 | }
|
190 |
|
191 | computations.push({
|
192 | el: frame,
|
193 | top: blockScroll,
|
194 | left: inlineScroll
|
195 | });
|
196 | }
|
197 |
|
198 | return computations;
|
199 | });
|
200 |
|
201 | return index;
|
202 |
|
203 | })));
|