scrivito
Version:
Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.
143 lines (119 loc) • 3.49 kB
text/typescript
// @rewire
import {
Action,
History as HistoryV4,
UnregisterCallback,
createBrowserHistory,
} from 'history';
import type { History as HistoryV5 } from 'history-5';
import * as URI from 'urijs';
import { ArgumentError, docUrl, onReset } from 'scrivito_sdk/common';
import { createStateContainer } from 'scrivito_sdk/state';
export interface HistoryState {
historyChangesCount: number;
location: string;
isRevisit: boolean;
}
let history: HistoryV4 | HistoryV5 | undefined;
let unlistenToHistory: UnregisterCallback | undefined;
let lastAction: undefined | Action;
/** @public */
export function useHistory(historyToUse: HistoryV4): void;
/** @internal */
export function useHistory(historyToUse: HistoryV4 | HistoryV5): void;
/** @internal */
export function useHistory(historyToUse: HistoryV4 | HistoryV5): void {
if (historyToUse.createHref({ pathname: '/' }) !== '/') {
throw new ArgumentError(
'Expected a history without a preconfigured basename.' +
` For further details, see: ${docUrl('js-sdk/useHistory')}`
);
}
if (historyToUse === history) {
return;
}
const isFirstHistory = !history;
listenToHistory(historyToUse);
history = historyToUse;
if (!isFirstHistory) {
historyHasChanged();
}
}
export function getHistoryState(): HistoryState {
return {
historyChangesCount: getHistoryChangesCount(),
location: get(),
isRevisit: lastAction === 'POP',
};
}
export function get(): string {
const location = getHistory().location;
return `${location.pathname}${location.search}${location.hash}`;
}
export function getHistoryChangesCount(): number {
return historyChangesCountState.get() || 0;
}
export function push(resource: string): void {
const uri = new URI(resource);
getHistory().push({
pathname: uri.pathname(),
search: uri.search(),
hash: uri.hash(),
});
}
export function replace(resource: string): void {
const uri = new URI(resource);
getHistory().replace({
pathname: uri.pathname(),
search: uri.search(),
hash: uri.hash(),
});
}
export function isCurrentHistoryState(historyState: HistoryState): boolean {
return historyState.historyChangesCount === getHistoryChangesCount();
}
// For test purpose only.
export function reset(): void {
history = undefined;
lastAction = undefined;
unlistenToHistory = undefined;
historyChangesCountState.clear();
}
// export for test purpose only
export function createInitialHistory(): HistoryV4 | HistoryV5 {
return createBrowserHistory();
}
function ensureHistory(): void {
if (!history) {
useHistory(createInitialHistory());
}
}
function getHistory(): HistoryV4 | HistoryV5 {
ensureHistory();
return history!;
}
function listenToHistory(historyToListen: HistoryV4 | HistoryV5): void {
if (unlistenToHistory) {
unlistenToHistory();
}
if (isHistoryV4(historyToListen)) {
unlistenToHistory = historyToListen.listen((_location, action) => {
historyHasChanged(action);
});
} else {
unlistenToHistory = historyToListen.listen(({ action }) => {
historyHasChanged(action);
});
}
}
function historyHasChanged(action?: Action) {
lastAction = action;
historyChangesCountState.set(getHistoryChangesCount() + 1);
}
const historyChangesCountState = createStateContainer<number>();
function isHistoryV4(
historyToCheck: HistoryV4 | HistoryV5
): historyToCheck is HistoryV4 {
return historyToCheck.hasOwnProperty('length');
}
onReset(reset);