UNPKG

@ima/core

Version:

IMA.js framework for isomorphic javascript application

118 lines (117 loc) 3.79 kB
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