| | |
| | | |
| | | const baseSetup = (el, refs, data) => { |
| | | el.dataset.itemId = data.id; |
| | | |
| | | window.prefixInput(refs.checkbox, `select-${data.id}`, true); |
| | | let wrapper = refs.checkbox.closest('.preview'); |
| | | window.prefixInput(refs.checkbox, `select-${data.id}`, wrapper, true); |
| | | refs.checkbox.value = data.id; |
| | | refs.checkbox.checked = crud.selected.has(parseInt(data.id)); |
| | | if (refs.selectLabel) refs.selectLabel.htmlFor = `select-${data.id}`; |
| | |
| | | baseSetup(el, refs, data); |
| | | |
| | | manyRefs?.inputs?.forEach(el => { |
| | | window.prefixInput(el, `${data.id}-`); |
| | | let wrapper = el.closest('[data-field]'); |
| | | window.prefixInput(el, `${data.id}-`, wrapper); |
| | | }); |
| | | |
| | | manyRefs?.status?.forEach(el => { |
| | |
| | | if (crud.isTimeline) { |
| | | if (refs.sharedRow) { |
| | | refs.sharedRow.querySelectorAll('input,select,textarea').forEach(input => { |
| | | window.prefixInput(input, `${data.id}-`); |
| | | let wrapper = input.closest('[data-field]'); |
| | | window.prefixInput(input, `${data.id}-`, wrapper); |
| | | }); |
| | | |
| | | crud.populate.populate(refs.sharedRow, data); |
| | |
| | | point.dataset.itemId = timeline.id; |
| | | |
| | | point.querySelectorAll('input,select,textarea').forEach(input => { |
| | | window.prefixInput(input, `${timeline.id}-`); |
| | | let wrapper = input.closest('[data-field]'); |
| | | window.prefixInput(input, `${timeline.id}-`, wrapper); |
| | | }); |
| | | |
| | | crud.populate.populate(point, { |
| | |
| | | if (crud.ui.table.form?.dataset.edit !== undefined) { |
| | | // Non-timeline: prefix all inputs normally |
| | | manyRefs?.inputs?.forEach(input => { |
| | | window.prefixInput(input, `${data.id}-`); |
| | | let wrapper = input.closest('[data-field]'); |
| | | window.prefixInput(input, `${data.id}-`, wrapper); |
| | | }); |
| | | |
| | | manyRefs?.status?.forEach(el => { |
| | |
| | | if (name === 'date') { |
| | | this.handleCustomDateSelection() |
| | | } |
| | | if (['edit','bulkEdit','create'].includes(name)) { |
| | | //handle escapes (not form submits) |
| | | if (window.debouncer.timeouts.has(`save-${this.content}`)) { |
| | | this.scheduleSave(0); |
| | | } |
| | | } |
| | | break; |
| | | case 'modal-open': |
| | | |
| | |
| | | } |
| | | if (event === 'operation-status' |
| | | && data.status === 'completed' |
| | | && data.endpoint === 'content' |
| | | && Object.keys(data.data?.posts??{}).length > 0) { |
| | | && data.endpoint === 'uploads/groups') { |
| | | |
| | | console.log('Cleared local cache. Refresh to see changes'); |
| | | this.store.clearCache(); |
| | | let ids = Object.keys(data.data.posts); |
| | | let storedChanges = this.changesStore.getMany(ids); |
| | | } |
| | | if (event === 'operation-status' |
| | | && data.status === 'completed' |
| | | && data.type === 'content_update') { |
| | | console.log('Cleared local cache. Refresh to see changes'); |
| | | this.store.clearCache(); |
| | | |
| | | this.changesStore.deleteMany(ids); |
| | | |
| | | for (let id of ids) { |
| | | let stored = storedChanges.filter(change => change.id === id)[0]??false; |
| | | |
| | | let sentChanges = data.data.posts[id]; |
| | | let remainingChanges = {}; |
| | | |
| | | for (let [key, value] of Object.entries(sentChanges)) { |
| | | if (stored && !Object.hasOwn(stored, key)) continue; |
| | | if (stored[key] === value) { |
| | | delete stored[key]; |
| | | } |
| | | remainingChanges[key] = value; |
| | | } |
| | | if (Object.keys(remainingChanges).length > 0) { |
| | | remainingChanges['id'] = id; |
| | | remainingChanges['content'] = this.content; |
| | | this.changes.set(id, remainingChanges); |
| | | } |
| | | // Check for result data (from ContentExecutor) |
| | | if (!data.result || !data.result.posts) { |
| | | console.warn('Content update completed but no result.posts', data); |
| | | return; |
| | | } |
| | | if (Object.values(this.changes).length > 0) { |
| | | this.scheduleBackup(); |
| | | |
| | | // Get successfully processed post IDs |
| | | const successfulIds = Object.keys(data.result.posts).filter(id => { |
| | | return data.result.posts[id]?.success === true; |
| | | }); |
| | | |
| | | if (successfulIds.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | // Clear from both persistent and in-memory storage |
| | | this.changesStore.deleteMany(successfulIds); |
| | | successfulIds.forEach(id => this.changes.delete(id)); |
| | | } |
| | | |
| | | }); |
| | |
| | | } else if (modal.classList.contains('create')) { |
| | | title = `Creating your new ${this.singular}`; |
| | | } |
| | | this.cancelBackup(); |
| | | this.handleBackup().then(()=>{}); |
| | | this.savePosts(title,false).then(()=>{}); |
| | | this.scheduleSave(0); |
| | | } |
| | | handleChange(e) { |
| | | // Early bailout - target must be in an item or be a filter |
| | |
| | | if (!item) return; |
| | | item.dataset.itemId.split(',').forEach(itemId => { |
| | | let field = this.forms.getField(e.target); |
| | | if (['repeater', 'tag-list'].includes(field.dataset.fieldType)) { |
| | | return; |
| | | } |
| | | let name = field.dataset.field; |
| | | let value = this.forms.getFieldValue(e.target); |
| | | this.updateItem(itemId, name, value); |
| | | }); |
| | | this.savePosts('', true).then(()=>{}); |
| | | } |
| | | updateItem(itemId, name, value) { |
| | | if (!this.changes.has(itemId)) { |
| | |
| | | this.changes.get(itemId)[name] = value; |
| | | |
| | | this.scheduleBackup(); |
| | | this.scheduleSave(); |
| | | } |
| | | scheduleBackup() { |
| | | window.debouncer.schedule( |
| | |
| | | 2000 |
| | | ); |
| | | } |
| | | |
| | | cancelBackup() { |
| | | window.debouncer.cancel(`changes-${this.content}`); |
| | | } |
| | | async handleBackup() { |
| | | await this.changesStore.saveMany(this.changes); |
| | | const changesArray = Array.from(this.changes.values()); |
| | | this.changes.clear(); |
| | | |
| | | const ids = changesArray.map(c => c.id); |
| | | const existing = await Promise.all( |
| | | ids.map(id => this.changesStore.get(id)) |
| | | ); |
| | | |
| | | const changes = changesArray.map((change, i) => |
| | | existing[i] ? window.deepMerge(existing[i], change) : change |
| | | ); |
| | | |
| | | await this.changesStore.saveMany(changes); |
| | | } |
| | | |
| | | scheduleSave(delay = 10000) { |
| | | window.debouncer.schedule( |
| | | `save-${this.content}`, |
| | | async () => { |
| | | // Ensure latest changes are in IndexedDB |
| | | if (this.changes.size > 0) { |
| | | this.cancelBackup(); |
| | | await this.handleBackup(); |
| | | } |
| | | |
| | | await this.savePosts('', false); |
| | | }, |
| | | delay |
| | | ); |
| | | } |
| | | handleFilterChange(target) { |
| | | let filter = target.dataset.filter; |
| | |
| | | await this.handleBackup(); |
| | | } |
| | | const changes = await this.changesStore.getAll(); |
| | | |
| | | console.log('Saving Changes: ', changes); |
| | | if (changes.length === 0) return; |
| | | |
| | | if (title === '') { |