@ima/core
Version:
IMA.js framework for isomorphic javascript application
118 lines (117 loc) • 3.79 kB
JavaScript
import { PageHandler } from './PageHandler';
import { ActionTypes } from '../../router/ActionTypes';
import { Window } from '../../window/Window';
export class PageNavigationHandler extends PageHandler {
_window;
#preManaged = false;
static $dependencies = [
Window
];
/**
* @param window The utility for manipulating the global context
* and global client-side-specific APIs.
*/ constructor(window){
super();
/**
* The utility for manipulating the global context and global
* client-side-specific APIs.
*/ this._window = window;
}
/**
* @inheritDoc
*/ init() {
// Setup history object to leave the scrolling to us and to not interfere
const browserWindow = this._window.getWindow();
if (browserWindow && 'scrollRestoration' in browserWindow.history) {
browserWindow.history.scrollRestoration = 'manual';
}
}
/**
* @inheritDoc
*/ handlePreManagedState(managedPage, nextManagedPage, action) {
const { options } = nextManagedPage;
/**
* Ignore first preManaged call, because this behavior
* is already set correctly by the browser.
*/ if (!this.#preManaged) {
this.#preManaged = true;
return;
}
if (managedPage && action && action.type !== ActionTypes.POP_STATE && action.type !== ActionTypes.ERROR) {
const isRedirection = action.type === ActionTypes.REDIRECT;
if (!isRedirection) {
this._saveScrollHistory();
}
this._setAddressBar(action.url, isRedirection);
}
// FIXME autoscroll will probably always be defined
if (options?.autoScroll) {
this._scrollTo({
x: 0,
y: 0
});
}
}
/**
* @inheritDoc
*/ handlePostManagedState(managedPage, previousManagedPage, action) {
const { event } = action;
const { options } = managedPage;
// FIXME autoscroll will probably always be defined
if (event?.state?.scroll && options?.autoScroll) {
this._scrollTo(event?.state.scroll);
}
}
/**
* Save user's scroll state to history.
*
* Replace scroll values in current state for actual scroll values in
* document.
*/ _saveScrollHistory() {
const url = this._window.getUrl();
const scroll = {
x: this._window.getScrollX(),
y: this._window.getScrollY()
};
const state = {
url,
scroll
};
const oldState = this._window.getHistoryState();
const newState = Object.assign({}, oldState, state);
this._window.replaceState(newState, '', url);
}
/**
* Scrolls to give coordinates on a page.
*/ _scrollTo({ x = 0, y = 0 }) {
setTimeout(()=>{
this._window.scrollTo(x, y);
}, 0);
}
/**
* Sets the provided URL to the browser's address bar by pushing or replacing a new
* state to the history.
*
* The state object pushed to or replaced in the history will be an object with the
* following structure: `{url: string}`. The `url` field will
* be set to the provided URL.
*
* @param url The URL.
* @param isRedirection If replaceState should be used instead of pushState.
*/ _setAddressBar(url, isRedirection) {
const scroll = {
x: 0,
y: 0
};
const state = {
url,
scroll
};
if (isRedirection) {
this._window.replaceState(state, '', url);
} else {
this._window.pushState(state, '', url);
}
}
}
//# sourceMappingURL=PageNavigationHandler.js.map