| | |
| | | this.selectionHandlers = new Map(); |
| | | this.sortables = new Map(); |
| | | |
| | | this.changes = new Map(); |
| | | |
| | | this.previewUrls = new Set(); |
| | | this.initElements(); |
| | | this.initListeners(); |
| | |
| | | video: 'video', |
| | | file: 'label > span', |
| | | details: 'details', |
| | | alt: '[name="image-alt-text"]', |
| | | title: '[name="image-title"]', |
| | | description: '[name="image-caption"]', |
| | | }, |
| | | manyRefs: { |
| | | inputs: 'input', |
| | | inputs: 'input, select, textarea', |
| | | }, |
| | | setup({el, refs, manyRefs, data}) { |
| | | const isNewUpload = Object.hasOwn(data, 'file'); |
| | |
| | | break; |
| | | } |
| | | if (refs.details) { |
| | | refs.details.append(T.create('uploadMeta')); |
| | | if (Object.hasOwn(data.field.config, 'showMeta') && !data.field.config.showMeta) { |
| | | refs.details.remove(); |
| | | } else { |
| | | if(Object.hasOwn(data, 'id')) { |
| | | refs.details.dataset.attachmentId = data.id; |
| | | } else if (Object.hasOwn(data, 'uploadId')) { |
| | | refs.details.dataset.uploadId = data.uploadId; |
| | | } |
| | | refs.details.setAttribute('data-ignore', ''); |
| | | |
| | | |
| | | if (mimeType !== 'image' && refs.alt) { |
| | | refs.alt.closest('.field')?.remove(); |
| | | } else if (Object.hasOwn(data, 'image-alt-text') && refs.alt) { |
| | | refs.alt.value = data['image-alt-text']; |
| | | } |
| | | if ((Object.hasOwn(data, 'title') || Object.hasOwn(data, 'file')) && refs.title) { |
| | | refs.title.value = data.title||data.file.name; |
| | | } |
| | | if (Object.hasOwn(data, 'image-caption') && refs.description) { |
| | | refs.description.value = data['image-caption']; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | if (manyRefs.inputs) { |
| | | for (let input of manyRefs.inputs) { |
| | | window.prefixInput(input, `${data.uploadId}-`); |
| | | window.prefixInput(input, `${data.id??data.uploadId}-`); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | |
| | | T.define('uploadMeta', { |
| | | refs: { |
| | | alt: '[name="alt_text"]', |
| | | title: '[name="image-title"]', |
| | | description: '[name="image-caption"]', |
| | | }, |
| | | setup({el, refs, manyRefs, data}) { |
| | | if (Object.hasOwn(data, 'alt') && refs.alt) { |
| | | refs.alt.value = data.alt; |
| | | } |
| | | if (Object.hasOwn(data, 'title') && refs.title) { |
| | | refs.title.value = data.title; |
| | | } |
| | | if (Object.hasOwn(data, 'description') && refs.description) { |
| | | refs.description.value = data.description; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | T.define('imageGroup', { |
| | | refs: { |
| | | selectAll: '[data-select-all]', |
| | |
| | | grid: '.item-grid' |
| | | }, |
| | | async setup({el, refs, manyRefs, data}) { |
| | | let fieldId = images.registerField(el, false, `recovery_${data.index}`); |
| | | let fieldId = images.registerField(el, false, false, `recovery_${data.index}`); |
| | | if (data.isCurrent) { |
| | | el.open = true; |
| | | |
| | |
| | | }; |
| | | |
| | | const upload = { ...defaults, ...data }; |
| | | |
| | | Object.preventExtensions(upload); |
| | | await this.stores.uploads.save(upload); |
| | | return upload; |
| | |
| | | } |
| | | } |
| | | handleChange(e) { |
| | | |
| | | let fieldId = this.getFieldIdFromElement(e.target); |
| | | if (!fieldId) return; |
| | | if (!fieldId) { |
| | | let isMeta = e.target.closest('[data-upload-id], [data-attachment-id]'); |
| | | if (isMeta) { |
| | | this.queueUploadMeta(e); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | if (e.target.matches(this.selectors.fields.input)) { |
| | | const files = Array.from(e.target.files); |
| | |
| | | } |
| | | |
| | | let field = this.fields.get(fieldId); |
| | | if (!field || !field.config.autoUpload) return; |
| | | |
| | | if (field.config.destination === 'post_group') { |
| | | this.handleGroupMetaChange(e.target); |
| | | } else { |
| | | this.queueUploadMeta(e).then(()=>{}); |
| | | this.queueUploadMeta(e); |
| | | } |
| | | } |
| | | handleGroupMetaChange(input) { |
| | |
| | | return { uploadMap, files }; |
| | | } |
| | | |
| | | async queueUploadMeta(e) { |
| | | const uploadId = e.target.closest(this.selectors.items.item)?.dataset.uploadId; |
| | | const upload = this.stores.uploads.get(uploadId); |
| | | if (!uploadId || !upload) return; |
| | | queueUploadMeta(e) { |
| | | let attachmentId = e.target.closest('[data-attachment-id]')?.dataset.attachmentId; |
| | | let isUpload = false; |
| | | if (!attachmentId) { |
| | | attachmentId = e.target.closest('[data-upload-id]')?.dataset.uploadId; |
| | | isUpload = true; |
| | | if (!attachmentId) return; |
| | | |
| | | const field = this.fields.get(upload.field); |
| | | if (!field) return; |
| | | |
| | | let data = {}; |
| | | data[e.target.name] = e.target.value; |
| | | } |
| | | |
| | | upload.fields = { ...upload.fields, ...data }; |
| | | await this.setUpload(upload.id, upload); |
| | | if (!this.changes.has(attachmentId)) { |
| | | let object = {}; |
| | | if (isUpload) { |
| | | object['uploadId'] = attachmentId; |
| | | } else { |
| | | object['attachmentId'] = attachmentId; |
| | | } |
| | | this.changes.set(attachmentId, object); |
| | | } |
| | | |
| | | let queueData = {}; |
| | | queueData[upload.attachmentId ?? upload.id] = upload.fields; |
| | | return await this.sendToQueue('uploads/meta', queueData, 'Uploading Meta', '', true); |
| | | let field = e.target.closest('[data-field]'); |
| | | let name = field.dataset.field; |
| | | |
| | | this.changes.get(attachmentId)[name] = e.target.value; |
| | | |
| | | this.scheduleSave(); |
| | | } |
| | | scheduleSave() { |
| | | window.debouncer.schedule( |
| | | `upload-meta`, |
| | | async () => { |
| | | if (this.changes.size > 0) { |
| | | let items = {}; |
| | | for (let [id, meta] of this.changes.entries()) { |
| | | console.log(id, meta); |
| | | items[id] = meta; |
| | | } |
| | | let data = { |
| | | user: window.auth.getUser(), |
| | | items: items |
| | | }; |
| | | await this.sendToQueue('uploads/meta', data, 'Uploading Meta', 'Uploading Meta', true); |
| | | this.changes.clear(); |
| | | } |
| | | }, |
| | | 2000 |
| | | ); |
| | | } |
| | | |
| | | /********************************************************************* |
| | | FIELD LOGIC |
| | | *********************************************************************/ |
| | | scanFields(container, autoUpload = true) { |
| | | scanFields(container, autoUpload = true, imageMeta = true) { |
| | | const fields = container.querySelectorAll(this.selectors.fields.field); |
| | | fields.forEach(uploader => this.registerField(uploader, autoUpload)); |
| | | fields.forEach(uploader => this.registerField(uploader, autoUpload, imageMeta)); |
| | | } |
| | | |
| | | registerField(element, autoUpload = true, id = null) { |
| | | registerField(element, autoUpload = true, imageMeta = true, id = null) { |
| | | const data = { |
| | | element: element, |
| | | id: (id) ? id : this.determineFieldId(element), |
| | | config: this.extractFieldConfig(element, autoUpload), |
| | | config: this.extractFieldConfig(element, autoUpload, imageMeta), |
| | | uploads: new Set(), |
| | | operationId: null, |
| | | groups: [], |
| | |
| | | return data.id; |
| | | } |
| | | |
| | | extractFieldConfig(fieldElement, autoUpload) { |
| | | extractFieldConfig(fieldElement, autoUpload, imageMeta) { |
| | | return { |
| | | autoUpload: autoUpload, |
| | | showMeta: imageMeta, |
| | | destination: fieldElement.dataset.destination || 'meta', //TODO: why do we need this? |
| | | content: this.extractFieldContent(fieldElement), |
| | | mode: fieldElement.dataset.mode || 'direct', |
| | |
| | | id: uploadId, |
| | | field: fieldId, |
| | | status: 'local_processing', |
| | | blob: null, |
| | | // blob: null, |
| | | fields: { |
| | | originalName: file.name, |
| | | originalSize: file.size, |