| | |
| | | } |
| | | |
| | | async init() { |
| | | this.initializeFields(); |
| | | // this.initializeFields(); |
| | | this.initListeners(); |
| | | |
| | | // Queue integration - handle completion/failure |
| | |
| | | /******************************************************************************* |
| | | * FIELD MANAGEMENT |
| | | *******************************************************************************/ |
| | | initializeFields() { |
| | | const fields = document.querySelectorAll(this.selectors.field.field); |
| | | fields.forEach(uploader => this.registerUploader(uploader)); |
| | | } |
| | | |
| | | scanFields(container) { |
| | | scanFields(container, autoUpload) { |
| | | console.log(autoUpload, 'autoUpload'); |
| | | const fields = container.querySelectorAll(this.selectors.field.field); |
| | | fields.forEach(uploader => this.registerUploader(uploader)); |
| | | fields.forEach(uploader => this.registerUploader(uploader, autoUpload)); |
| | | } |
| | | |
| | | registerUploader(uploader) { |
| | | registerUploader(uploader, autoUpload) { |
| | | const fieldId = this.determineFieldId(uploader); |
| | | const config = this.extractFieldConfig(uploader); |
| | | const config = this.extractFieldConfig(uploader, autoUpload); |
| | | const ui = this.buildFieldUI(uploader); |
| | | |
| | | console.log(config, 'registering with config'); |
| | | // Store field data with Sets for runtime |
| | | const fieldData = { |
| | | id: fieldId, |
| | |
| | | return fieldId; |
| | | } |
| | | |
| | | extractFieldConfig(fieldElement) { |
| | | extractFieldConfig(fieldElement, autoUpload) { |
| | | return { |
| | | autoUpload: autoUpload, |
| | | destination: fieldElement.dataset.destination || 'meta', |
| | | content: fieldElement.dataset.content || null, |
| | | mode: fieldElement.dataset.mode || 'direct', |
| | |
| | | const fieldWrapper = grid.closest('.field, .upload'); |
| | | if (!fieldWrapper) return; |
| | | |
| | | const movedItems = evt.items && evt.items.length > 0 ? evt.items : [evt.item]; |
| | | |
| | | // Get current order from DOM |
| | | let items = Array.from(grid.querySelectorAll('.item:not(.sortable-ghost):not(.sortable-clone)')) |
| | | .map(upload => upload.dataset.uploadId) |
| | |
| | | // Meta field changes |
| | | if (fieldId) { |
| | | const fieldData = this.getFieldData(fieldId); |
| | | if (!fieldData.config.autoUpload) { |
| | | return; |
| | | } |
| | | if (fieldData?.config.destination === 'post_group') { |
| | | this.handleGroupMetaChange(e.target); |
| | | } else { |
| | |
| | | this.refreshSortable(fieldId); |
| | | |
| | | // Queue for upload if in direct mode |
| | | if (fieldData.config.destination !== 'post_group') { |
| | | if (fieldData.config.autoUpload && fieldData.config.destination !== 'post_group') { |
| | | await this.queueUpload(fieldId); |
| | | this.maybeLockUploads(fieldId); |
| | | } |
| | |
| | | this.refreshSortable(fieldKey); |
| | | |
| | | // Queue for upload if needed |
| | | if (config.mode === 'direct' && config.destination !== 'post_group') { |
| | | console.log(config); |
| | | if (config.autoUpload && config.mode === 'direct' && config.destination !== 'post_group') { |
| | | await this.queueUpload(fieldKey); |
| | | } |
| | | } |
| | |
| | | // Can add custom logic here if needed |
| | | } |
| | | |
| | | getCurrentSelection(fieldId) { |
| | | let selected = []; |
| | | for (let [key, handler] of this.selectionHandlers) { |
| | | if ((fieldId === key || key.includes(fieldId)) && handler.selectedItems.size > 0) { |
| | | selected = selected.concat([...handler.selectedItems]); |
| | | } |
| | | } |
| | | return selected; |
| | | } |
| | | |
| | | /******************************************************************************* |
| | | * HELPER METHODS |
| | | *******************************************************************************/ |
| | |
| | | return progress[status] || 0; |
| | | } |
| | | |
| | | getModalType(fieldEl) { |
| | | if (!fieldEl?.element) return null; |
| | | if (fieldEl._cachedModalType !== undefined) { |
| | | return fieldEl._cachedModalType; |
| | | } |
| | | |
| | | const dialog = fieldEl.element.closest('dialog'); |
| | | if (!dialog) { |
| | | fieldEl._cachedModalType = null; |
| | | return null; |
| | | } |
| | | |
| | | let modalType = null; |
| | | if (dialog.classList.contains('edit')) modalType = 'edit'; |
| | | else if (dialog.classList.contains('create')) modalType = 'create'; |
| | | else if (dialog.classList.contains('bulkEdit')) modalType = 'bulkEdit'; |
| | | else modalType = dialog.className; |
| | | |
| | | fieldEl._cachedModalType = modalType; |
| | | return modalType; |
| | | } |
| | | |
| | | createUploadElement(upload, draggable = false) { |
| | | let image = window.getTemplate('uploadItem'); |
| | |
| | | * PERSISTENCE |
| | | *******************************************************************************/ |
| | | |
| | | /** |
| | | * Normalize field data loaded from IndexedDB |
| | | * Converts Arrays back to Sets, handles missing properties |
| | | */ |
| | | normalizeFieldData(fieldData) { |
| | | if (!fieldData) return null; |
| | | |
| | | // Convert uploads array back to Set |
| | | if (Array.isArray(fieldData.uploads)) { |
| | | fieldData.uploads = new Set(fieldData.uploads); |
| | | } else if (!fieldData.uploads) { |
| | | fieldData.uploads = new Set(); |
| | | } |
| | | |
| | | // Convert groups array, ensure proper structure |
| | | if (!Array.isArray(fieldData.groups)) { |
| | | fieldData.groups = []; |
| | | } |
| | | |
| | | // Ensure each group has uploads array |
| | | fieldData.groups = fieldData.groups.map(group => ({ |
| | | ...group, |
| | | uploads: Array.isArray(group.uploads) ? group.uploads : [] |
| | | })); |
| | | |
| | | return fieldData; |
| | | } |
| | | |
| | | schedulePersistance(fieldId) { |
| | | const key = `persist_${fieldId}`; |
| | | window.debouncer.schedule( |
| | |
| | | } |
| | | |
| | | /******************************************************************************* |
| | | HELPER to GET UPLOADED FILES |
| | | *******************************************************************************/ |
| | | /** |
| | | * Get all files for a form (searches all upload fields within form) |
| | | */ |
| | | async getFilesForForm(formElement) { |
| | | const uploadFields = formElement.querySelectorAll('[data-upload-field]'); |
| | | const allFiles = []; |
| | | |
| | | for (const field of uploadFields) { |
| | | const fieldId = this.determineFieldId(field); |
| | | const files = await this.getFilesForField(fieldId); |
| | | allFiles.push(...files); |
| | | } |
| | | |
| | | return allFiles; |
| | | } |
| | | |
| | | /** |
| | | * Get all files for a specific field |
| | | */ |
| | | async getFilesForField(fieldId) { |
| | | const fieldData = this.getFieldData(fieldId); |
| | | if (!fieldData?.uploads) return []; |
| | | |
| | | const files = []; |
| | | const uploadsArray = fieldData.uploads instanceof Set |
| | | ? Array.from(fieldData.uploads) |
| | | : fieldData.uploads; |
| | | |
| | | for (const uploadId of uploadsArray) { |
| | | const upload = this.uploadStore.get(uploadId); |
| | | if (!upload) continue; |
| | | |
| | | // Get the actual File object from blob data |
| | | const file = await this.getBlobData(uploadId); |
| | | if (file) { |
| | | files.push({ |
| | | file: file, |
| | | uploadId: uploadId, |
| | | fieldName: fieldData.config.name, |
| | | meta: upload.meta || {} |
| | | }); |
| | | } |
| | | } |
| | | |
| | | return files; |
| | | } |
| | | |
| | | /******************************************************************************* |
| | | * RECOVERY & RESTORATION |
| | | *******************************************************************************/ |
| | | |
| | |
| | | }); |
| | | if (pendingFields.length === 0) return; |
| | | |
| | | this.showRecoveryNotification(pendingFields); |
| | | await this.showRecoveryNotification(pendingFields); |
| | | } |
| | | |
| | | async showRecoveryNotification(pendingFields) { |