Fix gallery duplicate uploads

8dd5d9321d940360a596cfd3f2654a737206b69e

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

2 files changed, +51 -29Showing whitespace changes
public/global.d.ts+2 -0
@@ -16,6 +16,8 @@ declare var ai;
1616
17// Jquery plugins17// Jquery plugins
18interface JQuery {18interface JQuery {
19 nanogallery2(options?: any): JQuery;
20 nanogallery2(method: string, options?: any): JQuery;
19 pagination(method: 'getCurrentPageNum'): number;21 pagination(method: 'getCurrentPageNum'): number;
20 pagination(method: string, options?: any): JQuery;22 pagination(method: string, options?: any): JQuery;
21 pagination(options?: any): JQuery;23 pagination(options?: any): JQuery;
public/scripts/extensions/gallery/index.js+49 -29
@@ -3,6 +3,7 @@ import {
3 this_chid,3 this_chid,
4 characters,4 characters,
5 getRequestHeaders,5 getRequestHeaders,
6 event_types,
6} from '../../../script.js';7} from '../../../script.js';
7import { groups, selected_group } from '../../group-chats.js';8import { groups, selected_group } from '../../group-chats.js';
8import { loadFileToDocument, delay } from '../../utils.js';9import { loadFileToDocument, delay } from '../../utils.js';
@@ -25,6 +26,27 @@ let paginationVisiblePages = 10;
25let paginationMaxLinesPerPage = 2;26let paginationMaxLinesPerPage = 2;
26let galleryMaxRows = 3;27let 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
34const CUSTOM_GALLERY_REMOVED_EVENT = 'galleryRemoved';
35
36const 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
46mutationObserver.observe(document.body, {
47 childList: true,
48 subtree: false,
49});
2850
29/**51/**
30 * Retrieves a list of gallery items based on a given URL. This function calls an API endpoint52 * 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) {
59 * @returns {Promise<void>} - Promise representing the completion of the gallery initialization.81 * @returns {Promise<void>} - Promise representing the completion of the gallery initialization.
60 */82 */
61async function initGallery(items, url) {83async function initGallery(items, url) {
84 const nonce = `nonce-${Math.random().toString(36).substring(2, 15)}`;
62 const gallery = $('#dragGallery');85 const gallery = $('#dragGallery');
86 gallery.addClass(nonce);
63 gallery.nanogallery2({87 gallery.nanogallery2({
64 'items': items,88 'items': items,
65 thumbnailWidth: 'auto',89 thumbnailWidth: 'auto',
@@ -82,16 +106,26 @@ async function initGallery(items, url) {
82 fnThumbnailOpen: viewWithDragbox,106 fnThumbnailOpen: viewWithDragbox,
83 });107 });
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
86 eventSource.on('resizeUI', function (elmntName) {114 const resizeHandler = function () {
87 gallery.nanogallery2('resize');115 gallery.nanogallery2('resize');
88 });116 };
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 upload120 eventSource.once(event_types.CHAT_CHANGED, function () {
121 gallery.closest('#gallery').remove();
93 });122 });
94123
124 eventSource.once(CUSTOM_GALLERY_REMOVED_EVENT, function () {
125 gallery.nanogallery2('destroy');
126 dragDropHandler.destroy();
127 eventSource.removeListener('resizeUI', resizeHandler);
128 });
95129
96 // Set dropzone height to be the same as the parent130 // Set dropzone height to be the same as the parent
97 gallery.css('height', gallery.parent().css('height'));131 gallery.css('height', gallery.parent().css('height'));
@@ -140,16 +174,10 @@ async function showCharGallery() {
140174
141 const items = await getGalleryItems(url);175 const items = await getGalleryItems(url);
142 // if there already is a gallery, destroy it and place this one in its place176 // if there already is a gallery, destroy it and place this one in its place
143 if ($('#dragGallery').length) {177 $('#dragGallery').closest('#gallery').remove();
144 $('#dragGallery').nanogallery2('destroy');
145 initGallery(items, url);
146 } else {
147 makeMovable();178 makeMovable();
148 setTimeout(async () => {179 await delay(100);
149 await initGallery(items, url);180 await initGallery(items, url);
150 }, 100);
151 }
152
153 } catch (err) {181 } catch (err) {
154 console.trace();182 console.trace();
155 console.error(err);183 console.error(err);
@@ -202,11 +230,11 @@ async function uploadFile(file, url) {
202 toastr.success('File uploaded successfully. Saved at: ' + result.path);230 toastr.success('File uploaded successfully. Saved at: ' + result.path);
203231
204 // Refresh the gallery232 // Refresh the gallery
205 $('#dragGallery').nanogallery2('destroy'); // Destroy old gallery
206 const newItems = await getGalleryItems(url); // Fetch the latest items233 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
208235 makeMovable();
209236 await delay(100);
237 await initGallery(newItems, url); // Reinitialize the gallery with new items and pass 'url'
210 } catch (error) {238 } catch (error) {
211 console.error('There was an issue uploading the file:', error);239 console.error('There was an issue uploading the file:', error);
212240
@@ -273,11 +301,6 @@ function makeMovable(id = 'gallery') {
273 e.preventDefault();301 e.preventDefault();
274 return false;302 return false;
275 });303 });
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 });
281}304}
282305
283/**306/**
@@ -358,11 +381,6 @@ function makeDragImg(id, url) {
358 } else {381 } else {
359 console.error('Failed to append the template content or retrieve the appended content.');382 console.error('Failed to append the template content or retrieve the appended content.');
360 }383 }
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 });
366}384}
367385
368/**386/**
@@ -401,7 +419,8 @@ function viewWithDragbox(items) {
401419
402420
403// Registers a simple command for opening the char gallery.421// Registers a simple command for opening the char gallery.
404SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'show-gallery',422SlashCommandParser.addCommandObject(SlashCommand.fromProps({
423 name: 'show-gallery',
405 aliases: ['sg'],424 aliases: ['sg'],
406 callback: () => {425 callback: () => {
407 showCharGallery();426 showCharGallery();
@@ -409,7 +428,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'show-gallery
409 },428 },
410 helpString: 'Shows the gallery.',429 helpString: 'Shows the gallery.',
411}));430}));
412SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'list-gallery',431SlashCommandParser.addCommandObject(SlashCommand.fromProps({
432 name: 'list-gallery',
413 aliases: ['lg'],433 aliases: ['lg'],
414 callback: listGalleryCommand,434 callback: listGalleryCommand,
415 returns: 'list of images',435 returns: 'list of images',