import { safeRun } from "./util"; function encodePageUrl(name: string): string { return name.replaceAll(" ", "_"); } function decodePageUrl(url: string): string { return url.replaceAll("_", " "); } export class PathPageNavigator { navigationResolve?: () => void; async navigate(page: string, pos?: number) { window.history.pushState( { page, pos }, page, `/${encodePageUrl(page)}${pos ? "@" + pos : ""}` ); window.dispatchEvent(new PopStateEvent("popstate")); await new Promise((resolve) => { this.navigationResolve = resolve; }); this.navigationResolve = undefined; } subscribe( pageLoadCallback: (pageName: string, pos: number) => Promise ): void { const cb = () => { const gotoPage = this.getCurrentPage(); if (!gotoPage) { return; } safeRun(async () => { await pageLoadCallback(this.getCurrentPage(), this.getCurrentPos()); if (this.navigationResolve) { this.navigationResolve(); } }); }; window.addEventListener("popstate", cb); cb(); } getCurrentPage(): string { let [page] = location.pathname.substring(1).split("@"); return decodePageUrl(page); } getCurrentPos(): number { let [, pos] = location.pathname.substring(1).split("@"); return +pos || 0; } }