import { Logger } from '../../core/logger.js'; import { SPARouter } from './SPARouter.js'; import { getAdaptiveTransition, fastTransition } from './transition-config.js'; /** * SPA Router Module * * Provides Single Page Application navigation: * - Intercepts internal links and loads content via AJAX * - Updates only the
element, keeping header/footer unchanged * - Manages browser history (back/forward buttons work) * - Shows skeleton loading states during navigation * - Progressive enhancement (falls back to normal navigation on errors) * * Features: * - Automatic link interception for all internal links (href="/...") * - Opt-out via data-spa="false" * - Browser history management with pushState * - Loading states and smooth transitions * - Module re-initialization after content changes * - Skeleton loading animation * * Backend Integration: * - Sends X-SPA-Request header to signal SPA navigation * - Backend can return only
content for SPA requests * - Falls back to full page load if SPA request fails */ const SPARouterModule = { name: 'spa-router', router: null, initialized: false, init(config = {}) { // Prevent multiple initialization if (this.initialized && this.router) { Logger.warn('[SPARouterModule] SPA Router already initialized, returning existing instance'); return this.router; } Logger.info('[SPARouterModule] Initializing SPA Router'); // Default configuration mit schnelleren Transitions const defaultConfig = { containerSelector: 'main', linkSelector: 'a[href^="/"]', excludeSelector: '[data-spa="false"], [download], [target="_blank"], [href^="mailto:"], [href^="tel:"], [href^="#"]', enableSkeletonLoading: true, ...fastTransition, // Verwende schnelle Transitions als Standard ...getAdaptiveTransition() // Überschreibe mit adaptiven Einstellungen }; const options = { ...defaultConfig, ...config }; // Initialize router this.router = SPARouter.create(options); this.initialized = true; // Set up global access if (typeof window !== 'undefined') { window.spaRouter = this.router; } // Listen for module re-initialization events document.addEventListener('spa:reinit-module', this.handleModuleReinit.bind(this)); // Listen for navigation events for debugging document.addEventListener('spa:navigated', this.handleNavigation.bind(this)); Logger.info('[SPARouterModule] SPA Router initialized successfully'); return this.router; }, handleModuleReinit(event) { const { element, moduleName } = event.detail; Logger.info(`[SPARouterModule] Re-initializing module: ${moduleName}`, element); // This would need access to the main module system // For now, we'll just log and let the main init system handle it // Trigger a custom event that the main module system can listen to const reinitEvent = new CustomEvent('module:reinit-needed', { detail: { element, moduleName }, bubbles: true }); document.dispatchEvent(reinitEvent); }, handleNavigation(event) { const { url, timestamp } = event.detail; Logger.info(`[SPARouterModule] Navigation completed to: ${url}`); // Re-run auto form enhancement for new content if (typeof window.initAutoFormHandling === 'function') { // Only re-initialize forms that are not already enhanced setTimeout(() => { window.initAutoFormHandling(); }, 100); } // Trigger analytics or other tracking if needed if (typeof window.gtag === 'function') { window.gtag('config', 'GA_TRACKING_ID', { page_path: new URL(url).pathname }); } }, // Public API methods navigateTo(url, title) { if (this.router) { return this.router.navigateTo(url, title); } Logger.warn('[SPARouterModule] Router not initialized'); }, getCurrentUrl() { return this.router?.getCurrentUrl() || window.location.href; }, isNavigating() { return this.router?.isNavigating() || false; }, destroy() { if (this.router) { this.router.destroy(); this.router = null; } this.initialized = false; // Remove global reference if (typeof window !== 'undefined' && window.spaRouter) { delete window.spaRouter; } document.removeEventListener('spa:reinit-module', this.handleModuleReinit); document.removeEventListener('spa:navigated', this.handleNavigation); Logger.info('[SPARouterModule] SPA Router destroyed'); } }; // Export the router class for direct usage export { SPARouter }; // Export as default for module system export default SPARouterModule; // Export init function directly for compatibility with module system export const init = SPARouterModule.init.bind(SPARouterModule); // Also export named for direct usage export { SPARouterModule };