native-spa-route
Version:
provide SPA route's experience with native web component
109 lines (108 loc) • 4.15 kB
JavaScript
export function hook_a_link() {
document.body.addEventListener('click', (e) => {
const target = e.composedPath()[0];
if (target.tagName === 'A') {
const href = target.getAttribute('href');
if (typeof href === 'string') {
if (href.startsWith('http')) {
return;
}
e.preventDefault();
history.pushState({}, target.getAttribute('title') ?? '', href);
}
}
});
}
function _hook_3_params_func(lifecycle, func_name) {
window.history[func_name] = new Proxy(window.history[func_name], {
apply: (target, thisArg, argArray) => {
const arg0 = argArray[0];
const arg1 = argArray[1];
const arg2 = argArray[2];
let _url = arg2;
if (typeof lifecycle?.url_adapter === 'function') {
_url = lifecycle.url_adapter(_url);
}
lifecycle?.before?.(func_name, arg0, arg1, _url);
const ret = target.apply(thisArg, [arg0, arg1, _url]);
lifecycle?.after?.(func_name, arg0, arg1, _url);
window.dispatchEvent(new CustomEvent(`history:${func_name}`, {
detail: {
type: func_name,
data: arg0,
unused: arg1,
url: _url,
},
}));
return ret;
},
});
}
function _hook_0_params_func(lifecycle, func_name) {
window.history[func_name] = new Proxy(window.history[func_name], {
apply: (target, thisArg) => {
lifecycle?.before?.(func_name, undefined, '', undefined);
const ret = target.apply(thisArg, []);
lifecycle?.after?.(func_name, undefined, '', undefined);
window.dispatchEvent(new CustomEvent(`history:${func_name}`, {
detail: {
type: func_name,
},
}));
return ret;
},
});
}
function _hook_1_params_func(lifecycle, func_name) {
window.history[func_name] = new Proxy(window.history[func_name], {
apply: (target, thisArg, argArray) => {
lifecycle?.before?.(func_name, argArray[0], '', undefined);
const ret = target.apply(thisArg, argArray);
lifecycle?.after?.(func_name, argArray[0], '', undefined);
window.dispatchEvent(new CustomEvent(`history:${func_name}`, {
detail: {
type: func_name,
delta: argArray[0]
},
}));
return ret;
},
});
}
let hook_history_change_hooked = false;
export function hook_history_change(lifecycle = {}) {
if (hook_history_change_hooked)
return;
hook_history_change_hooked = true;
_hook_3_params_func(lifecycle, 'pushState');
_hook_3_params_func(lifecycle, 'replaceState');
_hook_0_params_func(lifecycle, 'back');
_hook_0_params_func(lifecycle, 'forward');
_hook_1_params_func(lifecycle, 'go');
}
export function hook_route_change(callback) {
window.addEventListener('history:pushState', callback);
window.addEventListener('history:replaceState', callback);
window.addEventListener('history:back', callback);
window.addEventListener('history:forward', callback);
window.addEventListener('history:go', callback);
window.addEventListener('popstate', callback, false);
}
export function unhook_route_change(callback) {
window.removeEventListener('history:pushState', callback);
window.removeEventListener('history:replaceState', callback);
window.removeEventListener('history:back', callback);
window.removeEventListener('history:forward', callback);
window.removeEventListener('history:go', callback);
window.removeEventListener('popstate', callback, false);
}
export function redirect(from, to) {
if (location.pathname === from) {
history.pushState(null, '', to);
}
hook_route_change(() => {
if (location.pathname === from) {
history.pushState(null, '', to);
}
});
}