| | |
| | | const fieldType = this.getFieldType(fieldWrapper); |
| | | |
| | | switch (fieldType) { |
| | | case 'image': |
| | | this.populateImageField(fieldWrapper, fieldName, fieldValue, imagesData); |
| | | break; |
| | | |
| | | case 'upload': |
| | | case 'gallery': |
| | | this.populateGalleryField(fieldWrapper, fieldName, fieldValue, imagesData); |
| | | case 'image': |
| | | this.populateUploadField(fieldWrapper, fieldName, fieldValue, imagesData); |
| | | break; |
| | | |
| | | case 'repeater': |
| | |
| | | * @returns {string} Field type |
| | | */ |
| | | getFieldType(fieldWrapper) { |
| | | // Check dataset first (most reliable for our use case) |
| | | if (fieldWrapper.dataset.fieldType) { |
| | | return fieldWrapper.dataset.fieldType; |
| | | } |
| | | |
| | | if (fieldWrapper.dataset.type) { |
| | | return fieldWrapper.dataset.type; |
| | | } |
| | | |
| | | // Check for specific field classes |
| | | const typeClasses = [ |
| | | 'image', 'gallery', 'repeater', 'taxonomy', 'user', 'location', |
| | | 'upload', 'repeater', 'taxonomy', 'user', 'location', |
| | | 'set', 'checkbox', 'select', 'radio', 'true_false', 'date', |
| | | 'time', 'datetime', 'editor', 'number', 'text', 'textarea', |
| | | 'email', 'url', 'tel', 'phone' |
| | |
| | | } |
| | | } |
| | | |
| | | // Check for data attribute |
| | | if (fieldWrapper.dataset.type) { |
| | | return fieldWrapper.dataset.type; |
| | | } |
| | | |
| | | // Check input type |
| | | const input = fieldWrapper.querySelector('input, select, textarea'); |
| | | if (input) { |
| | |
| | | */ |
| | | populateTextField(fieldWrapper, fieldName, fieldValue) { |
| | | const input = fieldWrapper.querySelector(`[name="${fieldName}"], input, textarea`); |
| | | // Skip file inputs - browsers don't allow setting their values programmatically |
| | | if (input && input.type === 'file') { |
| | | return; |
| | | } |
| | | if (input) { |
| | | |
| | | input.value = String(fieldValue || ''); |
| | | |
| | | // Update character counter if present |
| | |
| | | fieldWrapper.querySelector('textarea:not([data-editor="true"])'); |
| | | |
| | | if (textarea) { |
| | | const oldValue = textarea.value; |
| | | textarea.value = String(fieldValue || ''); |
| | | |
| | | // Trigger change event to update any dependencies |
| | |
| | | } else if (typeof fieldValue === 'string') { |
| | | try { |
| | | const parsed = JSON.parse(fieldValue); |
| | | termIds = Array.isArray(parsed) ? parsed.map(v => String(v)) : [String(parsed)]; |
| | | termIds = Array.isArray(parsed) ? |
| | | parsed.map(v => String(v)) : [String(parsed)]; |
| | | } catch (e) { |
| | | termIds = fieldValue.split(',').map(v => v.trim()); |
| | | } |
| | |
| | | const hiddenInput = fieldWrapper.querySelector(`input[type="hidden"][name="${fieldName}"]`); |
| | | if (hiddenInput) { |
| | | hiddenInput.value = termIds.join(','); |
| | | |
| | | // Trigger TaxonomySelector to update visual display |
| | | const toggle = fieldWrapper.querySelector('.taxonomy-toggle'); |
| | | if (toggle && toggle.dataset.fieldId && window.jvbTaxonomy) { |
| | | window.jvbTaxonomy.updateFieldFromInput(toggle.dataset.fieldId); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Populate image fields |
| | | * Populate upload fields (images, videos, files) |
| | | */ |
| | | populateImageField(fieldWrapper, fieldName, fieldValue, imagesData = {}) { |
| | | populateUploadField(fieldWrapper, fieldName, fieldValue, imagesData = {}) { |
| | | // Check if this is a timeline gallery |
| | | const isTimeline = fieldWrapper.dataset.subtype === 'timeline' || fieldName === 'timeline'; |
| | | |
| | | if (isTimeline) { |
| | | this.populateTimelineGallery(fieldWrapper, fieldName, fieldValue, imagesData); |
| | | return; |
| | | } |
| | | |
| | | if (!fieldValue) { |
| | | return; |
| | | } |
| | | |
| | | // Handle comma-separated IDs or single ID |
| | | const imageIds = String(fieldValue).split(',').filter(id => parseInt(id.trim())); |
| | | if (imageIds.length === 0) { |
| | | const itemIds = String(fieldValue).split(',').filter(id => parseInt(id.trim())); |
| | | if (itemIds.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | // Update hidden input |
| | | const hiddenInput = fieldWrapper.querySelector(`input[type="hidden"][name="${fieldName}"]`); |
| | | if (hiddenInput) { |
| | | hiddenInput.value = imageIds.join(','); |
| | | hiddenInput.value = itemIds.join(','); |
| | | } |
| | | |
| | | // Update image display |
| | | // Update display grid |
| | | const grid = fieldWrapper.querySelector('.item-grid'); |
| | | const uploadContainer = fieldWrapper.querySelector('.file-upload-container'); |
| | | fieldWrapper.querySelector('.progress')?.remove(); |
| | | |
| | | // Clear existing items first |
| | | if (grid) { |
| | | window.removeChildren(grid); |
| | | imageIds.forEach(imageId => { |
| | | let image = window.getTemplate('uploadItem'); |
| | | let img = image.querySelector('img'); |
| | | } |
| | | |
| | | let details = image.querySelector('details'); |
| | | let meta = window.getTemplate('uploadMeta') |
| | | details.append(meta); |
| | | [ |
| | | img.src, |
| | | img.alt, |
| | | image.querySelector('[name="image-title"]').value, |
| | | image.querySelector('[name="image-alt-text"]').value, |
| | | image.querySelector('[name="image-caption"]').value, |
| | | ] = [ |
| | | imagesData[imageId].medium, |
| | | imagesData[imageId].alt, |
| | | imagesData[imageId].title, |
| | | imagesData[imageId].alt, |
| | | imagesData[imageId].caption, |
| | | ]; |
| | | fieldWrapper.querySelector('.progress')?.remove(); |
| | | |
| | | details.querySelector('.upload-meta > .hint')?.remove(); |
| | | if (grid) { |
| | | itemIds.forEach(itemId => { |
| | | const template = window.getTemplate('uploadItem'); |
| | | |
| | | grid.append(image); |
| | | if (!template) { |
| | | console.warn('uploadItem template not found'); |
| | | return; |
| | | } |
| | | |
| | | let input = template.querySelector('input[name="select-item"]'); |
| | | let label = template.querySelector('label[for="select-item"]'); |
| | | |
| | | template.dataset.id = itemId; |
| | | input.name = input.name + `-${itemId}`; |
| | | input.id = input.name; |
| | | label.htmlFor = input.name; |
| | | |
| | | const img = template.querySelector('img'); |
| | | template.querySelector('video')?.remove(); |
| | | const details = template.querySelector('details'); |
| | | |
| | | // Populate with data |
| | | if (imagesData[itemId]) { |
| | | const data = imagesData[itemId]; |
| | | if (img) { |
| | | img.src = data.medium || data.small || data.large || ''; |
| | | img.alt = data['image-alt-text'] || data.alt || ''; |
| | | } |
| | | |
| | | // Populate metadata fields |
| | | const titleInput = template.querySelector('[name="image-title"]'); |
| | | const altInput = template.querySelector('[name="image-alt-text"]'); |
| | | const captionInput = template.querySelector('[name="image-caption"]'); |
| | | |
| | | if (titleInput) titleInput.value = data['image-title'] || data.title || ''; |
| | | if (altInput) altInput.value = data['image-alt-text'] || data.alt || ''; |
| | | if (captionInput) captionInput.value = data['image-caption'] || data.caption || ''; |
| | | } else { |
| | | console.warn('No image data found for ID:', itemId, 'Available data:', Object.keys(imagesData)); |
| | | } |
| | | |
| | | // Remove hint if present |
| | | details?.querySelector('.upload-meta > .hint')?.remove(); |
| | | |
| | | grid.append(template); |
| | | }); |
| | | |
| | | if (imageIds.length > 0) { |
| | | if (uploadContainer) { |
| | | uploadContainer.hidden = true; |
| | | } |
| | | // Hide upload container if items exist |
| | | if (itemIds.length > 0 && uploadContainer) { |
| | | uploadContainer.hidden = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Populate gallery fields |
| | | */ |
| | | populateGalleryField(fieldWrapper, fieldName, fieldValue, imagesData = {}) { |
| | | if (fieldName === 'timeline') { |
| | | this.populateTimelineGallery(fieldWrapper, fieldName, fieldValue, imagesData); |
| | | } else { |
| | | this.populateImageField(fieldWrapper, fieldName, fieldValue, imagesData); |
| | | } |
| | | } |
| | | |
| | | populateTimelineGallery(fieldWrapper, fieldName, fieldValue, imagesData) |
| | | { |
| | | if (!fieldValue) { |
| | | populateTimelineGallery(fieldWrapper, fieldName, fieldValue, imagesData) { |
| | | console.log('populating Timeline Gallery'); |
| | | if (!fieldValue || typeof fieldValue !== 'object') { |
| | | return; |
| | | } |
| | | |
| | | const imageIds = Object.keys(fieldValue); |
| | | const imageIds = Object.values(fieldValue); |
| | | if (imageIds.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | // Update image display |
| | | // Update display |
| | | const grid = fieldWrapper.querySelector('.item-grid'); |
| | | const uploadContainer = fieldWrapper.querySelector('.file-upload-container'); |
| | | fieldWrapper.querySelector('.progress')?.remove(); |
| | | |
| | | if (grid) { |
| | | window.removeChildren(grid); |
| | | imageIds.forEach(imageId => { |
| | | let image = window.getTemplate('timelineItem'); |
| | | let img = image.querySelector('img'); |
| | | console.log(imageIds); |
| | | for (let data of Object.entries(fieldValue)) { |
| | | let imageId = data['post_thumbnail']; |
| | | const template = window.getTemplate('timelineItem'); |
| | | if (!template) return; |
| | | |
| | | image.querySelector('video')?.remove(); |
| | | image.querySelector('.select-item span')?.remove(); |
| | | let data = fieldValue[imageId]; |
| | | const img = template.querySelector('img'); |
| | | |
| | | let imgData = imagesData[imageId]; |
| | | // Remove unnecessary elements |
| | | template.querySelector('video')?.remove(); |
| | | template.querySelector('.select-item span')?.remove(); |
| | | |
| | | img.src = imgData.medium; |
| | | let input = template.querySelector('input[name="select-item"]'); |
| | | let label = template.querySelector('label[for="select-item"]'); |
| | | template.dataset.id = imageId; |
| | | template.dataset.postId = data.id; |
| | | input.name = input.name + `-${imageId}`; |
| | | input.id = input.name; |
| | | label.htmlFor = input.name; |
| | | |
| | | data = { ... data, ... imgData}; |
| | | const imgData = imagesData[imageId]; |
| | | |
| | | let fields = image.querySelectorAll('.field'); |
| | | // Set image source |
| | | if (img && imgData) { |
| | | img.src = imgData.medium || imgData.small || imgData.large || ''; |
| | | img.title = imgData['image-title']; |
| | | } |
| | | |
| | | // Merge data |
| | | const mergedData = { ...data, ...imgData }; |
| | | |
| | | // Populate fields |
| | | const fields = template.querySelectorAll('.field'); |
| | | fields.forEach(field => { |
| | | if (field.classList.contains('group')){ |
| | | if (field.classList.contains('group')) { |
| | | return; |
| | | } |
| | | let input = field.querySelector('input, textarea'); |
| | | |
| | | let label = field.querySelector('label'); |
| | | let name = input.name.replace('upload_data::',''); |
| | | const input = field.querySelector('input:not([type="file"]), textarea'); |
| | | if (!input) return; |
| | | |
| | | let value = data[name]; |
| | | const label = field.querySelector('label'); |
| | | const name = input.name.replace('upload_data::', ''); |
| | | const value = mergedData[name]; |
| | | |
| | | // Populate the field |
| | | this.populateField(field, name, value, imagesData); |
| | | |
| | | let id = data.id; |
| | | let newName = `[${id}]${name}`; |
| | | [ |
| | | input.name, |
| | | input.id, |
| | | label.htmlFor |
| | | ] = [ |
| | | newName, |
| | | newName, |
| | | newName, |
| | | ] |
| | | // Update field identifiers |
| | | const id = data.id; |
| | | const newName = `[${id}]${name}`; |
| | | input.name = newName; |
| | | input.id = newName; |
| | | if (label) label.htmlFor = newName; |
| | | }); |
| | | grid.append(image); |
| | | }); |
| | | |
| | | grid.append(template); |
| | | } |
| | | |
| | | // Hide upload container if items exist |
| | | if (imageIds.length > 0 && uploadContainer) { |
| | | uploadContainer.hidden = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Populate repeater fields |
| | | */ |
| | | populateRepeaterField(fieldWrapper, fieldName, fieldValue, options = {}) { |
| | | populateRepeaterField(fieldWrapper, fieldName, fieldValue) { |
| | | if (!fieldValue || !Array.isArray(fieldValue)) { |
| | | return; |
| | | } |