Implement collection item reordering with bulk operations and persistent HTML attributes
- Add bulk reorder API endpoint (PUT /api/collections/{id}/reorder) with atomic transactions
- Replace individual position updates with efficient bulk operations in frontend
- Implement unified ID generation and proper data-item-id injection during enhancement
- Fix collection item position persistence through content edit cycles
- Add optimistic UI with rollback capability for better user experience
- Update sqlc queries to include last_edited_by fields in position updates
- Remove obsolete data-content-type attributes and unify naming conventions
This commit is contained in:
@@ -245,8 +245,8 @@ export class CollectionManager {
|
||||
* This is used for existing items that were reconstructed from database
|
||||
*/
|
||||
extractCollectionItemId(element) {
|
||||
// Look for data-collection-item-id attribute first (newly created items)
|
||||
let itemId = element.getAttribute('data-collection-item-id');
|
||||
// Look for data-item-id attribute first (from server enhancement)
|
||||
let itemId = element.getAttribute('data-item-id');
|
||||
if (itemId) {
|
||||
return itemId;
|
||||
}
|
||||
@@ -278,12 +278,11 @@ export class CollectionManager {
|
||||
const backendItems = await this.apiClient.getCollectionItems(this.collectionId);
|
||||
console.log('📋 Backend collection items:', backendItems);
|
||||
|
||||
// Map backend items to existing DOM elements by position
|
||||
// This assumes the DOM order matches the database order
|
||||
// Items already have data-item-id from server enhancement
|
||||
// Just update the collectionItemId in our internal items array
|
||||
backendItems.forEach((backendItem, index) => {
|
||||
if (this.items[index]) {
|
||||
this.items[index].collectionItemId = backendItem.item_id;
|
||||
this.items[index].element.setAttribute('data-collection-item-id', backendItem.item_id);
|
||||
console.log(`🔗 Mapped DOM element ${index} to collection item ${backendItem.item_id}`);
|
||||
}
|
||||
});
|
||||
@@ -462,7 +461,7 @@ export class CollectionManager {
|
||||
const newItem = tempContainer.firstElementChild;
|
||||
|
||||
// Set the collection item ID as data attribute for future reference
|
||||
newItem.setAttribute('data-collection-item-id', collectionItem.item_id);
|
||||
newItem.setAttribute('data-item-id', collectionItem.item_id);
|
||||
|
||||
return newItem;
|
||||
} else {
|
||||
@@ -472,7 +471,7 @@ export class CollectionManager {
|
||||
const newItem = tempContainer.firstElementChild;
|
||||
|
||||
// Set the collection item ID as data attribute for future reference
|
||||
newItem.setAttribute('data-collection-item-id', collectionItem.item_id);
|
||||
newItem.setAttribute('data-item-id', collectionItem.item_id);
|
||||
|
||||
return newItem;
|
||||
}
|
||||
@@ -629,9 +628,9 @@ export class CollectionManager {
|
||||
|
||||
try {
|
||||
// 1. Get the collection item ID from the element
|
||||
const collectionItemId = itemElement.getAttribute('data-collection-item-id');
|
||||
const collectionItemId = itemElement.getAttribute('data-item-id');
|
||||
if (!collectionItemId) {
|
||||
console.error('❌ Cannot remove item: missing data-collection-item-id attribute');
|
||||
console.error('❌ Cannot remove item: missing data-item-id attribute');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -688,42 +687,54 @@ export class CollectionManager {
|
||||
|
||||
try {
|
||||
// 1. Get the collection item ID
|
||||
const collectionItemId = itemElement.getAttribute('data-collection-item-id');
|
||||
const collectionItemId = itemElement.getAttribute('data-item-id');
|
||||
if (!collectionItemId) {
|
||||
console.error('❌ Cannot move item: missing data-collection-item-id attribute');
|
||||
console.error('❌ Cannot move item: missing data-item-id attribute');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Update position in database first (backend-first approach)
|
||||
// Note: Backend expects 0-based positions, but we may need to adjust based on backend implementation
|
||||
const success = await this.apiClient.updateCollectionItemPosition(this.collectionId, collectionItemId, newIndex);
|
||||
if (!success) {
|
||||
alert('Failed to update item position in database. Please try again.');
|
||||
return;
|
||||
}
|
||||
// 2. Store original state for potential rollback
|
||||
const originalItems = [...this.items];
|
||||
|
||||
// 3. Get the target position in DOM
|
||||
// 3. Perform DOM move (optimistic UI)
|
||||
const targetItem = this.items[newIndex];
|
||||
|
||||
// 4. Move in DOM
|
||||
if (direction === 'up') {
|
||||
this.container.insertBefore(itemElement, targetItem.element);
|
||||
} else {
|
||||
this.container.insertBefore(itemElement, targetItem.element.nextSibling);
|
||||
}
|
||||
|
||||
// 5. Update items array
|
||||
// 4. Update items array
|
||||
[this.items[currentIndex], this.items[newIndex]] = [this.items[newIndex], this.items[currentIndex]];
|
||||
this.items[currentIndex].index = currentIndex;
|
||||
this.items[newIndex].index = newIndex;
|
||||
|
||||
// 6. Update all item controls
|
||||
// 5. Update all item controls
|
||||
this.updateAllItemControls();
|
||||
|
||||
// 7. Trigger site enhancement to update static files
|
||||
// 6. Build bulk reorder payload from current DOM state
|
||||
const itemOrder = this.items.map((item, index) => ({
|
||||
itemId: item.element.getAttribute('data-item-id'),
|
||||
position: index + 1 // 1-based positions
|
||||
}));
|
||||
|
||||
// 7. Send bulk reorder to backend
|
||||
const success = await this.apiClient.reorderCollection(this.collectionId, itemOrder);
|
||||
if (!success) {
|
||||
// Rollback DOM changes
|
||||
this.items = originalItems;
|
||||
this.items.forEach(item => {
|
||||
this.container.appendChild(item.element);
|
||||
});
|
||||
this.updateAllItemControls();
|
||||
alert('Failed to update item position in database. Please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 8. Trigger site enhancement to update static files
|
||||
await this.apiClient.enhanceSite();
|
||||
|
||||
console.log('✅ Item moved successfully:', collectionItemId, '→ position', newIndex);
|
||||
console.log('✅ Item moved successfully:', collectionItemId, '→ position', newIndex + 1);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to move collection item:', error);
|
||||
alert('Failed to move item. Please try again.');
|
||||
|
||||
Reference in New Issue
Block a user