From d7dbe7fee362d587dfc334135d9581b6216a4295 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 23 Nov 2025 04:13:56 +0000
Subject: [PATCH] =Timeline block, and feed block updated. DataStore.js refactored to not block rendering
---
assets/js/dash/CRUD.js | 263 +++++++++++++++++++++++++++++++++++-----------------
1 files changed, 178 insertions(+), 85 deletions(-)
diff --git a/assets/js/dash/CRUD.js b/assets/js/dash/CRUD.js
index dfb568b..6780203 100644
--- a/assets/js/dash/CRUD.js
+++ b/assets/js/dash/CRUD.js
@@ -4,7 +4,6 @@
class CRUDManager {
constructor(config) {
this.queue = window.jvbQueue;
- console.log(this.queue);
this.config = config;
this.content = config.content || false;
this.settings = window.jvbUserSettings;
@@ -13,37 +12,71 @@
return;
}
this.isTimeline = false;
+ this.currentItemID = null;
this.initElements();
this.updateBulkOptions();
// Initialize components
- this.store = new window.jvbStore({
- name: this.content,
- storeName: this.content,
- endpoint: 'content',
- headers: {
- 'action_nonce': jvbSettings.dash,
- },
- indexes: [
- { name: 'status', keyPath: 'post_status'},
- { name: 'modified', keyPath: 'modified'},
- ],
- filters: {
- content: this.content,
- user: jvbSettings.currentUser,
- page: 1,
- status: 'all'
- },
- TTL: 3600000,
- cacheDOM: true
- });
+ this.store = window.jvbStore.register(
+ this.content,
+ {
+ keyPath: 'id',
+ endpoint: 'content',
+ headers: {
+ 'action_nonce': jvbSettings.dash,
+ },
+ indexes: [
+ {name: 'id', keyPath: 'id'},
+ { name: 'status', keyPath: 'status'},
+ { name: 'date', keyPath: 'date'},
+ { name: 'modified', keyPath: 'modified'},
+ { name: 'title', keyPath: 'title'}
+ ],
+ filters: {
+ content: this.content,
+ user: jvbSettings.currentUser,
+ page: 1,
+ status: 'all',
+ orderby: 'modified', //or title
+ order: 'desc'
+ },
+ TTL: 30 * 60 * 1000, //30 minutes cache
+ });
this.status = 'all';
this.filterTimeout = null;
this.viewController = new window.jvbViews(this.ui.container, this.store);
- this.formController = new window.jvbForm();
+ this.tableForm = null;
+ this.tableChanges = new Map();
+
+
+ this.formController = (this.isTimeline) ? new window.jvbForm({collectFormData: () => this.collectTimelineData.bind(this)}) : new window.jvbForm();
+ this.viewController.subscribe((event, form) => {
+ if (event === 'table-view' && !this.tableForm) {
+ if (!this.tableForm) {
+ this.tableForm = this.formController.registerForm(form, {
+ autosave: false,
+ formStatus: false,
+ isTable: true,
+ });
+ }
+
+ } else if (event === 'not-table-view') {
+ if (this.tableForm) {
+
+ }
+ } else if (event === 'order-changed') {
+ let data = this.store.get(form);
+ if (!data) {
+ return;
+ }
+ let changes = {};
+ changes[form] = data;
+ this.savePosts(changes, `Updating progression order`);
+ }
+ });
this.formController.subscribe((event, data) => {
switch(event) {
@@ -54,15 +87,16 @@
}
});
- if (window.jvbQueue) {
- window.jvbQueue.subscribe((event, data) => {
- if (event === 'operation-completed' && data.source === 'form') {
- this.handleQueueSuccess(event, data);
- } else if (event === 'operation-failed-permanent' && data.source === 'form') {
- this.handleQueueFailure(event, data);
- }
- });
- }
+ this.queue.subscribe((event, data) => {
+ if (!Object.hasOwn(data, 'endpoint') || data.endpoint !== 'content') return;
+ console.log('Queue Subscription in CRUD.js: ', data);
+ if (event === 'operation-completed') {
+ this.handleQueueSuccess(event, data);
+ } else if (event === 'operation-failed-permanent') {
+ this.handleQueueFailure(event, data);
+ }
+ });
+
// Track initialization
this.initialized = false;
@@ -70,35 +104,32 @@
this.init();
}
handleFormChange(event, data) {
+ let title = data.fullData.post_title;
+ let changes = (Object.hasOwn(data, 'changes')) ? data.changes : data.fullData;
+
+ let theChanges = {};
if (this.isTimeline) {
- data.changes.content = this.content;
- let changes = {};
- let postID = data.config.id.replace('edit-', '');
- changes[postID] = data.changes;
- this.savePosts(changes, `Saving ${data.fullData.post_title}'s Changes`);
+ theChanges[this.currentItemID] = changes;
+ this.savePosts(theChanges, title);
return;
}
- data.changes.content = this.content;
- let changes = {};
- let title = '';
+
let itemsToRemove = [];
switch (true) {
case data.config.element === this.ui.forms.edit:
- let postID = data.config.id.replace('edit-', '');
- console.log(postID);
- changes[postID] = data.changes;
- title = `Saving ${data.fullData['post_title']} Changes`;
+ theChanges[this.currentItemID] = changes;
+ title = `Saving ${title} Changes`;
// Check if status change requires removal
- if (data.changes.post_status && this.shouldRemoveItem(data.changes.post_status)) {
- itemsToRemove.push(postID);
+ if (changes.post_status && this.shouldRemoveItem(changes.post_status)) {
+ itemsToRemove.push(this.currentItemID);
}
break;
case data.config.element === this.ui.forms.bulkEdit:
let selected = data.config.element.querySelectorAll('.selected input:checked');
selected.forEach(sel => {
- changes[sel.value] = data.changes;
+ theChanges[sel.value] = changes;
// Check if status change requires removal
- if (data.changes.post_status && this.shouldRemoveItem(data.changes.post_status)) {
+ if (changes.post_status && this.shouldRemoveItem(changes.post_status)) {
itemsToRemove.push(sel.value);
}
});
@@ -107,8 +138,8 @@
break;
case data.config.element === this.ui.forms.create:
if (event === 'form-submit') {
- changes[data.config.data['form-id']] = data.fullData;
- title = `Saving ${data.fullData['post_title']} Changes`;
+ theChanges[data.config.data['form-id']] = changes;
+ title = `Saving ${title} Changes`;
}
break;
}
@@ -134,11 +165,11 @@
}
}
- if (window.isEmptyObject(changes)) {
+ if (window.isEmptyObject(theChanges)) {
return;
}
- this.savePosts(changes, title);
+ this.savePosts(theChanges, title);
}
shouldRemoveItem(newStatus) {
@@ -150,6 +181,13 @@
if (window.isEmptyObject(changes)) {
return;
}
+
+ //ensure content is in each post
+ for (let postId in changes) {
+ if (!changes[postId]['content']) {
+ changes[postId]['content'] = this.content;
+ }
+ }
let operation = {
endpoint: 'content',
headers: {
@@ -165,15 +203,15 @@
this.queue.addToQueue(operation);
}
- handleQueueSuccess(event, data) {
- console.log('Handling queue success...');
- console.log('Event', event);
- console.log('Data', data);
+ async handleQueueSuccess(event, data) {
+ this.store.clearCache();
+ this.store.clearHttpHeaders();
+ this.store.fetch();
}
handleQueueFailure(event, data) {
- console.log('Handling queue failure...');
- console.log('Event', event);
- console.log('Data', data);
+ console.error('Operation failed permanently:', data);
+ // Optionally show error notification to user
+ this.a11y?.announce(`Operation failed: ${data.error_message || 'Unknown error'}`);
}
initElements() {
@@ -194,14 +232,11 @@
uploader: 'details.uploader'
};
this.ui = window.uiFromSelectors(this.elements);
- this.isTimeline = Object.hasOwn(this.ui.forms.edit.dataset, 'timeline');
+ this.isTimeline = !!document.querySelector('[data-timeline]');
}
init() {
this.settings.addSetting(this.ui.uploader, 'open');
this.ui.uploader.addEventListener('toggle', (e) =>{
- console.log(e);
- console.log('Is Open: ', this.ui.uploader.open);
- console.log(this.ui.uploader.open ? 'on' : 'off');
this.settings.saveSetting('open', this.ui.uploader.open ? 'on' : 'off');
});
@@ -219,9 +254,9 @@
this.modals[name].subscribe((event, data) => {
switch (event) {
case 'modal-close':
+ this.currentItemID = null;
this.formController.cleanupForm(this.modals[name].modal.querySelector('form').dataset.formId);
//double check we have finished saving
- console.log('Data on modal close: ', data);
break;
case 'modal-open':
//probably not needed in this class
@@ -235,15 +270,6 @@
this.setupFilters();
-
- this.queue.subscribe((event, data) => {
- switch (event) {
- case 'operation-status':
- //update items?
- break;
- }
- });
-
this.initialized = true;
}
@@ -347,6 +373,14 @@
});
}
handleChange(e) {
+ if (e.target.closest('[data-id]')) {
+ if (this.isTimeline) {
+ this.handleTimelineTableChange(e);
+ } else {
+ this.handleTableChange(e);
+ }
+ return;
+ }
if (e.target.classList.contains('bulk-action-select')) {
if (e.target.value.startsWith('tax-')) {
const taxonomy = e.target.value.replace('tax-', '');
@@ -378,6 +412,73 @@
}
}
}
+ handleTableChange(e) {
+ const row = e.target.closest('tr[data-id]');
+ if (!row) return;
+
+ const input = e.target;
+ const postID = parseInt(row.dataset.id);
+ const fieldName = input.closest(['data-field'])?.dataset.field;
+ if (!fieldName) return;
+
+ const item = this.store.get(postID);
+ if (!item) return;
+
+ item.fields[fieldName] = this.getInputValue(input);
+
+ this.store.save(item);
+
+ let post = {};
+ post[postID] = item.fields;
+ this.savePosts(post, `Saving changes to ${this.content}`);
+ }
+ handleTimelineTableChange(e) {
+ const tbody = e.target.closest('tbody[data-id]');
+ if (!tbody) return;
+
+ const input = e.target;
+ const fieldName = input.closest('[data-field]')?.dataset.field;
+
+ if (!fieldName) return;
+
+ const parentID = parseInt(tbody.dataset.id);
+ const timelinePoint = input.closest('tr.timeline-point');
+
+ const item = this.store.get(parentID);
+ if (!item) return;
+
+ const value = this.getInputValue(input);
+
+ // Check if this is a specific point, or a shared value
+ if (timelinePoint) {
+ const imgID = timelinePoint.dataset.imageId;
+ if (!item.fields.timeline) {
+ item.fields.timeline = {};
+ }
+ if (!item.fields.timeline[imgID]) {
+ item.fields.timeline[imgID] = {};
+ }
+ item.fields.timeline[imgID][fieldName] = value;
+ } else {
+ item.fields[fieldName] = value;
+ }
+
+ //Update store directly
+ this.store.save(item);
+
+ let changes = {};
+ changes[parentID] = item.fields;
+ this.savePosts(changes, 'Updating progress post');
+ }
+ getInputValue(input) {
+ if (input.type === 'checkbox') {
+ return input.checked ? (input.value || '1') : '';
+ }
+ if (input.type === 'radio') {
+ return input.checked ? input.value : null;
+ }
+ return input.value;
+ }
openTaxonomyModal(taxonomy) {
// Check if jvbSelector exists
@@ -393,14 +494,13 @@
);
}
handleBulkTaxonomy(selectedIds, taxonomy) {
- console.log(taxonomy, selectedIds);
// Callback when terms are selected
if (selectedIds.length > 0) {
selectedIds = selectedIds.join(',');
let changes = {};
let selected = Array.from(this.viewController.selectedItems);
- console.log('selected',selected);
+
selected.forEach(sel => {
changes[sel] = {
content: this.content
@@ -408,7 +508,6 @@
changes[sel][taxonomy] = selectedIds;
});
- console.log('Taxonomy changes: ', changes);
let title = `Adding ${selected.length} ${this.config.plural??'posts'} to ${selectedIds.length} ${jvbSettings.labels[taxonomy].plural}`;
this.viewController.clearSelection();
@@ -420,7 +519,7 @@
if (!['publish', 'draft', 'trash', 'delete'].includes(status)){
return;
}
- console.log(`Setting status: ${status}`);
+
let changes = {};
for (let selected of this.viewController.selectedItems) {
changes[selected] = {
@@ -436,7 +535,7 @@
default:
title = window.uppercaseFirst(status)+'ing';
}
- console.log(this.status);
+
if ((this.status === 'all' && !['publish', 'draft'].includes(status)) || status !== this.status) {
let delay = 0;
for (let selected of this.viewController.selectedItems) {
@@ -503,9 +602,8 @@
window.removeChildren(container);
for (let selected of this.viewController.selectedItems) {
- console.log(selected);
let item = this.store.get(selected);
- console.log(item);
+
const img = window.getTemplate('bulkItem');
if (!img) return;
@@ -533,14 +631,12 @@
];
this.formController.registerForm(this.ui.forms.bulkEdit);
- console.log('Bulk Edit form registered');
}
populateEditForm(itemID) {
- console.log(itemID);
+ this.currentItemID = itemID;
let item = this.store.get(parseInt(itemID));
- console.log(item);
if (item) {
this.ui.modals.edit.dataset.itemID = itemID;
this.ui.modals.edit.dataset.content = this.content;
@@ -552,10 +648,8 @@
`Editing ${item.fields.post_title}`
];
form.dataset.formId = `edit-${itemID}`;
- console.log(form.dataset.formId);
new window.jvbPopulate(form, item.fields, item.images);
this.formController.registerForm(this.ui.forms.edit);
- console.log('Edit form registered');
}
}
@@ -593,7 +687,6 @@
document.querySelectorAll('[data-filter]').forEach(filter => {
filter.removeEventListener('change', this.filterHandler);
});
- this.store.subscribers.clear();
}
}
--
Gitblit v1.10.0