42 lines
1.8 KiB
JavaScript
42 lines
1.8 KiB
JavaScript
import { setupNativeEvents } from "../data/events.js";
|
|
import { createRouter, scrollToHash, bindEvent } from "./createRouter.js";
|
|
import { createBeforeLeave, keepDepth, notifyIfNotBlocked, saveCurrentDepth } from "../lifecycle.js";
|
|
export function hashParser(str) {
|
|
const to = str.replace(/^.*?#/, "");
|
|
// Hash-only hrefs like `#foo` from plain anchors will come in as `/#foo` whereas a link to
|
|
// `/foo` will be `/#/foo`. Check if the to starts with a `/` and if not append it as a hash
|
|
// to the current path so we can handle these in-page anchors correctly.
|
|
if (!to.startsWith("/")) {
|
|
const [, path = "/"] = window.location.hash.split("#", 2);
|
|
return `${path}#${to}`;
|
|
}
|
|
return to;
|
|
}
|
|
export function HashRouter(props) {
|
|
const getSource = () => window.location.hash.slice(1);
|
|
const beforeLeave = createBeforeLeave();
|
|
return createRouter({
|
|
get: getSource,
|
|
set({ value, replace, scroll, state }) {
|
|
if (replace) {
|
|
window.history.replaceState(keepDepth(state), "", "#" + value);
|
|
}
|
|
else {
|
|
window.history.pushState(state, "", "#" + value);
|
|
}
|
|
const hashIndex = value.indexOf("#");
|
|
const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : "";
|
|
scrollToHash(hash, scroll);
|
|
saveCurrentDepth();
|
|
},
|
|
init: notify => bindEvent(window, "hashchange", notifyIfNotBlocked(notify, delta => !beforeLeave.confirm(delta && delta < 0 ? delta : getSource()))),
|
|
create: setupNativeEvents({ preload: props.preload, explicitLinks: props.explicitLinks, actionBase: props.actionBase }),
|
|
utils: {
|
|
go: delta => window.history.go(delta),
|
|
renderPath: path => `#${path}`,
|
|
parsePath: hashParser,
|
|
beforeLeave
|
|
}
|
|
})(props);
|
|
}
|