| | |
| | | this.initStores(); |
| | | this.initWorker(); |
| | | |
| | | |
| | | //Maps for DOM references |
| | | this.fields = new Map(); |
| | | this.uploads = new Map(); |
| | |
| | | |
| | | if (manyRefs.inputs) { |
| | | for (let input of manyRefs.inputs) { |
| | | window.prefixInput(input, `${data.id??data.uploadId}-`); |
| | | let wrapper = input.closest('[data-field]')??el; |
| | | window.prefixInput(input, `${data.id??data.uploadId}-`, wrapper); |
| | | } |
| | | } |
| | | } |
| | |
| | | setup({el, refs, manyRefs, data}) { |
| | | el.dataset.groupId = data.groupId; |
| | | if (refs.selectAll) { |
| | | window.prefixInput(refs.selectAll, `select-all-${data.groupId}`, true); |
| | | let wrapper = refs.selectAll.closest('.field'); |
| | | window.prefixInput(refs.selectAll, `select-all-${data.groupId}`, wrapper,true); |
| | | } |
| | | let fields = T.create('groupMetadata', {groupId: data.groupId}); |
| | | if (fields) { |
| | |
| | | setup({el, refs, manyRefs, data}) { |
| | | if (refs.inputs) { |
| | | refs.inputs.forEach(input => { |
| | | window.prefixInput(input, `${data.groupId}-`); |
| | | let wrapper = input.closest('[data-field]'); |
| | | window.prefixInput(input, `${data.groupId}-`, wrapper); |
| | | }); |
| | | } |
| | | } |
| | |
| | | |
| | | // Capture values immediately (before debouncer) |
| | | const inputName = input.name; |
| | | if (!inputName) return; |
| | | const inputValue = input.value; |
| | | |
| | | // Extract the field name from the input name |
| | |
| | | await this.setBulkUpload(uploads, 'status', 'uploading'); |
| | | await this.setBulkGroup(fieldId, 'operationId', operationId); |
| | | this.fields.set(field.id, field); |
| | | |
| | | |
| | | this.notify('sent-to-queue', { |
| | | field: field, |
| | | operation: operationId, |
| | | }); |
| | | } else { |
| | | await this.setBulkUpload(uploads, 'status', 'failed'); |
| | | } |
| | | this.notify('sent-to-queue', fieldId); |
| | | return operationId; |
| | | } |
| | | |
| | |
| | | let uploadMap = []; |
| | | let files = []; |
| | | |
| | | for (const group of groups) { |
| | | const validGroups = groups.filter(group => { |
| | | const groupUploads = this.getGroupUploadsInOrder(group); |
| | | return groupUploads.length > 0 && groupUploads.some(u => this.formatFile(u)); |
| | | }); |
| | | |
| | | for (const group of validGroups) { |
| | | const groupElement = this.groups.get(group.id)?.element; |
| | | const fields = this.collectGroupFieldsFromDOM(groupElement, group.id); |
| | | |
| | |
| | | fields: fields |
| | | }; |
| | | |
| | | // Use helper to get uploads in stored order |
| | | const groupUploads = this.getGroupUploadsInOrder(group); |
| | | |
| | | for (const upload of groupUploads) { |
| | |
| | | uploadMap.push(upload.id); |
| | | } |
| | | } |
| | | posts.push(post); |
| | | |
| | | if (post.images.length > 0) { |
| | | posts.push(post); |
| | | } |
| | | } |
| | | |
| | | // Handle remaining uploads not in any group |
| | |
| | | post.images.push(imageData); |
| | | uploadMap.push(upload.id); |
| | | } |
| | | posts.push(post); |
| | | |
| | | if (post.images.length > 0) { |
| | | posts.push(post); |
| | | } |
| | | } |
| | | |
| | | return {posts, uploadMap, files}; |
| | |
| | | |
| | | const processNext = async () => { |
| | | while (queue.length > 0) { |
| | | const file = queue.shift(); |
| | | results.push(await this.processImage(file, maxWidth, maxHeight)); |
| | | const entry = queue.shift(); |
| | | const blob = await this.processImage(entry.file, maxWidth, maxHeight); |
| | | results.push({ uploadId: entry.uploadId, blob: blob }); |
| | | } |
| | | }; |
| | | |
| | |
| | | const otherEntries = uploadEntries.filter(e => !e.file.type.startsWith('image/')); |
| | | |
| | | // Process images in batches |
| | | const processedBlobs = await this.processImages( |
| | | imageEntries.map(e => e.file) |
| | | const processedImages = await this.processImages( |
| | | imageEntries.map(e => ({ file: e.file, uploadId: e.uploadId })) |
| | | ); |
| | | |
| | | // Update image uploads with processed blobs |
| | | for (let i = 0; i < imageEntries.length; i++) { |
| | | const { uploadId, upload } = imageEntries[i]; |
| | | upload.blob = processedBlobs[i]; |
| | | upload.fields.size = processedBlobs[i].size; |
| | | upload.status = 'queued'; |
| | | await this.setUpload(uploadId, upload); |
| | | processed++; |
| | | this.updateFieldProgress(fieldId, processed, totalFiles, 'Processing files...'); |
| | | for (const { uploadId, blob } of processedImages) { |
| | | const entry = imageEntries.find(e => e.uploadId === uploadId); |
| | | if (entry) { |
| | | entry.upload.blob = blob; |
| | | entry.upload.fields.size = blob.size; |
| | | entry.upload.status = 'queued'; |
| | | await this.setUpload(uploadId, entry.upload); |
| | | processed++; |
| | | this.updateFieldProgress(fieldId, processed, totalFiles, 'Processing files...'); |
| | | } |
| | | } |
| | | |
| | | // Handle non-image files (no processing needed) |
| | |
| | | *************************************************************/ |
| | | async checkRecovery() { |
| | | const pendingUploads = this.stores.uploads.filterByIndex({status: ['local_processing', 'queued', 'uploading']}); |
| | | const allGroups = Array.from(this.stores.groups.data.values()); |
| | | for (const group of allGroups) { |
| | | const hasUploads = this.stores.uploads.filterByIndex({group: group.id}).length > 0; |
| | | if (!hasUploads) { |
| | | await this.stores.groups.delete(group.id); |
| | | } |
| | | } |
| | | if (pendingUploads.length === 0) return; |
| | | |
| | | // Group by source page |
| | |
| | | avoidImplicitDeselect: true, |
| | | group: { name: fieldId, pull: true, put: true }, |
| | | dragClass: 'dragging', |
| | | ignore: '.empty-group', |
| | | |
| | | onStart: (evt) => { |
| | | // Get the dragged item's ID |
| | |
| | | |
| | | emptyZone.addEventListener('dragover', (e) => { |
| | | e.preventDefault(); |
| | | e.stopPropagation(); |
| | | e.dataTransfer.dropEffect = 'move'; |
| | | emptyZone.classList.add('drag-over'); |
| | | }); |
| | |
| | | |
| | | emptyZone.addEventListener('drop', async (e) => { |
| | | e.preventDefault(); |
| | | e.stopPropagation(); |
| | | emptyZone.classList.remove('drag-over'); |
| | | |
| | | // Get selected items from our tracking |