/** * UI Helper * Provides utility functions for UI components */ /** * Create and append a UI element * @param {string} type - Element type (div, input, button, etc.) * @param {Object} attributes - Attributes to set on the element * @param {string} [text] - Text content for the element * @param {HTMLElement} parent - Parent element * @returns {HTMLElement} - Created element */ export function createUIElement(type, attributes = {}, text = '', parent = null) { const element = document.createElement(type); // Set attributes for (const [key, value] of Object.entries(attributes || {})) { if (key === 'className') { element.className = value; } else { element.setAttribute(key, value); } } // Set text content if provided if (text) { element.textContent = text; } // Append to parent if provided if (parent) { parent.appendChild(element); } return element; } /** * Populate a dropdown with options * @param {HTMLSelectElement} dropdown - Dropdown element * @param {Array} items - Array of items * @param {string} valueKey - Key for item value * @param {string} textKey - Key for item text * @param {string} [selectedValue] - Value to select */ export function populateDropdown(dropdown, items, valueKey, textKey, selectedValue) { // Clear existing options dropdown.innerHTML = ''; // Add options items.forEach(item => { const option = document.createElement('option'); option.value = item[valueKey]; option.textContent = item[textKey]; dropdown.appendChild(option); }); // Set selected value if provided if (selectedValue !== undefined && selectedValue !== null) { dropdown.value = selectedValue; } } /** * Register an event handler for a UI element * @param {HTMLElement} element - UI element * @param {string} eventType - Event type (change, input, click, etc.) * @param {Function} handler - Event handler function */ export function registerHandler(element, eventType, handler) { if (element) { element.addEventListener(eventType, handler); } } /** * Create a preference binding between a UI element and persistence manager * @param {HTMLElement} element - UI element * @param {Object} persistenceManager - Persistence manager instance * @param {string} category - Preference category * @param {string} key - Preference key * @param {Function} [updateUIFunc] - Function to update UI when preference changes * @param {Function} [valueTransform] - Function to transform value before saving */ export function createPreferenceBinding(element, persistenceManager, category, key, updateUIFunc, valueTransform) { if (!element || !persistenceManager) return; // Get initial value from persistence const value = persistenceManager.getPreference(category, key); // Update UI initially if value exists and update function provided if (value !== null && value !== undefined && updateUIFunc) { updateUIFunc(element, value); } else { // Default UI update based on element type if (element.type === 'checkbox') { element.checked = !!value; } else if (element.tagName === 'SELECT' || element.type === 'text' || element.type === 'password') { element.value = value !== null && value !== undefined ? value : ''; } else if (element.type === 'range') { element.value = value !== null && value !== undefined ? value : 50; } } // Add event listener const eventType = element.type === 'checkbox' ? 'change' : 'input'; element.addEventListener(eventType, () => { let newValue; if (element.type === 'checkbox') { newValue = element.checked; } else if (element.type === 'range' || element.type === 'number') { newValue = parseFloat(element.value); } else { newValue = element.value; } // Apply transform if provided if (valueTransform) { newValue = valueTransform(newValue, element); } // Save to persistence persistenceManager.updatePreference(category, key, newValue); // Dispatch event for other modules document.dispatchEvent(new CustomEvent('preference:changed', { detail: { category, key, value: newValue } })); }); } /** * Set up common modal behaviors (show/hide/close) * @param {HTMLElement} modal - Modal element * @param {HTMLElement} [closeButton] - Close button element * @returns {Object} - Modal control functions */ export function setupModalControls(modal, closeButton) { if (!modal) return {}; const show = () => { modal.style.display = 'flex'; document.body.classList.add('modal-open'); }; const hide = () => { modal.style.display = 'none'; document.body.classList.remove('modal-open'); }; // Set up close button if provided if (closeButton) { closeButton.addEventListener('click', hide); } // Set up ESC key to close document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && modal.style.display === 'flex') { hide(); } }); return { show, hide, toggle: () => modal.style.display === 'flex' ? hide() : show() }; }