chore: complete update
This commit is contained in:
136
resources/js/core/ClickManager.js
Normal file
136
resources/js/core/ClickManager.js
Normal file
@@ -0,0 +1,136 @@
|
||||
// modules/core/click-manager.js
|
||||
import { Logger } from './logger.js';
|
||||
import { useEvent } from './useEvent.js';
|
||||
import {navigateTo} from "./navigateTo";
|
||||
import {SimpleCache} from "../utils/cache";
|
||||
|
||||
let callback = null;
|
||||
let unsubscribes = [];
|
||||
let cleanupInterval = null;
|
||||
const prefetchCache = new SimpleCache(20, 60000); //new Map();
|
||||
const maxCacheSize = 20; // max. Anzahl gecachter Seiten
|
||||
const cacheTTL = 60000; // Lebensdauer in ms (60s)
|
||||
|
||||
function isInternal(link) {
|
||||
return link.origin === location.origin;
|
||||
}
|
||||
|
||||
function handleClick(e) {
|
||||
const link = e.target.closest('a');
|
||||
if (!link || e.defaultPrevented) return;
|
||||
|
||||
const href = link.getAttribute('href');
|
||||
if (!href || href.startsWith('#')) return;
|
||||
|
||||
// Skip conditions
|
||||
if (
|
||||
link.target === '_blank' ||
|
||||
link.hasAttribute('download') ||
|
||||
link.getAttribute('rel')?.includes('external') ||
|
||||
link.hasAttribute('data-skip')
|
||||
) {
|
||||
Logger.info(`[click-manager] skipped: ${href}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInternal(link)) {
|
||||
e.preventDefault();
|
||||
|
||||
const cached = prefetchCache.get(href);
|
||||
const valid = cached && Date.now() - cached.timestamp < cacheTTL;
|
||||
|
||||
const options = {
|
||||
viewTransition: link.hasAttribute('data-view-transition'),
|
||||
replace: link.hasAttribute('data-replace'),
|
||||
modal: link.hasAttribute('data-modal'),
|
||||
prefetched: valid,
|
||||
data: valid ? cached.data : null,
|
||||
};
|
||||
|
||||
Logger.info(`[click-manager] internal: ${href}`, options);
|
||||
|
||||
if(options.modal) {
|
||||
callback?.(href, link, options);
|
||||
} else {
|
||||
navigateTo(href, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let prefetchTimeout;
|
||||
function handleMouseOver(e) {
|
||||
clearTimeout(prefetchTimeout);
|
||||
const link = e.target.closest('a[href]');
|
||||
if (!link || !isInternal(link)) return;
|
||||
|
||||
const href = link.getAttribute('href');
|
||||
if (!href || prefetchCache.has(href)) return;
|
||||
|
||||
// optional: Wait 150ms to reduce noise
|
||||
prefetchTimeout = setTimeout(() => prefetch(href), 150);
|
||||
}
|
||||
|
||||
function prefetch(href) {
|
||||
Logger.info(`[click-manager] prefetching: ${href}`);
|
||||
|
||||
fetch(href)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
if (prefetchCache.cache.size >= maxCacheSize) {
|
||||
const oldestKey = [...prefetchCache.cache.entries()].sort((a, b) => a[1].timestamp - b[1].timestamp)[0][0];
|
||||
prefetchCache.cache.delete(oldestKey);
|
||||
}
|
||||
prefetchCache.set(href, {
|
||||
data: html,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
Logger.warn(`[click-manager] prefetch failed for ${href}`, err);
|
||||
});
|
||||
}
|
||||
|
||||
function handlePopState() {
|
||||
const href = location.pathname;
|
||||
Logger.info(`[click-manager] popstate: ${href}`);
|
||||
navigateTo(href, { replace: true });
|
||||
}
|
||||
|
||||
export function getPrefetched(href) {
|
||||
const cached = prefetchCache.get(href);
|
||||
const valid = cached && Date.now() - cached.timestamp < cacheTTL;
|
||||
return valid ? cached.data : null;
|
||||
}
|
||||
|
||||
export function prefetchHref(href) {
|
||||
if (!href || prefetchCache.has(href)) return;
|
||||
prefetch(href);
|
||||
}
|
||||
|
||||
export function init(onNavigate) {
|
||||
callback = onNavigate;
|
||||
unsubscribes = [
|
||||
useEvent(document, 'click', handleClick),
|
||||
useEvent(document, 'mouseover', handleMouseOver),
|
||||
useEvent(window, 'popstate', handlePopState),
|
||||
]
|
||||
|
||||
cleanupInterval = setInterval(() => {
|
||||
for (const [key, val] of prefetchCache.cache.entries()) {
|
||||
if (Date.now() - val.timestamp > prefetchCache.ttl) {
|
||||
prefetchCache.cache.delete(key);
|
||||
}
|
||||
}
|
||||
}, 120000);
|
||||
|
||||
|
||||
Logger.info('[click-manager] ready');
|
||||
}
|
||||
|
||||
export function destroy() {
|
||||
callback = null;
|
||||
prefetchCache.clear();
|
||||
unsubscribes.forEach(unsub => unsub());
|
||||
unsubscribes = [];
|
||||
Logger.info('[click-manager] destroyed');
|
||||
}
|
||||
Reference in New Issue
Block a user