| | |
| | | populate (form, data = {}) |
| | | { |
| | | this.data = data; |
| | | this.mergeRootData(); |
| | | this.form = form; |
| | | if (!this.formHelper) { |
| | | this.formHelper = window.jvbForm; |
| | |
| | | } |
| | | } |
| | | |
| | | mergeRootData(){ |
| | | let check = ['status','date','modified']; |
| | | check.forEach(ch =>{ |
| | | this.data.fields[`post_${ch}`] = this.data[ch]; |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * |
| | | * @param {HTMLElement} field |
| | |
| | | const handlers = { |
| | | 'repeater': this.populateRepeater.bind(this), |
| | | 'tag-list': this.populateTagList.bind(this), |
| | | 'group': this.populateGroup.bind(this), |
| | | 'location': this.populateLocation.bind(this), |
| | | 'selector': this.populateTaxonomy.bind(this), |
| | | 'user': this.populateUser.bind(this), |
| | | 'upload': this.populateUpload.bind(this), |
| | | 'gallery': this.populateUpload.bind(this), |
| | | 'image': this.populateUpload.bind(this), |
| | | 'set': this.populateMultiValue.bind(this), |
| | | 'checkbox': this.populateMultiValue.bind(this), |
| | | 'select': this.populateSingleValue.bind(this), |
| | | 'radio': this.populateSingleValue.bind(this), |
| | | 'true-false': this.populateBoolean.bind(this), |
| | | 'toggle-text': this.populateBoolean.bind(this), |
| | | 'date': this.populateDate.bind(this), |
| | | 'time': this.populateDate.bind(this), |
| | | 'datetime': this.populateDate.bind(this), |
| | | 'number': this.populateNumber.bind(this), |
| | | 'textarea': this.populateTextarea.bind(this) |
| | | 'textarea': this.populateTextarea.bind(this), |
| | | 'quantity': this.populateNumber.bind(this), |
| | | }; |
| | | |
| | | if (Object.hasOwn(handlers, type)) { |
| | |
| | | if (!value || !Array.isArray(value)) return; |
| | | |
| | | const container = field.querySelector('.repeater-items'); |
| | | let template = field.querySelector('template')?.className??false; |
| | | let template = field.querySelector('template')?.className ?? false; |
| | | if (!container || !template) return; |
| | | |
| | | window.removeChildren(container); |
| | | |
| | | value.forEach((data, index) => { |
| | | data.index = index; |
| | | const row = this.templates.create(template, data); |
| | | let fields = row.querySelectorAll('.field'); |
| | | this.populate(fields, data); |
| | | const templateData = { ...data, index, repeater: field }; |
| | | |
| | | const row = this.templates.create(template, templateData); |
| | | if (!row) return; |
| | | |
| | | container.append(row); |
| | | |
| | | const formConfig = this.formHelper.getForm(row); |
| | | if (formConfig) { |
| | | this.formHelper.initializeFields(row, formConfig); |
| | | } |
| | | |
| | | for (let [fieldName, fieldValue] of Object.entries(data)) { |
| | | let subField = row.querySelector(`[data-field="${fieldName}"]`); |
| | | if (subField) { |
| | | this.populateField(subField, fieldName, fieldValue); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | populateTagList(field, name, value) { |
| | | if (!value || !Array.isArray(value)) return; |
| | | |
| | | const container = field.querySelector('.tag-items'); |
| | | let template = field.querySelector('template')?.className??false; |
| | | let template = field.querySelector('template')?.className ?? false; |
| | | if (!container || !template) return; |
| | | |
| | | window.removeChildren(container); |
| | | |
| | | value.forEach((data, index) => { |
| | | data.index = index; |
| | | const row = this.templates.create(template, data); |
| | | let fields = row.querySelectorAll('.field'); |
| | | this.populate(fields, data); |
| | | const row = this.templates.create(template, { |
| | | label: this.getTagLabel(data, field.dataset.tagFormat ?? 'first_field'), |
| | | fieldName: name, |
| | | ...data |
| | | }); |
| | | if (!row) return; |
| | | |
| | | // Set hidden input values directly |
| | | row.querySelectorAll('input[type="hidden"]').forEach(input => { |
| | | const key = input.dataset.field; |
| | | if (key && data[key] !== undefined) { |
| | | input.value = data[key]; |
| | | } |
| | | }); |
| | | |
| | | container.append(row); |
| | | }); |
| | | } |
| | | /** |
| | | * Build tag label from data - mirrors addTagListItem logic |
| | | */ |
| | | getTagLabel(data, format) { |
| | | const values = Object.values(data).filter(v => !this.isEmptyValue(v)); |
| | | switch (format) { |
| | | case 'first_field': |
| | | return values[0] ?? 'New Item'; |
| | | case 'all_fields': |
| | | return values.join(', ') || 'New Item'; |
| | | default: |
| | | if (format.includes('{')) { |
| | | let label = format; |
| | | for (const [key, value] of Object.entries(data)) { |
| | | label = label.replace(`{${key}}`, value); |
| | | } |
| | | return label; |
| | | } |
| | | return data[format] ?? values[0] ?? 'New Item'; |
| | | } |
| | | } |
| | | populateGroup(field, name, value) { |
| | | if (!value || typeof value !== 'object') return; |
| | | |
| | | for (let [subName, subValue] of Object.entries(value)) { |
| | | let subField = field.querySelector(`[data-field="${subName}"]`); |
| | | if (subField) { |
| | | this.populateField(subField, subName, subValue); |
| | | } |
| | | } |
| | | } |
| | | populateLocation(field, name, value) { |
| | | const subFields = ['address', 'lat', 'lng', 'street', 'city', 'province', 'postal_code', 'country']; |
| | | subFields.forEach(subField => { |
| | |
| | | } |
| | | } |
| | | populateUser(field, name, value) { |
| | | this.populateTaxonomyField(field, name, value); |
| | | this.populateTaxonomy(field, name, value); |
| | | } |
| | | populateUpload(field, name, value) { |
| | | if (name === 'timeline' || field.dataset.subtype && field.dataset.subtype === 'timeline') { |
| | | if (field.dataset.subtype && field.dataset.subtype === 'timeline') { |
| | | this.populateTimelineGallery(field,name,value); |
| | | return; |
| | | } |
| | |
| | | } |
| | | |
| | | const grid = field.querySelector('.item-grid'); |
| | | let uploadContainer = field.querySelector('.file-upload-container'); |
| | | uploadContainer.hidden = ids.length > 0; |
| | | |
| | | field.querySelector('.progress')?.remove(); |
| | | if (grid) { |
| | | window.removeChildren(grid); |
| | | ids.forEach(id => { |
| | | let data = this.data.images[id]??{}; |
| | | data.field = { |
| | | config: { |
| | | showMeta: true |
| | | } |
| | | }; |
| | | data.id = id; |
| | | grid.append(this.templates.create('uploadItem', data)); |
| | | }); |
| | |
| | | for (const m of meta) { |
| | | const input = imageDataField.querySelector(`[data-field="${m}"] input, [data-field="${m}"] textarea`); |
| | | if (input && data[m]!=='') { |
| | | input.value = data[m]; |
| | | input.value = window.decodeHTMLEntities(data[m]); |
| | | } |
| | | } |
| | | } |
| | |
| | | if (!value || !Array.isArray(value) || value.length === 0) return; |
| | | |
| | | let grid = field.querySelector('.item-grid'); |
| | | let uploadContainer = field.querySelector('.file-upload-container'); |
| | | uploadContainer.hidden = value.length > 0; |
| | | |
| | | if (grid) { |
| | | window.removeChildren(grid); |
| | | |
| | |
| | | } |
| | | return; |
| | | } |
| | | field.querySelectorAll(`[type="checkbox"][name=${name}]`).forEach(checkbox => { |
| | | field.querySelectorAll(`input[type="checkbox"][name="${name}[]"], input[type="checkbox"][name="${name}"]`).forEach(checkbox => { |
| | | checkbox.checked = value.includes(checkbox.value); |
| | | }); |
| | | |
| | |
| | | populateSingleValue(field, name, value) { |
| | | value = String(value || ''); |
| | | |
| | | // Try select first |
| | | let select = field.querySelector(`select[name="${name}"]`); |
| | | if (select) { |
| | | select.value = value; |
| | | return; |
| | | } |
| | | let input = field.querySelector(`[name="${name}"][value="${value}"]`); |
| | | |
| | | let input = field.querySelector(`input[type="radio"][value="${value}"], input[type="checkbox"][value="${value}"]`) |
| | | || field.querySelector(`[name="${name}"][value="${value}"]`); |
| | | if (input) { |
| | | input.checked = true; |
| | | } |
| | |
| | | } |
| | | } |
| | | populateTextarea(field, name, value) { |
| | | let textarea = field.querySelector('textarea'); |
| | | if (!textarea.dataset.editor) { |
| | | this.populateText(field, name, value) |
| | | return; |
| | | let textarea = field.querySelector('textarea[data-editor], textarea'); |
| | | this.populateText(field, name, value); |
| | | |
| | | if (textarea?.dataset.editor) { |
| | | const editor = field.querySelector('.ql-editor'); |
| | | if (editor) { |
| | | editor.innerHTML = value; |
| | | } else { |
| | | textarea.dispatchEvent(new Event('change', { bubbles: true })); |
| | | } |
| | | } |
| | | textarea.value = String(value || ''); |
| | | textarea.dispatchEvent(new Event('change', {bubbles: true})); |
| | | } |
| | | populateText(field, name, value) { |
| | | let input = field.querySelector(`[name="${name}"], input, textarea`); |
| | | if (input && input.type !== 'file') { |
| | | input.value = String(value || ''); |
| | | let input = field.querySelector(`[name="${name}"]`) |
| | | || field.querySelector('textarea[data-editor]') |
| | | || field.querySelector('input:not([type="hidden"]):not([type="file"]), textarea, select'); |
| | | if (input) { |
| | | input.value = window.decodeHTMLEntities(value??''); |
| | | } |
| | | } |
| | | /******************************************************************** |
| | |
| | | video: 'video', |
| | | file: '.select-item span', |
| | | img: 'img', |
| | | details: 'details[data-field]', |
| | | imgAlt: '[name="image-alt-text"]', |
| | | imgTitle: '[name="image-title"]', |
| | | imgDesc: '[name="image-caption"]', |
| | | details: '[data-field="image_data"] details', |
| | | imgAlt: '[data-field="image-alt-text"]', |
| | | imgTitle: '[data-field="image-title"]', |
| | | imgDesc: '[data-field="image-caption"]', |
| | | }, |
| | | manyRefs: { |
| | | fields: '.field', |
| | |
| | | let imgData = p.data.images[data['post_thumbnail']]??false; |
| | | if (refs.img && imgData) { |
| | | refs.img.src = imgData.medium || imgData.small || imgData.large || ''; |
| | | refs.img.title = imgData['image-title']??''; |
| | | refs.img.title = imgData.large.split("/").pop()??''; |
| | | refs.img.alt = imgData['image-alt-text']??''; |
| | | } |
| | | |
| | | |
| | | if (refs.details) { |
| | | let imgData = p.data.images[data.post_thumbnail]; |
| | | |
| | | refs.details.setAttribute('data-ignore', ''); |
| | | refs.details.dataset.attachmentId = data.post_thumbnail; |
| | | if (Object.hasOwn(imgData, 'image-alt-text') && refs.alt) { |
| | | refs.alt.value = imgData['image-alt-text']; |
| | | |
| | | let imgAlt = refs.imgAlt.querySelector('input'); |
| | | let imgTitle = refs.imgTitle.querySelector('input'); |
| | | let imgDesc = refs.imgDesc.querySelector('textarea'); |
| | | window.prefixInput(imgAlt, `[${data.post_thumbnail}]`, refs.imgAlt, false, true); |
| | | window.prefixInput(imgTitle, `[${data.post_thumbnail}]`, refs.imgTitle, false, true); |
| | | window.prefixInput(imgDesc, `[${data.post_thumbnail}]`, refs.imgDesc, false, true); |
| | | |
| | | if (Object.hasOwn(imgData, 'image-alt-text') && refs.imgAlt) { |
| | | imgAlt.value = window.decodeHTMLEntities(imgData['image-alt-text']); |
| | | } |
| | | if ((Object.hasOwn(imgData, 'image-title') || Object.hasOwn(data, 'file')) && refs.title) { |
| | | refs.title.value = imgData['image-title']||data.file.name; |
| | | if ((Object.hasOwn(imgData, 'image-title') || Object.hasOwn(data, 'file')) && refs.imgTitle) { |
| | | imgTitle.value = window.decodeHTMLEntities(imgData['image-title']||data.file.name); |
| | | } |
| | | if (Object.hasOwn(imgData, 'image-caption') && refs.description) { |
| | | refs.description.value = imgData['image-caption']; |
| | | if (Object.hasOwn(imgData, 'image-caption') && refs.imgDesc) { |
| | | imgDesc.value = window.decodeHTMLEntities(imgData['image-caption']); |
| | | } |
| | | } |
| | | |
| | | if (manyRefs.fields) { |
| | | for (let field of manyRefs.fields) { |
| | | if (field.closest('[data-ignore]')) continue; |
| | | if (field.dataset.fieldType === 'group') continue; |
| | | if (field.dataset.field === 'post_thumbnail') { |
| | | field.remove(); |
| | | continue; |
| | | } |
| | | let name = field.dataset.field; |
| | | let value = data[name]??''; |
| | | |
| | | const input = field.querySelector('input:not([type="file"]), textarea, select'); |
| | | if (input) window.prefixInput(input, `[${data.id}]`, field, false, true); |
| | | |
| | | let value = data[name] ?? ''; |
| | | if (!p.isEmptyValue(value)) { |
| | | p.populateField(field, name, value); |
| | | } |
| | | const input = field.querySelector('input:not([type="file"])'); |
| | | if (!input) continue; |
| | | window.prefixInput(input, `[${data.id}]`, field); |
| | | } |
| | | |
| | | } |