-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathindex.es6.js
103 lines (83 loc) · 3.38 KB
/
index.es6.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
if (window.history.pushState) {
const SCROLL_RESTORATION_TIMEOUT_MS = 3000;
const TRY_TO_SCROLL_INTERVAL_MS = 50;
const originalPushState = window.history.pushState;
const originalReplaceState = window.history.replaceState;
// Store current scroll position in current state when navigating away.
window.history.pushState = function() {
const newStateOfCurrentPage = Object.assign({}, window.history.state, {
__scrollX: window.scrollX,
__scrollY: window.scrollY,
});
originalReplaceState.call(window.history, newStateOfCurrentPage, '');
originalPushState.apply(window.history, arguments);
};
// Make sure we don't throw away scroll position when calling "replaceState".
window.history.replaceState = function(state, ...otherArgs) {
const newState = Object.assign({}, {
__scrollX: window.history.state && window.history.state.__scrollX,
__scrollY: window.history.state && window.history.state.__scrollY,
}, state);
originalReplaceState.apply(window.history, [newState].concat(otherArgs));
};
let timeoutHandle = null;
let scrollBarWidth = null;
// Try to scroll to the scrollTarget, but only if we can actually scroll
// there. Otherwise keep trying until we time out, then scroll as far as
// we can.
const tryToScrollTo = (scrollTarget) => {
// Stop any previous calls to "tryToScrollTo".
clearTimeout(timeoutHandle);
const body = document.body;
const html = document.documentElement;
if (!scrollBarWidth) {
scrollBarWidth = getScrollbarWidth();
}
// From http://stackoverflow.com/a/1147768
const documentWidth = Math.max(body.scrollWidth, body.offsetWidth,
html.clientWidth, html.scrollWidth, html.offsetWidth);
const documentHeight = Math.max(body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight);
if (documentWidth + scrollBarWidth - window.innerWidth >= scrollTarget.x &&
documentHeight + scrollBarWidth - window.innerHeight >= scrollTarget.y ||
Date.now() > scrollTarget.latestTimeToTry) {
window.scrollTo(scrollTarget.x, scrollTarget.y);
} else {
timeoutHandle = setTimeout(() => tryToScrollTo(scrollTarget),
TRY_TO_SCROLL_INTERVAL_MS);
}
};
// Try scrolling to the previous scroll position on popstate
const onPopState = () => {
const state = window.history.state;
if (state &&
Number.isFinite(state.__scrollX) &&
Number.isFinite(state.__scrollY)) {
setTimeout(() => tryToScrollTo({
x: state.__scrollX,
y: state.__scrollY,
latestTimeToTry: Date.now() + SCROLL_RESTORATION_TIMEOUT_MS,
}));
}
};
// Calculating width of browser's scrollbar
function getScrollbarWidth() {
let outer = document.createElement("div");
outer.style.visibility = "hidden";
outer.style.width = "100px";
outer.style.msOverflowStyle = "scrollbar";
document.body.appendChild(outer);
let widthNoScroll = outer.offsetWidth;
// force scrollbars
outer.style.overflow = "scroll";
// add innerdiv
let inner = document.createElement("div");
inner.style.width = "100%";
outer.appendChild(inner);
let widthWithScroll = inner.offsetWidth;
// remove divs
outer.parentNode.removeChild(outer);
return widthNoScroll - widthWithScroll;
}
window.addEventListener('popstate', onPopState, true);
}