Fix gallery duplicate uploads

8dd5d9321d940360a596cfd3f2654a737206b69e

Cohee <18619528+Cohee1207@users.noreply.github.com>

2 files changed, +55 -33Ignore whitespace
public/global.d.ts+2 -0
@@ -16,6 +16,8 @@ declare var ai;
1616
1717// Jquery plugins
1818interface JQuery {
19+ nanogallery2(options?: any): JQuery;
20+ nanogallery2(method: string, options?: any): JQuery;
1921 pagination(method: 'getCurrentPageNum'): number;
2022 pagination(method: string, options?: any): JQuery;
2123 pagination(options?: any): JQuery;
public/scripts/extensions/gallery/index.js+53 -33
@@ -3,6 +3,7 @@ import {
33 this_chid,
44 characters,
55 getRequestHeaders,
6+ event_types,
67} from '../../../script.js';
78import { groups, selected_group } from '../../group-chats.js';
89import { loadFileToDocument, delay } from '../../utils.js';
@@ -25,6 +26,27 @@ let paginationVisiblePages = 10;
2526let paginationMaxLinesPerPage = 2;
2627let galleryMaxRows = 3;
2728
29+$('body').on('click', '.dragClose', function () {
30+ const relatedId = $(this).data('related-id'); // Get the ID of the related draggable
31+ $(`body > .draggable[id="${relatedId}"]`).remove(); // Remove the associated draggable
32+});
33+
34+const CUSTOM_GALLERY_REMOVED_EVENT = 'galleryRemoved';
35+
36+const mutationObserver = new MutationObserver((mutations) => {
37+ mutations.forEach((mutation) => {
38+ mutation.removedNodes.forEach((node) => {
39+ if (node instanceof HTMLElement && node.tagName === 'DIV' && node.id === 'gallery') {
40+ eventSource.emit(CUSTOM_GALLERY_REMOVED_EVENT);
41+ }
42+ });
43+ });
44+});
45+
46+mutationObserver.observe(document.body, {
47+ childList: true,
48+ subtree: false,
49+});
2850
2951/**
3052 * Retrieves a list of gallery items based on a given URL. This function calls an API endpoint
@@ -59,7 +81,9 @@ async function getGalleryItems(url) {
5981 * @returns {Promise<void>} - Promise representing the completion of the gallery initialization.
6082 */
6183async function initGallery(items, url) {
84+ const nonce = `nonce-${Math.random().toString(36).substring(2, 15)}`;
6285 const gallery = $('#dragGallery');
86+ gallery.addClass(nonce);
6387 gallery.nanogallery2({
6488 'items': items,
6589 thumbnailWidth: 'auto',
@@ -82,16 +106,26 @@ async function initGallery(items, url) {
82106 fnThumbnailOpen: viewWithDragbox,
83107 });
84108
109+ const dragDropHandler = new DragAndDropHandler(`#dragGallery.${nonce}`, async (files, event) => {
110+ let file = files[0];
111+ uploadFile(file, url); // Added url parameter to know where to upload
112+ });
85113
86114 eventSource.on('resizeUI',const resizeHandler = function (elmntName) {
87115 gallery.nanogallery2('resize');
88116 });
89117
90- const dragDropHandler = new DragAndDropHandler('#dragGallery', async (files, event) => {
118+ eventSource.on('resizeUI', resizeHandler);
91- let file = files[0];
119+
92- uploadFile(file, url); // Added url parameter to know where to upload
120+ eventSource.once(event_types.CHAT_CHANGED, function () {
121+ gallery.closest('#gallery').remove();
93122 });
94123
124+ eventSource.once(CUSTOM_GALLERY_REMOVED_EVENT, function () {
125+ gallery.nanogallery2('destroy');
126+ dragDropHandler.destroy();
127+ eventSource.removeListener('resizeUI', resizeHandler);
128+ });
95129
96130 // Set dropzone height to be the same as the parent
97131 gallery.css('height', gallery.parent().css('height'));
@@ -140,16 +174,10 @@ async function showCharGallery() {
140174
141175 const items = await getGalleryItems(url);
142176 // if there already is a gallery, destroy it and place this one in its place
143177 if ($('#dragGallery').lengthclosest('#gallery') {.remove();
144- $('#dragGallery').nanogallery2('destroy');
178+ makeMovable();
145- initGallery(items, url);
179+ await delay(100);
146- } else {
180+ await initGallery(items, url);
147- makeMovable();
148- setTimeout(async () => {
149- await initGallery(items, url);
150- }, 100);
151- }
152-
153181 } catch (err) {
154182 console.trace();
155183 console.error(err);
@@ -202,11 +230,11 @@ async function uploadFile(file, url) {
202230 toastr.success('File uploaded successfully. Saved at: ' + result.path);
203231
204232 // Refresh the gallery
205- $('#dragGallery').nanogallery2('destroy'); // Destroy old gallery
206233 const newItems = await getGalleryItems(url); // Fetch the latest items
207- initGallery(newItems, url); // Reinitialize the gallery with new items and pass 'url'
234+ $('#dragGallery').closest('#gallery').remove(); // Destroy old gallery
208-
235+ makeMovable();
209-
236+ await delay(100);
237+ await initGallery(newItems, url); // Reinitialize the gallery with new items and pass 'url'
210238 } catch (error) {
211239 console.error('There was an issue uploading the file:', error);
212240
@@ -273,11 +301,6 @@ function makeMovable(id = 'gallery') {
273301 e.preventDefault();
274302 return false;
275303 });
276-
277- $('body').on('click', '.dragClose', function () {
278- const relatedId = $(this).data('related-id'); // Get the ID of the related draggable
279- $(`#${relatedId}`).remove(); // Remove the associated draggable
280- });
281304}
282305
283306/**
@@ -358,11 +381,6 @@ function makeDragImg(id, url) {
358381 } else {
359382 console.error('Failed to append the template content or retrieve the appended content.');
360383 }
361-
362- $('body').on('click', '.dragClose', function () {
363- const relatedId = $(this).data('related-id'); // Get the ID of the related draggable
364- $(`#${relatedId}`).remove(); // Remove the associated draggable
365- });
366384}
367385
368386/**
@@ -401,7 +419,8 @@ function viewWithDragbox(items) {
401419
402420
403421// Registers a simple command for opening the char gallery.
404422SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'show-gallery',
423+ name: 'show-gallery',
405424 aliases: ['sg'],
406425 callback: () => {
407426 showCharGallery();
@@ -409,7 +428,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'show-gallery
409428 },
410429 helpString: 'Shows the gallery.',
411430}));
412431SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'list-gallery',
432+ name: 'list-gallery',
413433 aliases: ['lg'],
414434 callback: listGalleryCommand,
415435 returns: 'list of images',
@@ -432,14 +452,14 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'list-gallery
432452
433453async function listGalleryCommand(args) {
434454 try {
435455 let url = args.char ?? (args.group ? groups.find(it => it.name == args.group)?.id : null) ?? (selected_group || this_chid);
436456 if (!args.char && !args.group && !selected_group && this_chid) {
437457 const char = characters[this_chid];
438458 url = char.avatar.replace('.png', '');
439459 }
440460
441461 const items = await getGalleryItems(url);
442462 return JSON.stringify(items.map(it => it.src));
443463
444464 } catch (err) {
445465 console.trace();