Unblock textarea send during edit (#4714)

60a8b519512f81f5418de378a09b3ee3b7c65ce1

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

Signed
3 files changed, +53 -30Showing whitespace changes
public/script.js+7 -5
@@ -276,6 +276,7 @@ import { event_types, eventSource } from './scripts/events.js';
276276import { initAccessibility } from './scripts/a11y.js';
277277import { applyStreamFadeIn } from './scripts/util/stream-fadein.js';
278278import { initDomHandlers } from './scripts/dom-handlers.js';
279+import { SimpleMutex } from './scripts/util/SimpleMutex.js';
279280
280281// API OBJECT FOR EXTERNAL WIRING
281282globalThis.SillyTavern = {
@@ -1560,9 +1561,8 @@ export async function reloadCurrentChat() {
15601561export async function sendTextareaMessage() {
15611562 if (is_send_press) return;
15621563 if (isExecutingCommandsFromChatInput) return;
1563- if (this_edit_mes_id >= 0) return; // don't proceed if editing a message
15641564
15651565 let generateType = 'normal';
15661566 // "Continue on send" is activated when the user hits "send" (or presses enter) on an empty chat box, and the last
15671567 // message was sent from a character (not the user or the system).
15681568 const textareaText = String($('#send_textarea').val());
@@ -1581,7 +1581,7 @@ export async function sendTextareaMessage() {
15811581 await newAssistantChat({ temporary: false });
15821582 }
15831583
15841584 return await Generate(generateType);
15851585}
15861586
15871587/**
@@ -2190,6 +2190,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
21902190 }
21912191
21922192 applyCharacterTagsToMessageDivs({ mesIds: newMessageId });
2193+ updateEditArrowClasses();
21932194}
21942195
21952196/**
@@ -9937,8 +9938,9 @@ jQuery(async function () {
99379938 $('#option_continue').trigger('click');
99389939 });
99399940
9940- $('#send_but').on('click', function () {
9941+ const userInputGenerateMutex = new SimpleMutex(sendTextareaMessage);
9941- sendTextareaMessage();
9942+ $('#send_but').on('click', async function () {
9943+ await userInputGenerateMutex.update();
99429944 });
99439945
99449946 //menu buttons setup
public/scripts/extensions.js+2 -25
@@ -10,10 +10,12 @@ import { isAdmin } from './user.js';
1010import { addLocaleData, getCurrentLocale, t } from './i18n.js';
1111import { debounce_timeout } from './constants.js';
1212import { accountStorage } from './util/AccountStorage.js';
13+import { SimpleMutex } from './util/SimpleMutex.js';
1314
1415export {
1516 getContext,
1617 getApiUrl,
18+ SimpleMutex as ModuleWorkerWrapper,
1719};
1820
1921/** @type {string[]} */
@@ -124,31 +126,6 @@ export function renderExtensionTemplateAsync(extensionName, templateId, template
124126 return renderTemplateAsync(`scripts/extensions/${extensionName}/${templateId}.html`, templateData, sanitize, localize, true);
125127}
126128
127-// Disables parallel updates
128-export class ModuleWorkerWrapper {
129- constructor(callback) {
130- this.isBusy = false;
131- this.callback = callback;
132- }
133-
134- // Called by the extension
135- async update(...args) {
136- // Don't touch me I'm busy...
137- if (this.isBusy) {
138- return;
139- }
140-
141- // I'm free. Let's update!
142- try {
143- this.isBusy = true;
144- await this.callback(...args);
145- }
146- finally {
147- this.isBusy = false;
148- }
149- }
150-}
151-
152129export const extension_settings = {
153130 apiUrl: defaultUrl,
154131 apiKey: '',
public/scripts/util/SimpleMutex.js+44 -0
@@ -0,0 +1,44 @@
1+/**
2+ * A simple mutex class to prevent concurrent updates.
3+ */
4+export class SimpleMutex {
5+ /**
6+ * @type {boolean}
7+ */
8+ isBusy = false;
9+
10+ /**
11+ * @type {Function}
12+ */
13+ callback = () => {};
14+
15+ /**
16+ * Constructs a SimpleMutex.
17+ * @param {Function} callback Callback function.
18+ */
19+ constructor(callback) {
20+ this.isBusy = false;
21+ this.callback = callback;
22+ }
23+
24+ /**
25+ * Updates the mutex by calling the callback if not busy.
26+ * @param {...any} args Callback args
27+ * @returns {Promise<void>}
28+ */
29+ async update(...args) {
30+ // Don't touch me I'm busy...
31+ if (this.isBusy) {
32+ return;
33+ }
34+
35+ // I'm free. Let's update!
36+ try {
37+ this.isBusy = true;
38+ await this.callback(...args);
39+ }
40+ finally {
41+ this.isBusy = false;
42+ }
43+ }
44+}