- Fix RedisCache driver to handle MGET failures gracefully with fallback - Add comprehensive discovery context comparison debug tools - Identify root cause: WEB context discovery missing 166 items vs CLI - WEB context missing RequestFactory class entirely (52 vs 69 commands) - Improved exception handling with detailed binding diagnostics
289 lines
9.0 KiB
JavaScript
289 lines
9.0 KiB
JavaScript
|
||
|
||
import { registerModules, activeModules } from "../modules/index.js";
|
||
import { Logger } from './logger.js';
|
||
import {useEvent} from "./useEvent";
|
||
|
||
|
||
|
||
/*import { createTrigger, destroyTrigger, destroyAllTriggers } from './scrollfx/index.js';
|
||
|
||
createTrigger({
|
||
element: 'section',
|
||
target: '.fade',
|
||
start: 'top 80%',
|
||
end: 'bottom 30%',
|
||
scrub: true,
|
||
onUpdate: (() => {
|
||
const progressMap = new WeakMap();
|
||
|
||
return (el, progress) => {
|
||
if (!el) return;
|
||
|
||
let current = progressMap.get(el) || 0;
|
||
current += (progress - current) * 0.1;
|
||
progressMap.set(el, current);
|
||
|
||
el.style.opacity = current;
|
||
el.style.transform = `translateY(${30 - 30 * current}px)`;
|
||
};
|
||
})(),
|
||
|
||
onEnter: el => el.classList.add('entered'),
|
||
onLeave: el => {
|
||
el.classList.remove('entered');
|
||
el.style.opacity = 0;
|
||
el.style.transform = 'translateY(30px)';
|
||
}
|
||
});*/
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
let lastScrollY = window.scrollY;
|
||
|
||
const fadeElements = document.querySelectorAll('.fade-in-on-scroll');
|
||
|
||
// Observer 1: Einblenden beim Runterscrollen
|
||
const fadeInObserver = new IntersectionObserver((entries) => {
|
||
const scrollingDown = window.scrollY > lastScrollY;
|
||
lastScrollY = window.scrollY;
|
||
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting && scrollingDown) {
|
||
entry.target.classList.add('visible');
|
||
}
|
||
});
|
||
}, {
|
||
threshold: 0.4,
|
||
rootMargin: '0px 0px -10% 0px'
|
||
});
|
||
|
||
// Observer 2: Ausblenden beim Hochscrollen
|
||
const fadeOutObserver = new IntersectionObserver((entries) => {
|
||
const scrollingUp = window.scrollY < lastScrollY;
|
||
lastScrollY = window.scrollY;
|
||
|
||
entries.forEach(entry => {
|
||
if (!entry.isIntersecting && scrollingUp) {
|
||
entry.target.classList.remove('visible');
|
||
}
|
||
});
|
||
}, {
|
||
threshold: 0.5,
|
||
rootMargin: '0% 0px 50% 0px' // früher triggern beim Hochscrollen
|
||
});
|
||
|
||
// Alle Elemente mit beiden Observern beobachten
|
||
fadeElements.forEach(el => {
|
||
fadeInObserver.observe(el);
|
||
fadeOutObserver.observe(el);
|
||
});
|
||
*/
|
||
|
||
|
||
/*
|
||
const newContent = '<h1>Neue Seite</h1>'; // dein AJAX-Inhalt z. B.
|
||
const container = document.querySelector('main');
|
||
|
||
document.startViewTransition(() => {
|
||
container.innerHTML = newContent;
|
||
});*/
|
||
|
||
import {autoLoadResponsiveVideos} from "../utils/autoLoadResponsiveVideo";
|
||
|
||
/**
|
||
* Initialize DOM elements with data-module attributes
|
||
*/
|
||
function initDataModuleElements() {
|
||
const elements = document.querySelectorAll('[data-module]');
|
||
Logger.info(`[DOMInit] Found ${elements.length} elements with data-module attributes`);
|
||
|
||
elements.forEach(element => {
|
||
const moduleName = element.dataset.module;
|
||
const moduleData = activeModules.get(moduleName);
|
||
|
||
if (!moduleData || !moduleData.mod) {
|
||
Logger.warn(`[DOMInit] Module "${moduleName}" not found or failed to initialize`);
|
||
return;
|
||
}
|
||
|
||
// Parse options from data-options attribute
|
||
let options = {};
|
||
try {
|
||
if (element.dataset.options) {
|
||
options = JSON.parse(element.dataset.options);
|
||
}
|
||
} catch (error) {
|
||
Logger.warn(`[DOMInit] Invalid JSON in data-options for ${moduleName}:`, error);
|
||
}
|
||
|
||
// Initialize the module on this element
|
||
try {
|
||
const moduleInstance = moduleData.mod;
|
||
|
||
// Check for element-specific init method first, then fallback to general init
|
||
if (typeof moduleInstance.initElement === 'function') {
|
||
const result = moduleInstance.initElement(element, options);
|
||
Logger.info(`[DOMInit] Initialized ${moduleName} on element:`, element);
|
||
|
||
// Store reference for cleanup
|
||
element._moduleInstance = result;
|
||
element._moduleName = moduleName;
|
||
} else if (typeof moduleInstance.init === 'function') {
|
||
const result = moduleInstance.init(element, options);
|
||
Logger.info(`[DOMInit] Initialized ${moduleName} on element:`, element);
|
||
|
||
// Store reference for cleanup
|
||
element._moduleInstance = result;
|
||
element._moduleName = moduleName;
|
||
} else {
|
||
Logger.warn(`[DOMInit] Module ${moduleName} has no init method for DOM elements`);
|
||
}
|
||
} catch (error) {
|
||
Logger.error(`[DOMInit] Failed to initialize ${moduleName} on element:`, error, element);
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Initialize SPA Router for seamless navigation
|
||
*/
|
||
function initSPARouter() {
|
||
const spaRouterModule = activeModules.get('spa-router');
|
||
|
||
if (!spaRouterModule || !spaRouterModule.mod) {
|
||
Logger.info('[Init] SPA Router module not available, skipping');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Initialize SPA Router with default configuration
|
||
const router = spaRouterModule.mod.init({
|
||
containerSelector: 'main',
|
||
enableTransitions: true,
|
||
transitionDuration: 300
|
||
});
|
||
|
||
// Make functions globally available for re-initialization
|
||
window.initAutoFormHandling = initAutoFormHandling;
|
||
window.initDataModuleElements = initDataModuleElements;
|
||
|
||
Logger.info('[Init] SPA Router initialized successfully');
|
||
} catch (error) {
|
||
Logger.error('[Init] Failed to initialize SPA Router:', error);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Auto-initialize all forms with form-handling (opt-out approach)
|
||
*/
|
||
function initAutoFormHandling() {
|
||
// Find all forms except those explicitly opting out and those already enhanced
|
||
const forms = document.querySelectorAll('form:not([data-form-handling="false"]):not([data-auto-enhanced])');
|
||
Logger.info(`[AutoForms] Found ${forms.length} forms for auto-enhancement`);
|
||
|
||
if (forms.length === 0) return;
|
||
|
||
// Check if form-handling module is available
|
||
const formHandlingModule = activeModules.get('form-handling');
|
||
if (!formHandlingModule || !formHandlingModule.mod) {
|
||
Logger.warn('[AutoForms] form-handling module not available, skipping auto-init');
|
||
return;
|
||
}
|
||
|
||
forms.forEach(form => {
|
||
// Skip forms that already have explicit data-module
|
||
if (form.hasAttribute('data-module')) {
|
||
Logger.info(`[AutoForms] Skipping form with explicit data-module:`, form);
|
||
return;
|
||
}
|
||
|
||
// Skip forms that are already enhanced (double-check)
|
||
if (form.hasAttribute('data-auto-enhanced')) {
|
||
return;
|
||
}
|
||
|
||
// Parse options from data-form-options attribute
|
||
let options = {};
|
||
try {
|
||
if (form.dataset.formOptions) {
|
||
options = JSON.parse(form.dataset.formOptions);
|
||
}
|
||
} catch (error) {
|
||
Logger.warn('[AutoForms] Invalid JSON in data-form-options:', error);
|
||
}
|
||
|
||
// Set default options for auto-enhanced forms
|
||
const autoOptions = {
|
||
validateOnSubmit: true,
|
||
validateOnBlur: false,
|
||
validateOnInput: false,
|
||
showInlineErrors: true,
|
||
ajaxSubmit: true,
|
||
enableStateTracking: false, // Conservative default
|
||
...options
|
||
};
|
||
|
||
// Initialize form handling
|
||
try {
|
||
// Use initElement for DOM-specific initialization
|
||
const result = formHandlingModule.mod.initElement ?
|
||
formHandlingModule.mod.initElement(form, autoOptions) :
|
||
formHandlingModule.mod.init(form, autoOptions);
|
||
|
||
Logger.info('[AutoForms] Auto-enhanced form:', {
|
||
id: form.id || 'unnamed',
|
||
action: form.action || 'none',
|
||
method: form.method || 'get',
|
||
elements: form.elements.length
|
||
});
|
||
|
||
// Mark as auto-enhanced
|
||
form.setAttribute('data-auto-enhanced', 'true');
|
||
form._moduleInstance = result;
|
||
form._moduleName = 'form-handling';
|
||
} catch (error) {
|
||
Logger.error('[AutoForms] Failed to auto-enhance form:', error, form);
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Initialize the application
|
||
* Sets up all modules and core functionality
|
||
* @async
|
||
* @function initApp
|
||
* @returns {Promise<void>}
|
||
*/
|
||
export async function initApp() {
|
||
|
||
await registerModules();
|
||
|
||
// Initialize DOM elements after modules are registered
|
||
initDataModuleElements();
|
||
|
||
// Auto-enhance all forms with form-handling
|
||
initAutoFormHandling();
|
||
|
||
// Initialize SPA Router for seamless navigation
|
||
initSPARouter();
|
||
|
||
autoLoadResponsiveVideos();
|
||
|
||
/*initNoiseToggle({
|
||
selector: '.noise-overlay',
|
||
toggleKey: 'g', // Taste zum Umschalten
|
||
className: 'grainy', // Klasse auf <body>
|
||
enableTransition: true // Smooth fade
|
||
});
|
||
|
||
|
||
fadeScrollTrigger('.fade');
|
||
zoomScrollTrigger('.zoomed');
|
||
|
||
fixedZoomScrollTrigger('h1');*/
|
||
}
|