Files
ai.interactive.fiction/public/js/ui-helper.js

171 lines
5.4 KiB
JavaScript

/**
* 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() };
}