70 lines
1.5 KiB
TypeScript
70 lines
1.5 KiB
TypeScript
type NavigationListener = (loading: boolean) => void;
|
|
|
|
let listeners = new Set<NavigationListener>();
|
|
let loading = false;
|
|
|
|
function notify() {
|
|
listeners.forEach((listener) => listener(loading));
|
|
}
|
|
|
|
export function subscribeNavigationLoading(listener: NavigationListener) {
|
|
listeners.add(listener);
|
|
listener(loading);
|
|
return () => {
|
|
listeners.delete(listener);
|
|
};
|
|
}
|
|
|
|
export function startNavigation() {
|
|
if (loading) return;
|
|
loading = true;
|
|
notify();
|
|
}
|
|
|
|
export function stopNavigation() {
|
|
if (!loading) return;
|
|
loading = false;
|
|
notify();
|
|
}
|
|
|
|
export function isNavigationLoading() {
|
|
return loading;
|
|
}
|
|
|
|
export function isInternalNavigationClick(
|
|
event: MouseEvent,
|
|
anchor: HTMLAnchorElement
|
|
): boolean {
|
|
if (event.defaultPrevented) return false;
|
|
if (event.button !== 0) return false;
|
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return false;
|
|
if (anchor.target === "_blank") return false;
|
|
if (anchor.hasAttribute("download")) return false;
|
|
|
|
const href = anchor.getAttribute("href");
|
|
if (
|
|
!href ||
|
|
href.startsWith("#") ||
|
|
href.startsWith("mailto:") ||
|
|
href.startsWith("tel:") ||
|
|
href.startsWith("javascript:")
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const url = new URL(href, window.location.href);
|
|
if (url.origin !== window.location.origin) return false;
|
|
if (
|
|
url.pathname === window.location.pathname &&
|
|
url.search === window.location.search &&
|
|
!url.hash
|
|
) {
|
|
return false;
|
|
}
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|