- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
159 lines
5.3 KiB
JavaScript
159 lines
5.3 KiB
JavaScript
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 <main> 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 <main> 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 }; |