From e9967fa22781d922ba4eb8fb44fe72d200ac4b14 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 10 Nov 2025 21:04:10 +0000
Subject: [PATCH] =IconsManager.php update
---
assets/js/concise/UploadManager.js | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 107 insertions(+), 0 deletions(-)
diff --git a/assets/js/concise/UploadManager.js b/assets/js/concise/UploadManager.js
index 0fd8f6e..b59101c 100644
--- a/assets/js/concise/UploadManager.js
+++ b/assets/js/concise/UploadManager.js
@@ -99,6 +99,20 @@
'failed_permanent': 'Upload failed permanently'
};
+ // Sortable configuration
+ this.sortableInstances = new Map();
+ this.sortableConfig = {
+ animation: 150,
+ draggable: '.item',
+ handle: '.select-item-label, img', // Can drag by image or checkbox label
+ ghostClass: 'sortable-ghost',
+ chosenClass: 'sortable-chosen',
+ dragClass: 'sortable-drag',
+ onEnd: (evt) => {
+ this.handleReorder(evt);
+ }
+ };
+
this.init();
}
@@ -210,6 +224,9 @@
if (config.destination === 'post_group' && !this.dragController) {
this.initGroupFeatures();
}
+ if (config.type !== 'single') {
+ this.initSortable(field);
+ }
return fieldId;
}
@@ -356,6 +373,76 @@
});
}
+ initSortable(field) {
+ if (!window.Sortable) return;
+
+ // Main grid
+ const mainGrid = field.element.querySelector('.item-grid:not(.group)');
+ if (mainGrid) {
+ this.sortableInstances.set(`${field.id}-main`,
+ new Sortable(mainGrid, {
+ ...this.sortableConfig,
+ group: {
+ name: field.id,
+ pull: true,
+ put: true
+ }
+ })
+ );
+ }
+
+ // Group grids (for selection mode with grouping)
+ const groupGrids = field.element.querySelectorAll('.item-grid.group');
+ groupGrids.forEach((grid, index) => {
+ this.sortableInstances.set(`${field.id}-group-${index}`,
+ new Sortable(grid, {
+ ...this.sortableConfig,
+ group: {
+ name: field.id,
+ pull: true,
+ put: true
+ }
+ })
+ );
+ });
+ }
+
+// Add reorder handler
+ handleReorder(evt) {
+ const grid = evt.to;
+ const fieldWrapper = grid.closest('.field, .upload');
+ if (!fieldWrapper) return;
+
+ const form = fieldWrapper.closest('form');
+ if (!form) return;
+
+ // Get form config if available
+ const formId = form.dataset.formId;
+ if (formId && window.jvbForms) {
+ const formConfig = window.jvbForms.forms?.get(formId);
+ if (formConfig?.options.autosave) {
+ // Trigger autosave after reordering
+ window.jvbForms.scheduleSave(formConfig, 1000);
+ }
+ }
+
+ // Announce for accessibility
+ if (window.jvbA11y) {
+ window.jvbA11y.announce('Item reordered');
+ }
+
+ // Trigger custom event
+ fieldWrapper.dispatchEvent(new CustomEvent('jvb-items-reordered', {
+ detail: {
+ from: evt.from,
+ to: evt.to,
+ oldIndex: evt.oldIndex,
+ newIndex: evt.newIndex
+ },
+ bubbles: true
+ }));
+ }
+
/*******************************************************************************
* EXTERNAL FILE DROP HANDLERS (for new uploads from desktop)
*******************************************************************************/
@@ -2936,6 +3023,12 @@
this.selectionHandlers.clear();
this.cleanupAllPreviewUrls();
+ this.sortableInstances.forEach(instance => {
+ if (instance?.destroy) {
+ instance.destroy();
+ }
+ });
+ this.sortableInstances.clear();
// Clear data
this.fields.clear();
@@ -2945,6 +3038,20 @@
this.subscribers.clear();
}
+ destroySortable(fieldName) {
+ // Destroy all sortable instances for this field
+ const instances = Array.from(this.sortableInstances.keys())
+ .filter(key => key.startsWith(fieldName));
+
+ instances.forEach(key => {
+ const instance = this.sortableInstances.get(key);
+ if (instance?.destroy) {
+ instance.destroy();
+ }
+ this.sortableInstances.delete(key);
+ });
+ }
+
cleanupRestore() {
this.restoreModal.handleClose();
this.restoreSelection.destroy();
--
Gitblit v1.10.0