import { safeRun } from "../common/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)}`); window.dispatchEvent( new PopStateEvent("popstate", { state: { page, pos }, }) ); await new Promise((resolve) => { this.navigationResolve = resolve; }); this.navigationResolve = undefined; } subscribe( pageLoadCallback: (pageName: string, pos: number) => Promise ): void { const cb = (event?: PopStateEvent) => { const gotoPage = this.getCurrentPage(); if (!gotoPage) { return; } safeRun(async () => { await pageLoadCallback( this.getCurrentPage(), event?.state && event.state.pos ); if (this.navigationResolve) { this.navigationResolve(); } }); }; window.addEventListener("popstate", cb); cb(); } decodeURI(): [string, number] { let parts = decodeURI(location.pathname).substring(1).split("@"); let page = parts.length > 1 ? parts.slice(0, parts.length - 1).join("@") : parts[0]; let pos = parts.length > 1 ? parts[parts.length - 1] : "0"; if (pos.match(/^\d+$/)) { return [page, +pos]; } else { return [`${page}@${pos}`, 0]; } } getCurrentPage(): string { return decodePageUrl(this.decodeURI()[0]); } getCurrentPos(): number { console.log("Pos", this.decodeURI()[1]); return this.decodeURI()[1]; } }