- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
140 lines
4.1 KiB
JavaScript
140 lines
4.1 KiB
JavaScript
// modules/core/router.js
|
||
import { init as initClickManager } from './ClickManager.js';
|
||
import { navigateTo } from './navigateTo.js';
|
||
|
||
const routes = new Map();
|
||
const wildcards = [];
|
||
const guards = new Map();
|
||
|
||
let currentRoute = null;
|
||
let layoutCallback = null;
|
||
let metaCallback = null;
|
||
|
||
/**
|
||
* Registriert eine neue Route mit optionalem Handler
|
||
* @param {string} path - Pfad der Route
|
||
* @param {Function} handler - Callback bei Treffer
|
||
*/
|
||
export function defineRoute(path, handler) {
|
||
if (path.includes('*')) {
|
||
wildcards.push({ pattern: new RegExp('^' + path.replace('*', '.*') + '$'), handler });
|
||
} else {
|
||
routes.set(path, handler);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Definiert einen Guard für eine Route
|
||
* @param {string} path - Pfad
|
||
* @param {Function} guard - Guard-Funktion (return false = block)
|
||
*/
|
||
export function guardRoute(path, guard) {
|
||
guards.set(path, guard);
|
||
}
|
||
|
||
/**
|
||
* Gibt die aktuell aktive Route zurück
|
||
*/
|
||
export function getRouteContext() {
|
||
return currentRoute;
|
||
}
|
||
|
||
/**
|
||
* Setzt eine Callback-Funktion für dynamische Layout-Switches
|
||
*/
|
||
export function onLayoutSwitch(fn) {
|
||
layoutCallback = fn;
|
||
}
|
||
|
||
/**
|
||
* Setzt eine Callback-Funktion für Meta-Daten (z. B. title, theme)
|
||
*/
|
||
export function onMetaUpdate(fn) {
|
||
metaCallback = fn;
|
||
}
|
||
|
||
function matchRoute(href) {
|
||
if (routes.has(href)) return routes.get(href);
|
||
for (const entry of wildcards) {
|
||
if (entry.pattern.test(href)) return entry.handler;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function runGuard(href) {
|
||
const guard = guards.get(href);
|
||
return guard ? guard(href) !== false : true;
|
||
}
|
||
|
||
function extractMetaFromHTML(html) {
|
||
const temp = document.createElement('div');
|
||
temp.innerHTML = html;
|
||
const metaTags = {};
|
||
temp.querySelectorAll('[data-meta]').forEach(el => {
|
||
for (const attr of el.attributes) {
|
||
if (attr.name.startsWith('data-meta-')) {
|
||
const key = attr.name.replace('data-meta-', '');
|
||
metaTags[key] = attr.value;
|
||
}
|
||
}
|
||
})
|
||
//const title = temp.querySelector('[data-meta-title]')?.getAttribute('data-meta-title');
|
||
//const theme = temp.querySelector('[data-meta-theme]')?.getAttribute('data-meta-theme');
|
||
return { metaTags };
|
||
}
|
||
|
||
function animateLayoutSwitch(type) {
|
||
document.body.dataset.layout = type;
|
||
document.body.classList.add('layout-transition');
|
||
setTimeout(() => document.body.classList.remove('layout-transition'), 300);
|
||
}
|
||
|
||
/**
|
||
* Startet den Router mit optionaler Prefetch-Konfiguration
|
||
* @param {Object} prefetchOptions - Optionen für das Prefetching-System
|
||
*/
|
||
export function startRouter(prefetchOptions = {}) {
|
||
initClickManager((href, link, options) => {
|
||
if (!runGuard(href)) return;
|
||
|
||
if (options.modal) {
|
||
const handler = matchRoute(href);
|
||
currentRoute = { href, modal: true, link, options };
|
||
handler?.(currentRoute);
|
||
layoutCallback?.(currentRoute);
|
||
metaCallback?.(currentRoute);
|
||
} else {
|
||
navigateTo(href, {
|
||
...options,
|
||
onUpdate: (html) => {
|
||
const container = document.querySelector('main');
|
||
if (container) container.innerHTML = html;
|
||
|
||
const routeHandler = matchRoute(href);
|
||
currentRoute = { href, html, modal: false };
|
||
|
||
const meta = extractMetaFromHTML(html);
|
||
if (meta.title) document.title = meta.title;
|
||
if (meta.theme) document.documentElement.style.setProperty('--theme-color', meta.theme);
|
||
|
||
routeHandler?.(currentRoute);
|
||
layoutCallback?.(currentRoute);
|
||
metaCallback?.(currentRoute);
|
||
}
|
||
});
|
||
}
|
||
}, prefetchOptions);
|
||
|
||
// Bei Seitenstart erste Route prüfen
|
||
window.addEventListener('DOMContentLoaded', () => {
|
||
const href = location.pathname;
|
||
const routeHandler = matchRoute(href);
|
||
currentRoute = { href, modal: false };
|
||
routeHandler?.(currentRoute);
|
||
layoutCallback?.(currentRoute);
|
||
metaCallback?.(currentRoute);
|
||
});
|
||
}
|
||
|
||
export { animateLayoutSwitch, extractMetaFromHTML };
|