hy-push-state
Version:
Turn static web sites into dynamic web apps
63 lines (62 loc) • 2.13 kB
JavaScript
import { getScrollTop, Cause } from "./common";
export class ScrollManager {
constructor(parent) {
this.parent = parent;
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
}
manageScrollPosition({ cause, url: { hash } }) {
switch (cause) {
case Cause.Push: {
// FIXME: make configurable
this.scrollHashIntoView(hash, { behavior: "smooth", block: "start", inline: "nearest" });
break;
}
case Cause.Pop: {
this.restoreScrollPosition();
break;
}
case Cause.Init: {
this.restoreScrollPositionOnReload();
break;
}
}
}
elementFromHash(hash) {
return document.getElementById(decodeURIComponent(hash.substr(1)));
}
scrollHashIntoView(hash, options) {
requestAnimationFrame(() => {
if (hash) {
const el = this.elementFromHash(hash);
// TODO: assert `scrollIntoView` !?
if (el)
el.scrollIntoView(options);
}
else {
window.scroll(window.pageXOffset, 0);
}
});
}
restoreScrollPosition() {
const { histId } = this.parent;
const { scrollTop } = (history.state && history.state[histId]) || {};
if (scrollTop != null) {
window.scroll(window.pageXOffset, scrollTop);
}
}
restoreScrollPositionOnReload() {
const { histId } = this.parent;
const scrollState = history.state && history.state[histId];
// FIXME: As far as I can tell there is no better way of figuring out if the user has scrolled
// and it doesn't work on hash links b/c the scroll position is going to be non-null by definition
if (scrollState && getScrollTop() === 0) {
this.restoreScrollPosition();
}
else if (location.hash) {
this.scrollHashIntoView(location.hash, true);
}
}
}
;