// Universal Toggle Manager - Complete solution for all config toggles class ToggleManager { constructor() { this.toggles = new Map(); this.init(); } init() { //console.log('ToggleManager: Initializing...'); // Auto-discover all toggle configurations this.discoverToggles(); //console.log('ToggleManager: Discovered', this.toggles.size, 'toggle configurations'); // Debug: Log discovered toggles if (this.toggles.size > 0) { //console.log('ToggleManager: No toggles found - will retry after config loads...'); // Set up a mutation observer to detect when config content is added this.setupContentObserver(); } else { //console.log('ToggleManager: Discovered toggles:', Array.from(this.toggles.keys())); } // Also set up observer in case more toggles are added later this.setupContentObserver(); // Retry discovery after a short delay to handle timing issues setTimeout(() => { //console.log('ToggleManager: Retrying toggle discovery...'); this.rediscoverToggles(); }, 100); } // Set up observer to detect when config content is loaded setupContentObserver() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { // Check if any new elements with data-toggle-config were added const newToggles = Array.from(mutation.addedNodes).filter(node => node.nodeType === Node.ELEMENT_NODE && (node.dataset?.toggleConfig || node.querySelector('[data-toggle-config]'))); if (newToggles.length > 0) { //console.log('ToggleManager: New toggle elements detected, re-discovering...'); this.rediscoverToggles(); observer.disconnect(); // Stop observing once we find toggles } } }); }); // Start observing the main content area const contentContainer = document.getElementById('main-content') || document.querySelector('.main'); if (contentContainer) { observer.observe(contentContainer, { childList: true, subtree: true }); } } // Re-discover toggles (called after content is loaded) rediscoverToggles() { //console.log('ToggleManager: Re-discovering toggles...'); this.toggles.clear(); // Clear existing toggles this.discoverToggles(); //console.log('ToggleManager: Re-discovered', this.toggles.size, 'toggle configurations'); if (this.toggles.size > 0) { //console.log('ToggleManager: Successfully discovered toggles:', Array.from(this.toggles.keys())); } } // Auto-discover toggle configurations from the page discoverToggles() { //console.log('ToggleManager: Looking for elements with [data-toggle-config]...'); // Find all elements with data-toggle-config attribute const toggleElements = document.querySelectorAll('[data-toggle-config]'); //console.log('ToggleManager: Found', toggleElements.length, 'elements with data-toggle-config'); toggleElements.forEach((element, index) => { const config = element.dataset.toggleConfig; const sectionId = element.dataset.sectionId; const toggleType = element.dataset.toggleType || 'checkbox'; //console.log(`ToggleManager: Processing element ${index}:`, { //config: config, //sectionId: sectionId, //toggleType: toggleType, //element: element.tagName + (element.id ? '#' + element.id : '') + (element.name ? '[name=' + element.name + ']' : '') //}); if (config && sectionId) { this.toggles.set(config, { config: config, sectionId: sectionId, toggleType: toggleType, element: element }); //console.log(`ToggleManager: Registered toggle for config: ${config}`); } else { //console.log(`ToggleManager: Skipping element - missing config or sectionId`); } }); } // Universal toggle function - works for any config option toggle(configKey, isEnabled) { //console.log('=== TOGGLE MANAGER DEBUG ==='); //console.log('configKey:', configKey); //console.log('isEnabled:', isEnabled); const toggle = this.toggles.get(configKey); if (!toggle) { console.error('ToggleManager: No toggle found for config:', configKey); return false; } //console.log('Toggle found:', toggle); const sectionContent = document.getElementById(toggle.sectionId); const fields = sectionContent?.querySelectorAll('.config-fields input, .config-fields select, .config-fields textarea'); //console.log('sectionContent found:', !!sectionContent); //console.log('fields found:', fields ? fields.length : 0); if (sectionContent && fields) { if (isEnabled) { //console.log('Enabling section...'); sectionContent.classList.remove('hidden'); fields.forEach((field, index) => { //console.log(`Enabling field ${index}:`, field); field.disabled = false; const fieldGroup = field?.closest('.field-group'); if (fieldGroup) { fieldGroup.style.opacity = '1'; fieldGroup.style.pointerEvents = 'auto'; } }); } else { //console.log('Disabling section...'); sectionContent.classList.add('hidden'); fields.forEach((field, index) => { //console.log(`Disabling field ${index}:`, field); field.disabled = true; const fieldGroup = field?.closest('.field-group'); if (fieldGroup) { fieldGroup.style.opacity = '0.5'; fieldGroup.style.pointerEvents = 'none'; } }); } //console.log('=== TOGGLE MANAGER SUCCESS ==='); return true; } else { console.error('ToggleManager: Section content or fields not found'); return false; } } // Universal toggle section renderer - works for ANY config option static renderToggleSection(configKey, configItems, displaySubcategory, subcategoryDescription, config) { const isEnabled = configKey.value === 'true' || configKey.value === 'git'; const sectionId = `${configKey.key.replace(/[^a-zA-Z0-9]/g, '-')}-${configKey.key}`; const toggleId = `${configKey.key.toLowerCase()}-toggle`; // Determine toggle type and class based on config key let toggleType = 'checkbox'; let toggleClass = 'generic-master-toggle'; if (configKey.key.includes('INSTALL_MODE')) { toggleType = 'select'; toggleClass = 'git-master-toggle'; } else if (configKey.key.includes('MAIL')) { toggleType = 'checkbox'; toggleClass = 'mail-master-toggle'; } else if (configKey.key.includes('BACKUP_REMOTE_')) { // Specifically target BACKUP_REMOTE_1_ENABLED, BACKUP_REMOTE_2_ENABLED, etc. toggleType = 'checkbox'; toggleClass = 'backup-remote-toggle'; } let html = `

${displaySubcategory}

${subcategoryDescription}

`; if (toggleType === 'select') { // Git/Select toggle html += ` `; } else { // Checkbox toggle html += ` `; } html += `
`; // Add all other fields (excluding the toggle key itself) configItems.filter(item => item.key !== configKey.key).forEach(item => { const fieldId = `config-${item.key}`; html += window.ConfigShared?.generateField(fieldId, item.key, item.value, item.title, item.description, item.options, config) || ''; }); // Add special buttons for specific config types if (configKey.key.includes('MAIL')) { html += `
`; } html += `
`; return html; } // Register a new toggle configuration register(configKey, sectionId, toggleType = 'checkbox') { this.toggles.set(configKey, { config: configKey, sectionId: sectionId, toggleType: toggleType }); } // Get all registered toggles getToggles() { return Array.from(this.toggles.keys()); } // Check if a toggle exists hasToggle(configKey) { return this.toggles.has(configKey); } } // Global instance window.toggleManager = new ToggleManager(); // Make static method available on instance too window.toggleManager.renderToggleSection = ToggleManager.renderToggleSection; // Add method to manually trigger discovery when config is loaded window.toggleManager.forceRediscover = function() { //console.log('ToggleManager: Force re-discovering toggles...'); window.toggleManager.rediscoverToggles(); }; // Static access for backward compatibility window.ConfigShared = window.ConfigShared || {}; window.ConfigShared.toggleSection = function(sectionId, isEnabled) { // Try to find the config key from the section const toggleElements = document.querySelectorAll(`[data-section-id="${sectionId}"]`); if (toggleElements.length > 0) { const configKey = toggleElements[0].dataset.toggleConfig; return window.toggleManager.toggle(configKey, isEnabled); } else { console.error('ConfigShared.toggleSection: No toggle found for section:', sectionId); return false; } };