SecureNotes/src/navigation.ts

112 lines
3.7 KiB
TypeScript
Executable File

import Observable from "./helper/observable";
import { Page, PageProps } from "./page";
import { h } from "preact";
function serializQuery(obj: any) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}
function parseQuery(query: string) {
let data: any = {};
if (query.startsWith("?")) query = query.slice(1)
query.split("&").forEach(e => {
let [key, value] = e.split("=");
key = decodeURIComponent(key)
value = decodeURIComponent(value)
data[key] = value
})
return data
}
export default class Navigation {
private static _pages: Map<string, typeof Page> = new Map();
private static _page: { route: string, page: JSX.Element };
private static pageObservableServer = new Observable<JSX.Element>(false);
public static pageObservable = Navigation.pageObservableServer.getPublicApi();
private static _state: { [key: string]: any };
private static _hidden_state: { [key: string]: any };
public static addPage(route: string, comp: typeof Page) {
Navigation._pages.set(route, comp);
}
// public static get state() {
// return Navigation._state;
// }
public static set default(comp: typeof Page) {
console.log("Set default");
Navigation._pages.set("/", comp);
}
public static set not_found(comp: typeof Page) {
Navigation._pages.set("/404", comp);
}
public static setPage(route: string, state?: { [key: string]: string }, hidden?: { [key: string]: string }, replace?: boolean) {
let component = Navigation._pages.get(route);
if (!component && route !== "/404") {
Navigation.setPage("/404", { route, key: "404" })
} else {
if (!Navigation.page || Navigation.page.route !== route || JSON.stringify(state) !== JSON.stringify(Navigation._state) || JSON.stringify(Navigation._hidden_state) !== JSON.stringify(hidden)) {
let s = "";
if (state) {
s = "?" + serializQuery(state)
}
let newhash = "#" + route + s;
let newkey = newhash + serializQuery(hidden)
let whash = window.location.hash;
if (!whash || whash === "") whash = "#/"
let oldkey = whash + serializQuery(history.state);
if (newkey !== oldkey) {
if (replace)
window.history.replaceState(hidden, document.title, newhash);
else
window.history.pushState(hidden, document.title, newhash);
}
let page = h(component as any, { state: state, key: newhash + serializQuery(hidden), hidden: hidden });
Navigation._state = state;
Navigation._hidden_state = hidden;
Navigation._page = { page, route };
Navigation.pageObservableServer.send(page);
}
}
}
static get page() {
return Navigation._page;
}
static onHashChange(hidden_state: { [key: string]: string }) {
let hash = window.location.hash.substring(1);
if (hash && hash !== "") {
let [route, state] = hash.split("?");
let s;
if (state) {
try {
s = parseQuery(state)
} catch (err) {
s = undefined;
console.error(err);
}
}
Navigation.setPage(route, s, hidden_state)
} else {
Navigation.setPage("/");
}
}
static start() {
window.addEventListener("popstate", (ev) => {
Navigation.onHashChange(ev.state);
})
Navigation.onHashChange(undefined);
}
}