diff --git a/web_interface/static/v3/plugins_manager.js b/web_interface/static/v3/plugins_manager.js index 58239d74..64c4db58 100644 --- a/web_interface/static/v3/plugins_manager.js +++ b/web_interface/static/v3/plugins_manager.js @@ -6414,6 +6414,184 @@ window.updateImageScheduleDay = function(fieldId, imageId, imageIdx, day) { })(); // End IIFE +// Functions to handle array-of-objects +// Define these at the top level (outside any IIFE) to ensure they're always available +if (typeof window !== 'undefined') { + window.addArrayObjectItem = function(fieldId, fullKey, maxItems) { + const itemsContainer = document.getElementById(fieldId + '_items'); + const hiddenInput = document.getElementById(fieldId + '_data'); + if (!itemsContainer || !hiddenInput) return; + + const currentItems = itemsContainer.querySelectorAll('.array-object-item'); + if (currentItems.length >= maxItems) { + alert(`Maximum ${maxItems} items allowed`); + return; + } + + // Get schema for item properties from the hidden input's data attribute or currentPluginConfig + const schema = (typeof currentPluginConfig !== 'undefined' && currentPluginConfig?.schema) || (typeof window.currentPluginConfig !== 'undefined' && window.currentPluginConfig?.schema); + if (!schema) return; + + // Navigate to the items schema + const keys = fullKey.split('.'); + let itemsSchema = schema.properties; + for (const key of keys) { + if (itemsSchema && itemsSchema[key]) { + itemsSchema = itemsSchema[key]; + if (itemsSchema.type === 'array' && itemsSchema.items) { + itemsSchema = itemsSchema.items; + break; + } + } + } + + if (!itemsSchema || !itemsSchema.properties) return; + + const newIndex = currentItems.length; + // Use renderArrayObjectItem if available, otherwise create basic HTML + let itemHtml = ''; + if (typeof renderArrayObjectItem === 'function') { + itemHtml = renderArrayObjectItem(fieldId, fullKey, itemsSchema.properties, {}, newIndex, itemsSchema); + } else { + // Fallback: create basic HTML structure + itemHtml = `
`; + Object.keys(itemsSchema.properties || {}).forEach(propKey => { + const propSchema = itemsSchema.properties[propKey]; + const propLabel = propSchema.title || propKey.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); + itemHtml += `
`; + if (propSchema.type === 'boolean') { + itemHtml += ``; + } else { + itemHtml += ``; + } + itemHtml += `
`; + }); + itemHtml += `
`; + } + itemsContainer.insertAdjacentHTML('beforeend', itemHtml); + window.updateArrayObjectData(fieldId); + + // Update add button state + const addButton = itemsContainer.nextElementSibling; + if (addButton && currentItems.length + 1 >= maxItems) { + addButton.disabled = true; + addButton.style.opacity = '0.5'; + addButton.style.cursor = 'not-allowed'; + } + }; + + window.removeArrayObjectItem = function(fieldId, index) { + const itemsContainer = document.getElementById(fieldId + '_items'); + if (!itemsContainer) return; + + const item = itemsContainer.querySelector(`.array-object-item[data-index="${index}"]`); + if (item) { + item.remove(); + // Re-index remaining items + const remainingItems = itemsContainer.querySelectorAll('.array-object-item'); + remainingItems.forEach((itemEl, newIndex) => { + itemEl.setAttribute('data-index', newIndex); + // Update all inputs within this item - need to update name/id attributes + itemEl.querySelectorAll('input, select, textarea').forEach(input => { + const name = input.getAttribute('name') || input.id; + if (name) { + // Update name/id attribute with new index + const newName = name.replace(/\[\d+\]/, `[${newIndex}]`); + if (input.getAttribute('name')) input.setAttribute('name', newName); + if (input.id) input.id = input.id.replace(/\d+/, newIndex); + } + }); + // Update button onclick attributes + itemEl.querySelectorAll('button[onclick]').forEach(button => { + const onclick = button.getAttribute('onclick'); + if (onclick) { + button.setAttribute('onclick', onclick.replace(/\d+/, newIndex)); + } + }); + }); + window.updateArrayObjectData(fieldId); + + // Update add button state + const addButton = itemsContainer.nextElementSibling; + if (addButton) { + const maxItems = parseInt(addButton.getAttribute('onclick').match(/\d+/)[0]); + if (remainingItems.length < maxItems) { + addButton.disabled = false; + addButton.style.opacity = '1'; + addButton.style.cursor = 'pointer'; + } + } + } + }; + + window.updateArrayObjectData = function(fieldId) { + const itemsContainer = document.getElementById(fieldId + '_items'); + const hiddenInput = document.getElementById(fieldId + '_data'); + if (!itemsContainer || !hiddenInput) return; + + const items = []; + const itemElements = itemsContainer.querySelectorAll('.array-object-item'); + + itemElements.forEach((itemEl, index) => { + const item = {}; + // Get all text inputs in this item + itemEl.querySelectorAll('input[type="text"], input[type="url"], input[type="number"]').forEach(input => { + const propKey = input.getAttribute('data-prop-key'); + if (propKey && propKey !== 'logo_file') { + item[propKey] = input.value.trim(); + } + }); + // Handle checkboxes + itemEl.querySelectorAll('input[type="checkbox"]').forEach(checkbox => { + const propKey = checkbox.getAttribute('data-prop-key'); + if (propKey) { + item[propKey] = checkbox.checked; + } + }); + // Handle file upload data (stored in data attributes) + itemEl.querySelectorAll('[data-file-data]').forEach(fileEl => { + const fileData = fileEl.getAttribute('data-file-data'); + if (fileData) { + try { + const data = JSON.parse(fileData); + const propKey = fileEl.getAttribute('data-prop-key'); + if (propKey) { + item[propKey] = data; + } + } catch (e) { + console.error('Error parsing file data:', e); + } + } + }); + items.push(item); + }); + + hiddenInput.value = JSON.stringify(items); + }; + + window.handleArrayObjectFileUpload = function(event, fieldId, itemIndex, propKey, pluginId) { + // TODO: Implement file upload handling for array object items + // This is a placeholder - file upload in nested objects needs special handling + console.log('File upload for array object item:', { fieldId, itemIndex, propKey, pluginId }); + window.updateArrayObjectData(fieldId); + }; + + window.removeArrayObjectFile = function(fieldId, itemIndex, propKey) { + // TODO: Implement file removal for array object items + // This is a placeholder - file removal in nested objects needs special handling + console.log('File removal for array object item:', { fieldId, itemIndex, propKey }); + window.updateArrayObjectData(fieldId); + }; + + console.log('[ARRAY-OBJECTS] Functions defined on window:', { + addArrayObjectItem: typeof window.addArrayObjectItem, + removeArrayObjectItem: typeof window.removeArrayObjectItem, + updateArrayObjectData: typeof window.updateArrayObjectData, + handleArrayObjectFileUpload: typeof window.handleArrayObjectFileUpload, + removeArrayObjectFile: typeof window.removeArrayObjectFile + }); +} + // Make currentPluginConfig globally accessible (outside IIFE) window.currentPluginConfig = null;