Chore: Add code formatting conventions as eslint rules (#5158) * Add code formatting conventions as eslint rules * Improve formatting in addQuickReply

357da3219b6686616c3435524fa23ac987eff840

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

Signed
94 files changed, +366 -566Ignore whitespace
.eslintrc.cjs+23 -0
@@ -102,5 +102,28 @@ module.exports = {
102102 // These rules should eventually be enabled.
103103 'no-async-promise-executor': 'off',
104104 'no-inner-declarations': 'off',
105+ 'brace-style': 'off',
106+ // Additional formatting rules based on codebase conventions
107+ 'array-bracket-spacing': ['error', 'never'],
108+ 'computed-property-spacing': ['error', 'never'],
109+ 'block-spacing': ['error', 'always'],
110+ 'keyword-spacing': ['error', { before: true, after: true }],
111+ 'space-before-blocks': ['error', 'always'],
112+ 'space-before-function-paren': ['error', { anonymous: 'always', named: 'never', asyncArrow: 'always' }],
113+ 'space-in-parens': ['error', 'never'],
114+ 'comma-spacing': ['error', { before: false, after: true }],
115+ 'key-spacing': ['error', { beforeColon: false, afterColon: true }],
116+ 'func-call-spacing': ['error', 'never'],
117+ 'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1, maxBOF: 0 }],
118+ 'padded-blocks': ['error', 'never'],
119+ 'no-whitespace-before-property': 'error',
120+ 'space-unary-ops': ['error', { words: true, nonwords: false }],
121+ 'arrow-spacing': ['error', { before: true, after: true }],
122+ 'template-curly-spacing': ['error', 'never'],
123+ 'rest-spread-spacing': ['error', 'never'],
124+ 'generator-star-spacing': ['error', { before: false, after: true }],
125+ 'yield-star-spacing': ['error', { before: false, after: true }],
126+ 'template-tag-spacing': ['error', 'never'],
127+ 'switch-colon-spacing': ['error', { after: true, before: false }],
105128 },
106129};
public/script.js+2 -14
@@ -2516,7 +2516,6 @@ export function addOneMessage(mes, { type = undefined, insertAfter = null, scrol
25162516 * @returns {JQuery<HTMLElement>} Rendered HTMLElement.
25172517 */
25182518export function updateMessageElement(mes, { messageId = chat.length - 1, messageElement = messageTemplate.clone(), adjustMediaScroll = SCROLL_BEHAVIOR.NONE } = {}) {
2519-
25202519 let avatarImg = getThumbnailUrl('persona', user_avatar);
25212520
25222521 //for non-user messages
@@ -3709,9 +3708,9 @@ class StreamingProcessor {
37093708 }
37103709
37113710 /**
37123711 * @returns {GeneratorAsyncGenerator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[], state: any }, void, void>}
37133712 */
37143713 async* nullStreamingGeneration() {
37153714 throw new Error('Generation function for streaming is not hooked up');
37163715 }
37173716
@@ -4862,7 +4861,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
48624861
48634862 // Add quiet generation prompt at depth 0
48644863 if (quiet_prompt && quiet_prompt.length) {
4865-
48664864 // here name1 is forced for all quiet prompts..why?
48674865 const name = name1;
48684866 //checks if we are in instruct, if so, formats the chat as such, otherwise just adds the quiet prompt
@@ -5399,7 +5397,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
53995397 if (!isAborted && power_user.auto_swipe && generatedTextFiltered(getMessage)) {
54005398 is_send_press = false;
54015399 return await swipe(null, SWIPE_DIRECTION.RIGHT, { source: SWIPE_SOURCE.AUTO_SWIPE, repeated: true, forceMesId: chat.length - 1 });
5402-
54035400 }
54045401
54055402 console.debug('/api/chats/save called by /Generate');
@@ -6517,7 +6514,6 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
65176514 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
65186515 addOneMessage(chat[chat_id], { type: 'swipe' });
65196516 !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
6520-
65216517 } else {
65226518 console.debug('entering chat update routine for non-swipe post');
65236519 const newMessage = {};
@@ -8247,7 +8243,6 @@ export async function getChatsFromFiles(data, isGroupChat) {
82478243 currentChat.shift();
82488244 }
82498245 chat_dict[file_name] = currentChat;
8250-
82518246 } catch (error) {
82528247 console.error(error);
82538248 }
@@ -9588,7 +9583,6 @@ export async function createOrEditCharacter(e) {
95889583 select_rm_info('char_create', avatarId, oldSelectedChar);
95899584
95909585 crop_data = undefined;
9591-
95929586 } catch (error) {
95939587 console.error('Error creating character', error);
95949588 toastr.error(t`Failed to create character`);
@@ -9984,7 +9978,6 @@ export async function swipe(event, direction, { source, repeated, message = chat
99849978 duration: 0, //used to be 100 //Disabled on Cohee's request. https://github.com/SillyTavern/SillyTavern/pull/4610/files#r2408731744
99859979 queue: false,
99869980 progress: function (animation, progress, remainingMs) {
9987-
99889981 if (is_animation_scroll) chatElement.scrollTop(getMessageBottomHeight(thisMesDiv));
99899982 },
99909983 complete: function () {
@@ -10001,7 +9994,6 @@ export async function swipe(event, direction, { source, repeated, message = chat
100019994 * @param {boolean} [skipSwipeOut=false]
100029995 */
100039996 async function animateSwipe(run_generate = false, skipSwipeOut = false) {
10004-
100059997 if (!skipSwipeOut) {
100069998 //Swipe out.
100079999 await animateSwipeTransition(mesId, { xEnd: `${swipeRange}px`, duration: swipeDuration });
@@ -10069,7 +10061,6 @@ export async function swipe(event, direction, { source, repeated, message = chat
1006910061
1007010062 //If the swipe is not being deleted.
1007110063 if (source != SWIPE_SOURCE.DELETE && source != SWIPE_SOURCE.BACK) {
10072-
1007310064 // Make sure ad-hoc changes to extras are saved before swiping away
1007410065 syncMesToSwipe(mesId);
1007510066
@@ -10382,7 +10373,6 @@ export async function doNewChat({ deleteCurrentChat = false } = {}) {
1038210373 await createOrEditCharacter(new CustomEvent('newChat'));
1038310374 if (deleteCurrentChat) await delChat(chat_file_for_del + '.jsonl');
1038410375 }
10385-
1038610376}
1038710377
1038810378/**
@@ -11407,9 +11397,7 @@ jQuery(async function () {
1140711397
1140811398 divchat.style.borderRadius = '';
1140911399 divchat.style.backgroundColor = '';
11410-
1141111400 } else {
11412-
1141311401 divchat.style.borderRadius = '10px'; // Adjust the value to control the roundness of the corners
1141411402 divchat.style.backgroundColor = ''; // Set the background color to your preference
1141511403
public/scripts/BulkEditOverlay.js+2 -2
@@ -101,7 +101,7 @@ class CharacterContextMenu {
101101 * @param {number} characterId
102102 * @returns {Promise<void>}
103103 */
104104 static persona = async (characterId) => void (await convertCharacterToPersona(characterId));
105105
106106 /**
107107 * Delete one or more characters,
@@ -754,7 +754,7 @@ class BulkEditOverlay {
754754
755755 handleContextMenuShow = (event) => {
756756 event.preventDefault();
757757 const [x, y] = this.#getContextMenuPosition(event);
758758 CharacterContextMenu.show(x, y);
759759 this.#contextMenuOpen = true;
760760 };
public/scripts/PromptManager.js+0 -2
@@ -986,7 +986,6 @@ class PromptManager {
986986 * @returns {void}
987987 */
988988 addPrompt(prompt, identifier) {
989-
990989 if (typeof prompt !== 'object' || prompt === null) throw new Error('Object is not a prompt');
991990
992991 const newPrompt = {
@@ -1318,7 +1317,6 @@ class PromptManager {
13181317 this.updatePromptByIdentifier(identifier, prompt);
13191318 debouncedSaveServiceSettings().then(() => this.render());
13201319 });
1321-
13221320 }
13231321
13241322 /**
public/scripts/RossAscends-mods.js+0 -3
@@ -101,7 +101,6 @@ observer.observe(document.documentElement, observerConfig);
101101 * @returns {string} - A human-readable string that represents the time spent generating characters.
102102 */
103103export function humanizeGenTime(total_gen_time) {
104-
105104 //convert time_spent to humanized format of "_ Hours, _ Minutes, _ Seconds" from milliseconds
106105 let time_spent = total_gen_time || 0;
107106 time_spent = Math.floor(time_spent / 1000);
@@ -1274,8 +1273,6 @@ export function initRossMods() {
12741273 }
12751274
12761275
1277-
1278-
12791276 if (event.ctrlKey && /^[1-9]$/.test(event.key)) {
12801277 // This will eventually be to trigger quick replies
12811278 // event.preventDefault();
public/scripts/autocomplete/AutoComplete.js+0 -5
@@ -80,8 +80,6 @@ export class AutoComplete {
8080 }
8181
8282
83-
84-
8583 /**
8684 * @param {HTMLTextAreaElement|HTMLInputElement} textarea The textarea to receive autocomplete.
8785 * @param {() => boolean} checkIfActivate Function should return true only if under the current conditions, autocomplete should display (e.g., for slash commands: autoComplete.text[0] == '/')
@@ -414,7 +412,6 @@ export class AutoComplete {
414412 });
415413
416414
417-
418415 if (this.isForceHidden) {
419416 // hidden with escape
420417 return this.hide();
@@ -465,7 +462,6 @@ export class AutoComplete {
465462 }
466463
467464
468-
469465 /**
470466 * Create updated DOM.
471467 */
@@ -514,7 +510,6 @@ export class AutoComplete {
514510 }
515511
516512
517-
518513 /**
519514 * Update position of DOM.
520515 */
public/scripts/autocomplete/AutoCompleteFuzzyScore.js+0 -3
@@ -1,6 +1,3 @@
1-
2-
3-
41export class AutoCompleteFuzzyScore {
52 /**@type {number}*/ start;
63 /**@type {number}*/ longestConsecutive;
public/scripts/autocomplete/AutoCompleteNameResult.js+0 -1
@@ -2,7 +2,6 @@ import { AutoCompleteNameResultBase } from './AutoCompleteNameResultBase.js';
22import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js';
33
44
5-
65export class AutoCompleteNameResult extends AutoCompleteNameResultBase {
76 /**
87 *
public/scripts/autocomplete/AutoCompleteNameResultBase.js+2 -3
@@ -1,14 +1,13 @@
11import { AutoCompleteOption } from './AutoCompleteOption.js';
22
33
4-
54export class AutoCompleteNameResultBase {
65 /**@type {string} */ name;
76 /**@type {number} */ start;
87 /**@type {AutoCompleteOption[]} */ optionList = [];
98 /**@type {boolean} */ canBeQuoted = false;
109 /**@type {()=>string} */ makeNoMatchText = () => `No matches found for "${this.name}"`;
1110 /**@type {()=>string} */ makeNoOptionsText = () => 'No options';
1211
1312
1413 /**
public/scripts/autocomplete/AutoCompleteOption.js+1 -2
@@ -1,7 +1,6 @@
11import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js';
22
33
4-
54export class AutoCompleteOption {
65 /** @type {string} */ name;
76 /** @type {string} */ typeIcon;
@@ -72,7 +71,7 @@ export class AutoCompleteOption {
7271 name.classList.add('name');
7372 name.classList.add('monospace');
7473 name.textContent = noSlash ? '' : '/';
7574 key.split('').forEach(char => {
7675 const span = document.createElement('span'); {
7776 span.textContent = char;
7877 name.append(span);
public/scripts/bulk-edit.js+1 -1
@@ -55,7 +55,7 @@ function onSelectAllButtonClick() {
5555
5656 if (!atLeastOneSelected) {
5757 // If none was selected, trigger click on all to deselect all of them
5858 for (const character of characters) {
5959 const checked = $(character).find('.bulk_select_checkbox:checked') ?? false;
6060 if (checked && character instanceof HTMLElement) {
6161 characterGroupOverlay.toggleSingleCharacter(character);
public/scripts/cfg-scale.js+0 -1
@@ -150,7 +150,6 @@ function onCfgMenuItemClick() {
150150 setTimeout(function () {
151151 $('#cfgConfig').hide();
152152 }, animation_duration);
153-
154153 }
155154 //duplicate options menu close handler from script.js
156155 //because this listener takes priority
public/scripts/chat-backups.js+1 -1
@@ -199,7 +199,7 @@ class BackupsBrowser {
199199 const deleteButton = document.createElement('div');
200200 deleteButton.classList.add('right_menu_button', 'fa-solid', 'fa-trash');
201201 deleteButton.title = t`Delete backup`;
202202 deleteButton.addEventListener('click', async () => {
203203 const isDeleted = await this.deleteBackup(backup.file_name);
204204 if (isDeleted) {
205205 listItem.remove();
public/scripts/data-maid.js+0 -1
@@ -251,7 +251,6 @@ class DataMaidDialog {
251251 categoryElement.remove();
252252 this.displayEmptyPlaceholder();
253253 });
254-
255254 });
256255 categoryElement.querySelectorAll('.dataMaidItemDelete').forEach(button => {
257256 button.addEventListener('click', async () => {
public/scripts/extensions/assets/index.js+1 -2
@@ -94,8 +94,7 @@ async function downloadAssetsList(url) {
9494 updateCurrentAssets().then(async function () {
9595 fetch(url, { cache: 'no-cache' })
9696 .then(response => response.json())
9797 .then(async function (json) {
98-
9998 availableAssets = {};
10099 $('#assets_menu').empty();
101100
public/scripts/extensions/expressions/index.js+1 -3
@@ -1414,7 +1414,6 @@ export async function getExpressionsList({ filterAvailable = false } = {}) {
14141414 });
14151415
14161416 if (apiResult.ok) {
1417-
14181417 const data = await apiResult.json();
14191418 expressionsList = data.labels;
14201419 return expressionsList;
@@ -1488,7 +1487,6 @@ function chooseSpriteForExpression(spriteFolderName, expression, { prevExpressio
14881487 }
14891488
14901489 return spriteFile;
1491-
14921490}
14931491
14941492/**
@@ -2333,7 +2331,7 @@ function migrateSettings() {
23332331 name: 'expression-folder-override',
23342332 aliases: ['spriteoverride', 'costume'],
23352333 callback: setSpriteFolderCommand,
23362334 namedArgumentList: [
23372335 SlashCommandNamedArgument.fromProps({
23382336 name: 'name',
23392337 description: 'Character name to set a subfolder for. If not provided, the character who last sent a message will be used.',
public/scripts/extensions/gallery/index.js+0 -1
@@ -791,7 +791,6 @@ async function listGalleryCommand(args) {
791791
792792 const items = await getGalleryItems(url);
793793 return JSON.stringify(items.map(it => it.src));
794-
795794 } catch (err) {
796795 console.error(err);
797796 }
public/scripts/extensions/quick-reply/api/QuickReplyApi.js+9 -15
@@ -10,22 +10,18 @@ export class QuickReplyApi {
1010 /** @type {SettingsUi} */ settingsUi;
1111
1212
13-
14-
1513 constructor(/** @type {QuickReplySettings} */settings, /** @type {SettingsUi} */settingsUi) {
1614 this.settings = settings;
1715 this.settingsUi = settingsUi;
1816 }
1917
2018
21-
22-
2319 /**
2420 * @param {QuickReply} qr
2521 * @returns {QuickReplySet}
2622 */
2723 getSetByQr(qr) {
2824 return QuickReplySet.list.find(it => it.qrList.includes(qr));
2925 }
3026
3127 /**
@@ -48,13 +44,11 @@ export class QuickReplyApi {
4844 getQrByLabel(setName, label) {
4945 const set = this.getSetByName(setName);
5046 if (!set) return;
5147 if (Number.isInteger(label)) return set.qrList.find(it => it.id == label);
5248 return set.qrList.find(it => it.label == label);
5349 }
5450
5551
56-
57-
5852 /**
5953 * Executes a quick reply by its index and returns the result.
6054 *
@@ -63,7 +57,7 @@ export class QuickReplyApi {
6357 */
6458 async executeQuickReplyByIndex(idx) {
6559 const qr = [...this.settings.config.setList, ...(this.settings.chatConfig?.setList ?? [])]
6660 .map(it => it.set.qrList)
6761 .flat()[idx]
6862 ;
6963 if (qr) {
@@ -400,7 +394,7 @@ export class QuickReplyApi {
400394 if (oldSet) {
401395 QuickReplySet.list.splice(QuickReplySet.list.indexOf(oldSet), 1, set);
402396 } else {
403397 const idx = QuickReplySet.list.findIndex(it => it.name.localeCompare(name) == 1);
404398 if (idx > -1) {
405399 QuickReplySet.list.splice(idx, 0, set);
406400 } else {
@@ -460,7 +454,7 @@ export class QuickReplyApi {
460454 * @returns array with the names of all quick reply sets
461455 */
462456 listSets() {
463457 return QuickReplySet.list.map(it => it.name);
464458 }
465459 /**
466460 * Gets a list of all globally active quick reply sets.
@@ -468,7 +462,7 @@ export class QuickReplyApi {
468462 * @returns array with the names of all quick reply sets
469463 */
470464 listGlobalSets() {
471465 return this.settings.config.setList.map(it => it.set.name);
472466 }
473467 /**
474468 * Gets a list of all quick reply sets activated by the current chat.
@@ -476,7 +470,7 @@ export class QuickReplyApi {
476470 * @returns array with the names of all quick reply sets
477471 */
478472 listChatSets() {
479473 return this.settings.chatConfig?.setList?.flatMap(it => it.set.name) ?? [];
480474 }
481475
482476 /**
@@ -490,7 +484,7 @@ export class QuickReplyApi {
490484 if (!set) {
491485 throw new Error(`No quick reply set with name "${name}" found.`);
492486 }
493487 return set.qrList.map(it => it.label);
494488 }
495489
496490 /**
public/scripts/extensions/quick-reply/index.js+13 -17
@@ -14,8 +14,6 @@ import { selected_group } from '../../group-chats.js';
1414export { debounceAsync };
1515
1616
17-
18-
1917const _VERBOSE = true;
2018export const debug = (...msg) => _VERBOSE ? console.debug('[QR2]', ...msg) : null;
2119export const log = (...msg) => _VERBOSE ? console.log('[QR2]', ...msg) : null;
@@ -54,8 +52,6 @@ let autoExec;
5452export let quickReplyApi;
5553
5654
57-
58-
5955const loadSets = async () => {
6056 const response = await fetch('/api/settings/get', {
6157 method: 'POST',
@@ -72,7 +68,7 @@ const loadSets = async () => {
7268 set.disableSend = set.quickActionEnabled ?? false;
7369 set.placeBeforeInput = set.placeBeforeInputEnabled ?? false;
7470 set.injectInput = set.AutoInputInject ?? false;
7571 set.qrList = set.quickReplySlots.map((slot, idx) => {
7672 const qr = {};
7773 qr.id = idx + 1;
7874 qr.label = slot.label ?? '';
@@ -87,7 +83,7 @@ const loadSets = async () => {
8783 qr.executeOnNewChat = slot.autoExecute_newChat ?? false;
8884 qr.executeBeforeGeneration = slot.autoExecute_beforeGeneration ?? false;
8985 qr.automationId = slot.automationId ?? '';
9086 qr.contextList = (slot.contextMenu ?? []).map(it => ({
9187 set: it.preset,
9288 isChained: it.chain,
9389 }));
@@ -99,8 +95,8 @@ const loadSets = async () => {
9995 }
10096 }
10197 // need to load QR lists after all sets are loaded to be able to resolve context menu entries
10298 setList.forEach((set, idx) => {
10399 QuickReplySet.list[idx].qrList = set.qrList.map(it => QuickReply.from(it));
104100 QuickReplySet.list[idx].init();
105101 });
106102 log('sets: ', QuickReplySet.list);
@@ -140,7 +136,7 @@ const executeIfReadyElseQueue = async (functionToCall, args) => {
140136 await functionToCall(...args);
141137 } else {
142138 log('queueing', { functionToCall, args });
143139 executeQueue.push(async () => await functionToCall(...args));
144140 }
145141};
146142
@@ -183,9 +179,9 @@ const init = async () => {
183179
184180 buttons = new ButtonUi(settings);
185181 buttons.show();
186182 settings.onSave = () => buttons.refresh();
187183
188184 globalThis.executeQuickReplyByName = async (name, args = {}, options = {}) => {
189185 let qr = [
190186 ...settings.config.setList,
191187 ...(settings.chatConfig?.setList ?? []),
@@ -193,14 +189,14 @@ const init = async () => {
193189 ]
194190 .map(it => it.set.qrList)
195191 .flat()
196192 .find(it => it.label == name)
197193 ;
198194 if (!qr) {
199195 let [setName, ...qrName] = name.split('.');
200196 qrName = qrName.join('.');
201197 let qrs = QuickReplySet.get(setName);
202198 if (qrs) {
203199 qr = qrs.qrList.find(it => it.label == qrName);
204200 }
205201 }
206202 if (qr && qr.onExecute) {
@@ -215,7 +211,7 @@ const init = async () => {
215211 slash.init();
216212 autoExec = new AutoExecuteHandler(settings);
217213
218214 eventSource.on(event_types.APP_READY, async () => await finalizeInit());
219215
220216 globalThis.quickReplyApi = quickReplyApi;
221217};
@@ -275,14 +271,14 @@ const onChatChanged = async (chatIdx) => {
275271
276272 await autoExec.handleChatChanged();
277273};
278274eventSource.on(event_types.CHAT_CHANGED, (...args) => executeIfReadyElseQueue(onChatChanged, args));
279275eventSource.on(event_types.CHARACTER_DELETED, purgeCharacterQuickReplySets);
280276eventSource.on(event_types.CHARACTER_RENAMED, updateCharacterQuickReplySets);
281277
282278const onUserMessage = async () => {
283279 await autoExec.handleUser();
284280};
285281eventSource.makeFirst(event_types.USER_MESSAGE_RENDERED, (...args) => executeIfReadyElseQueue(onUserMessage, args));
286282
287283const onAiMessage = async (messageId) => {
288284 if (['...'].includes(chat[messageId]?.mes)) {
@@ -292,7 +288,7 @@ const onAiMessage = async (messageId) => {
292288
293289 await autoExec.handleAi();
294290};
295291eventSource.makeFirst(event_types.CHARACTER_MESSAGE_RENDERED, (...args) => executeIfReadyElseQueue(onAiMessage, args));
296292
297293const onGroupMemberDraft = async () => {
298294 await autoExec.handleGroupMemberDraft();
public/scripts/extensions/quick-reply/src/AutoExecuteHandler.js+1 -5
@@ -8,8 +8,6 @@ export class AutoExecuteHandler {
88 /** @type {Boolean[]}*/ preventAutoExecuteStack = [];
99
1010
11-
12-
1311 constructor(/** @type {QuickReplySettings} */settings) {
1412 this.settings = settings;
1513 }
@@ -20,13 +18,11 @@ export class AutoExecuteHandler {
2018 }
2119
2220
23-
24-
2521 async performAutoExecute(/** @type {QuickReply[]} */qrList) {
2622 for (const qr of qrList) {
2723 this.preventAutoExecuteStack.push(qr.preventAutoExecute);
2824 try {
2925 await qr.execute({ isAutoExecute: true });
3026 } catch (ex) {
3127 warn(ex);
3228 } finally {
public/scripts/extensions/quick-reply/src/QuickReply.js+104 -114
@@ -22,13 +22,11 @@ export class QuickReply {
2222 * @param {{ id?: number; contextList?: any; }} props
2323 */
2424 static from(props) {
2525 props.contextList = (props.contextList ?? []).map((/** @type {any} */ it) => QuickReplyContextLink.from(it));
2626 return Object.assign(new this(), props);
2727 }
2828
2929
30-
31-
3230 /**@type {number}*/ id;
3331 /**@type {string}*/ icon;
3432 /**@type {string}*/ label = '';
@@ -89,8 +87,6 @@ export class QuickReply {
8987 }
9088
9189
92-
93-
9490 unrender() {
9591 this.dom?.remove();
9692 this.dom = null;
@@ -129,7 +125,7 @@ export class QuickReply {
129125 menu.show(evt);
130126 }
131127 });
132128 root.addEventListener('click', (evt) => {
133129 if (evt.ctrlKey) {
134130 this.showEditor();
135131 return;
@@ -169,8 +165,6 @@ export class QuickReply {
169165 }
170166
171167
172-
173-
174168 renderSettings(idx) {
175169 if (!this.settingsDom) {
176170 const item = document.createElement('div'); {
@@ -190,7 +184,7 @@ export class QuickReply {
190184 addNew.classList.add('fa-solid');
191185 addNew.classList.add('fa-plus');
192186 addNew.title = 'Add quick reply';
193187 addNew.addEventListener('click', () => this.onInsertBefore());
194188 actions.append(addNew);
195189 }
196190 const paste = document.createElement('div'); {
@@ -201,7 +195,7 @@ export class QuickReply {
201195 paste.classList.add('fa-solid');
202196 paste.classList.add('fa-paste');
203197 paste.title = 'Add quick reply from clipboard';
204198 paste.addEventListener('click', async () => {
205199 const text = await navigator.clipboard.readText();
206200 this.onInsertBefore(text);
207201 });
@@ -215,11 +209,11 @@ export class QuickReply {
215209 importFile.classList.add('fa-solid');
216210 importFile.classList.add('fa-file-import');
217211 importFile.title = 'Add quick reply from JSON file';
218212 importFile.addEventListener('click', async () => {
219213 const inp = document.createElement('input'); {
220214 inp.type = 'file';
221215 inp.accept = '.json';
222216 inp.addEventListener('change', async () => {
223217 if (inp.files.length > 0) {
224218 for (const file of inp.files) {
225219 const text = await file.text();
@@ -256,7 +250,7 @@ export class QuickReply {
256250 icon.classList.add('fa-solid');
257251 icon.classList.add(this.icon);
258252 }
259253 icon.addEventListener('click', async () => {
260254 let value = await showFontAwesomePicker();
261255 this.updateIcon(value);
262256 });
@@ -267,7 +261,7 @@ export class QuickReply {
267261 lbl.classList.add('qr--set-itemLabel');
268262 lbl.classList.add('text_pole');
269263 lbl.value = this.label;
270264 lbl.addEventListener('input', () => this.updateLabel(lbl.value));
271265 lblContainer.append(lbl);
272266 }
273267 itemContent.append(lblContainer);
@@ -283,7 +277,7 @@ export class QuickReply {
283277 opt.classList.add('fa-solid');
284278 opt.textContent = '⁝';
285279 opt.title = 'Additional options:\n - large editor\n - context menu\n - auto-execution\n - tooltip';
286280 opt.addEventListener('click', () => this.showEditor());
287281 optContainer.append(opt);
288282 }
289283 itemContent.append(optContainer);
@@ -294,7 +288,7 @@ export class QuickReply {
294288 mes.classList.add('qr--set-itemMessage');
295289 mes.value = this.message;
296290 //HACK need to use jQuery to catch the triggered event from the expanded editor
297291 $(mes).on('input', () => this.updateMessage(mes.value));
298292 itemContent.append(mes);
299293 }
300294 const actions = document.createElement('div'); {
@@ -306,7 +300,7 @@ export class QuickReply {
306300 move.classList.add('fa-solid');
307301 move.classList.add('fa-truck-arrow-right');
308302 move.title = 'Move quick reply to other set';
309303 move.addEventListener('click', () => this.onTransfer(this));
310304 actions.append(move);
311305 }
312306 const copy = document.createElement('div'); {
@@ -316,7 +310,7 @@ export class QuickReply {
316310 copy.classList.add('fa-solid');
317311 copy.classList.add('fa-copy');
318312 copy.title = 'Copy quick reply to clipboard';
319313 copy.addEventListener('click', async () => {
320314 await navigator.clipboard.writeText(JSON.stringify(this));
321315 copy.classList.add('qr--success');
322316 await delay(3010);
@@ -331,7 +325,7 @@ export class QuickReply {
331325 cut.classList.add('fa-solid');
332326 cut.classList.add('fa-cut');
333327 cut.title = 'Cut quick reply to clipboard (copy and remove)';
334328 cut.addEventListener('click', async () => {
335329 await navigator.clipboard.writeText(JSON.stringify(this));
336330 this.delete();
337331 });
@@ -344,8 +338,8 @@ export class QuickReply {
344338 exp.classList.add('fa-solid');
345339 exp.classList.add('fa-file-export');
346340 exp.title = 'Export quick reply as file';
347341 exp.addEventListener('click', () => {
348342 const blob = new Blob([JSON.stringify(this)], { type: 'text' });
349343 const url = URL.createObjectURL(blob);
350344 const a = document.createElement('a'); {
351345 a.href = url;
@@ -363,7 +357,7 @@ export class QuickReply {
363357 del.classList.add('fa-trash-can');
364358 del.classList.add('redWarningBG');
365359 del.title = 'Remove Quick Reply\n---\nShift+Click to skip confirmation';
366360 del.addEventListener('click', async (evt) => {
367361 if (!evt.shiftKey) {
368362 const result = await Popup.show.confirm(
369363 'Remove Quick Reply',
@@ -408,7 +402,7 @@ export class QuickReply {
408402 else {
409403 icon.textContent = '…';
410404 }
411405 icon.addEventListener('click', async () => {
412406 let value = await showFontAwesomePicker();
413407 if (value === null) return;
414408 if (this.icon) icon.classList.remove(this.icon);
@@ -425,18 +419,18 @@ export class QuickReply {
425419 /**@type {HTMLInputElement}*/
426420 const showLabel = dom.querySelector('#qr--modal-showLabel');
427421 showLabel.checked = this.showLabel;
428422 showLabel.addEventListener('click', () => {
429423 this.updateShowLabel(showLabel.checked);
430424 });
431425 /**@type {HTMLInputElement}*/
432426 const label = dom.querySelector('#qr--modal-label');
433427 label.value = this.label;
434428 label.addEventListener('input', () => {
435429 this.updateLabel(label.value);
436430 });
437431 let switcherList;
438432 // @ts-ignore
439433 dom.querySelector('#qr--modal-switcher').addEventListener('click', (evt) => {
440434 if (switcherList) {
441435 switcherList.remove();
442436 switcherList = null;
@@ -445,15 +439,15 @@ export class QuickReply {
445439 const list = document.createElement('ul'); {
446440 switcherList = list;
447441 list.classList.add('qr--modal-switcherList');
448442 const makeList = (qrs) => {
449443 const setItem = document.createElement('li'); {
450444 setItem.classList.add('qr--modal-switcherItem');
451445 setItem.addEventListener('click', () => {
452446 list.innerHTML = '';
453447 for (const qrs of quickReplyApi.listSets()) {
454448 const item = document.createElement('li'); {
455449 item.classList.add('qr--modal-switcherItem');
456450 item.addEventListener('click', () => {
457451 list.innerHTML = '';
458452 makeList(quickReplyApi.getSetByName(qrs));
459453 });
@@ -484,7 +478,7 @@ export class QuickReply {
484478 }
485479 const addItem = document.createElement('li'); {
486480 addItem.classList.add('qr--modal-switcherItem');
487481 addItem.addEventListener('click', () => {
488482 const qr = quickReplyApi.getSetByQr(this).addQuickReply();
489483 this.editorPopup.completeAffirmative();
490484 qr.showEditor();
@@ -505,11 +499,11 @@ export class QuickReply {
505499 }
506500 list.append(addItem);
507501 }
508502 for (const qr of qrs.qrList.toSorted((a, b) => a.label.toLowerCase().localeCompare(b.label.toLowerCase()))) {
509503 const item = document.createElement('li'); {
510504 item.classList.add('qr--modal-switcherItem');
511505 if (qr == this) item.classList.add('qr--current');
512506 else item.addEventListener('click', () => {
513507 this.editorPopup.completeAffirmative();
514508 qr.showEditor();
515509 });
@@ -588,7 +582,7 @@ export class QuickReply {
588582 });
589583 };
590584 const updateScrollDebounced = updateScroll;
591585 const updateSyntaxEnabled = () => {
592586 if (syntax.checked) {
593587 dom.querySelector('#qr--modal-messageHolder').classList.remove('qr--noSyntax');
594588 } else {
@@ -623,7 +617,7 @@ export class QuickReply {
623617 // @ts-ignore
624618 if (navigator.keyboard) {
625619 // @ts-ignore
626620 navigator.keyboard.getLayoutMap().then(it => dom.querySelector('#qr--modal-commentKey').textContent = it.get('Backslash'));
627621 } else {
628622 dom.querySelector('#qr--modal-commentKey').closest('small').remove();
629623 }
@@ -632,12 +626,12 @@ export class QuickReply {
632626 const message = dom.querySelector('#qr--modal-message');
633627 this.editorMessage = message;
634628 message.value = this.message;
635629 const updateMessageDebounced = debounce((value) => this.updateMessage(value), 10);
636630 message.addEventListener('input', () => {
637631 updateMessageDebounced(message.value);
638632 updateScrollDebounced();
639633 }, { passive: true });
640634 const getLineStart = () => {
641635 const start = message.selectionStart;
642636 let lineStart;
643637 if (start == 0 || message.value[start - 1] == '\n') {
@@ -651,7 +645,7 @@ export class QuickReply {
651645 }
652646 return lineStart;
653647 };
654648 message.addEventListener('keydown', async (evt) => {
655649 if (this.isExecuting) return;
656650 if (evt.key == 'Tab' && !evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
657651 // increase indent
@@ -668,13 +662,13 @@ export class QuickReply {
668662 document.execCommand('insertText', false, `\t${affectedLines.join('\n\t')}`);
669663 message.selectionStart = start + 1;
670664 message.selectionEnd = end + affectedLines.length;
671665 message.dispatchEvent(new Event('input', { bubbles: true }));
672666 } else if (!(ac.isReplaceable && ac.isActive)) {
673667 evt.stopImmediatePropagation();
674668 evt.stopPropagation();
675669 // document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
676670 document.execCommand('insertText', false, '\t');
677671 message.dispatchEvent(new Event('input', { bubbles: true }));
678672 }
679673 } else if (evt.key == 'Tab' && evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
680674 // decrease indent
@@ -686,7 +680,7 @@ export class QuickReply {
686680 const lineStart = getLineStart();
687681 message.selectionStart = lineStart;
688682 const affectedLines = message.value.substring(lineStart, end).split('\n');
689683 const newText = affectedLines.map(it => it.replace(/^\t/, '')).join('\n');
690684 const delta = affectedLines.join('\n').length - newText.length;
691685 // document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
692686 if (delta > 0) {
@@ -697,7 +691,7 @@ export class QuickReply {
697691 }
698692 message.selectionStart = start - (affectedLines[0].startsWith('\t') ? 1 : 0);
699693 message.selectionEnd = end - delta;
700694 message.dispatchEvent(new Event('input', { bubbles: true }));
701695 } else {
702696 message.selectionStart = start;
703697 }
@@ -714,7 +708,7 @@ export class QuickReply {
714708 document.execCommand('insertText', false, `\n${indent}`);
715709 message.selectionStart = start + 1 + indent.length;
716710 message.selectionEnd = message.selectionStart;
717711 message.dispatchEvent(new Event('input', { bubbles: true }));
718712 }
719713 } else if (evt.key == 'Enter' && evt.ctrlKey && !evt.shiftKey && !evt.altKey) {
720714 if (executeShortcut.checked) {
@@ -751,7 +745,7 @@ export class QuickReply {
751745 parser.parse(message.value, false);
752746 const start = message.selectionStart;
753747 const end = message.selectionEnd;
754748 const comment = parser.commandIndex.findLast(it => it.name == '*' && (it.start <= start && it.end >= start || it.start <= end && it.end >= end));
755749 if (comment) {
756750 // uncomment
757751 let content = message.value.slice(comment.start + 1, comment.end - 1);
@@ -778,15 +772,15 @@ export class QuickReply {
778772 message.selectionStart = start + 3;
779773 message.selectionEnd = end + 3;
780774 }
781775 message.dispatchEvent(new Event('input', { bubbles: true }));
782776 }
783777 });
784778 const ac = await setSlashCommandAutoComplete(message, true);
785779 message.addEventListener('wheel', (evt) => {
786780 updateScrollDebounced(evt);
787781 });
788782 // @ts-ignore
789783 message.addEventListener('scroll', (evt) => {
790784 updateScrollDebounced();
791785 });
792786 let preBreakPointStart;
@@ -794,7 +788,7 @@ export class QuickReply {
794788 /**
795789 * @param {SlashCommandBreakPoint} bp
796790 */
797791 const removeBreakpoint = (bp) => {
798792 // start at -1 because "/" is not included in start-end
799793 let start = bp.start - 1;
800794 // step left until forward slash "/"
@@ -812,7 +806,7 @@ export class QuickReply {
812806 message.selectionEnd = end;
813807 // document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
814808 document.execCommand('insertText', false, '');
815809 message.dispatchEvent(new Event('input', { bubbles: true }));
816810 let postStart = preBreakPointStart;
817811 let postEnd = preBreakPointEnd;
818812 // set caret back to where it was
@@ -834,12 +828,12 @@ export class QuickReply {
834828 // selection end was behind breakpoint: move back by length of removed string
835829 postEnd = preBreakPointEnd - (end - start);
836830 }
837831 return { start: postStart, end: postEnd };
838832 };
839833 /**
840834 * @param {SlashCommandExecutor} cmd
841835 */
842836 const addBreakpoint = (cmd) => {
843837 // start at -1 because "/" is not included in start-end
844838 let start = cmd.start - 1;
845839 let indent = '';
@@ -860,16 +854,16 @@ export class QuickReply {
860854 message.selectionEnd = start;
861855 // document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
862856 document.execCommand('insertText', false, breakpointText);
863857 message.dispatchEvent(new Event('input', { bubbles: true }));
864858 return breakpointText.length;
865859 };
866860 const toggleBreakpoint = () => {
867861 const idx = message.selectionStart;
868862 let postStart = preBreakPointStart;
869863 let postEnd = preBreakPointEnd;
870864 const parser = new SlashCommandParser();
871865 parser.parse(message.value, false);
872866 const cmdIdx = parser.commandIndex.findLastIndex(it => it.start <= idx);
873867 if (cmdIdx > -1) {
874868 const cmd = parser.commandIndex[cmdIdx];
875869 if (cmd instanceof SlashCommandBreakPoint) {
@@ -891,12 +885,12 @@ export class QuickReply {
891885 message.selectionEnd = postEnd;
892886 }
893887 };
894888 message.addEventListener('pointerdown', (evt) => {
895889 if (!evt.ctrlKey || !evt.altKey) return;
896890 preBreakPointStart = message.selectionStart;
897891 preBreakPointEnd = message.selectionEnd;
898892 });
899893 message.addEventListener('pointerup', async (evt) => {
900894 if (!evt.ctrlKey || !evt.altKey || message.selectionStart != message.selectionEnd) return;
901895 toggleBreakpoint();
902896 });
@@ -910,11 +904,11 @@ export class QuickReply {
910904 });
911905 window.addEventListener('resize', resizeListener);
912906 updateSyntaxEnabled();
913907 const updateSyntax = () => {
914908 if (messageSyntaxInner && syntax.checked) {
915909 morphdom(
916910 messageSyntaxInner,
917911 `<div>${hljs.highlight(`${message.value}${message.value.slice(-1) == '\n' ? ' ' : ''}`, { language: 'stscript', ignoreIllegals: true })?.value}</div>`,
918912 { childrenOnly: true },
919913 );
920914 updateScrollDebounced();
@@ -924,7 +918,7 @@ export class QuickReply {
924918 const fpsTime = 1000 / 30;
925919 let lastMessageValue = null;
926920 let wasSyntax = null;
927921 const updateSyntaxLoop = () => {
928922 const now = Date.now();
929923 // fps limit
930924 if (now - lastSyntaxUpdate < fpsTime) return requestAnimationFrame(updateSyntaxLoop);
@@ -945,7 +939,7 @@ export class QuickReply {
945939 updateSyntax();
946940 requestAnimationFrame(updateSyntaxLoop);
947941 };
948942 requestAnimationFrame(() => updateSyntaxLoop());
949943 message.style.setProperty('text-shadow', 'none', 'important');
950944 updateWrap();
951945 updateTabSize();
@@ -955,7 +949,7 @@ export class QuickReply {
955949 const tpl = dom.querySelector('#qr--ctxItem');
956950 const linkList = dom.querySelector('#qr--ctxEditor');
957951 const fillQrSetSelect = (/**@type {HTMLSelectElement}*/select, /**@type {QuickReplyContextLink}*/ link) => {
958952 [{ name: 'Select a QR set' }, ...QuickReplySet.list.toSorted((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()))].forEach(qrs => {
959953 const opt = document.createElement('option'); {
960954 opt.value = qrs.name;
961955 opt.textContent = qrs.name;
@@ -1002,7 +996,7 @@ export class QuickReply {
1002996 addCtxItem(link, this.contextList.length - 1);
1003997 });
1004998 const onContextSort = () => {
1005999 this.contextList = Array.from(linkList.querySelectorAll('.qr--ctxItem')).map((it, idx) => {
10061000 const link = this.contextList[Number(it.getAttribute('data-order'))];
10071001 it.setAttribute('data-order', String(idx));
10081002 return link;
@@ -1019,63 +1013,63 @@ export class QuickReply {
10191013 /**@type {HTMLInputElement}*/
10201014 const preventAutoExecute = dom.querySelector('#qr--preventAutoExecute');
10211015 preventAutoExecute.checked = this.preventAutoExecute;
10221016 preventAutoExecute.addEventListener('click', () => {
10231017 this.preventAutoExecute = preventAutoExecute.checked;
10241018 this.updateContext();
10251019 });
10261020 /**@type {HTMLInputElement}*/
10271021 const isHidden = dom.querySelector('#qr--isHidden');
10281022 isHidden.checked = this.isHidden;
10291023 isHidden.addEventListener('click', () => {
10301024 this.isHidden = isHidden.checked;
10311025 this.updateContext();
10321026 });
10331027 /**@type {HTMLInputElement}*/
10341028 const executeOnStartup = dom.querySelector('#qr--executeOnStartup');
10351029 executeOnStartup.checked = this.executeOnStartup;
10361030 executeOnStartup.addEventListener('click', () => {
10371031 this.executeOnStartup = executeOnStartup.checked;
10381032 this.updateContext();
10391033 });
10401034 /**@type {HTMLInputElement}*/
10411035 const executeOnUser = dom.querySelector('#qr--executeOnUser');
10421036 executeOnUser.checked = this.executeOnUser;
10431037 executeOnUser.addEventListener('click', () => {
10441038 this.executeOnUser = executeOnUser.checked;
10451039 this.updateContext();
10461040 });
10471041 /**@type {HTMLInputElement}*/
10481042 const executeOnAi = dom.querySelector('#qr--executeOnAi');
10491043 executeOnAi.checked = this.executeOnAi;
10501044 executeOnAi.addEventListener('click', () => {
10511045 this.executeOnAi = executeOnAi.checked;
10521046 this.updateContext();
10531047 });
10541048 /**@type {HTMLInputElement}*/
10551049 const executeOnChatChange = dom.querySelector('#qr--executeOnChatChange');
10561050 executeOnChatChange.checked = this.executeOnChatChange;
10571051 executeOnChatChange.addEventListener('click', () => {
10581052 this.executeOnChatChange = executeOnChatChange.checked;
10591053 this.updateContext();
10601054 });
10611055 /**@type {HTMLInputElement}*/
10621056 const executeOnGroupMemberDraft = dom.querySelector('#qr--executeOnGroupMemberDraft');
10631057 executeOnGroupMemberDraft.checked = this.executeOnGroupMemberDraft;
10641058 executeOnGroupMemberDraft.addEventListener('click', () => {
10651059 this.executeOnGroupMemberDraft = executeOnGroupMemberDraft.checked;
10661060 this.updateContext();
10671061 });
10681062 /**@type {HTMLInputElement}*/
10691063 const executeBeforeGeneration = dom.querySelector('#qr--executeBeforeGeneration');
10701064 executeBeforeGeneration.checked = this.executeBeforeGeneration;
10711065 executeBeforeGeneration.addEventListener('click', () => {
10721066 this.executeBeforeGeneration = executeBeforeGeneration.checked;
10731067 this.updateContext();
10741068 });
10751069 /**@type {HTMLInputElement}*/
10761070 const executeOnNewChat = dom.querySelector('#qr--executeOnNewChat');
10771071 executeOnNewChat.checked = this.executeOnNewChat;
10781072 executeOnNewChat.addEventListener('click', () => {
10791073 this.executeOnNewChat = executeOnNewChat.checked;
10801074 this.updateContext();
10811075 });
@@ -1102,13 +1096,13 @@ export class QuickReply {
11021096 /**@type {HTMLElement}*/
11031097 const executeBtn = dom.querySelector('#qr--modal-execute');
11041098 this.editorExecuteBtn = executeBtn;
11051099 executeBtn.addEventListener('click', async () => {
11061100 await this.executeFromEditor();
11071101 });
11081102 /**@type {HTMLElement}*/
11091103 const executeBtnPause = dom.querySelector('#qr--modal-pause');
11101104 this.editorExecuteBtnPause = executeBtnPause;
11111105 executeBtnPause.addEventListener('click', async () => {
11121106 if (this.abortController) {
11131107 if (this.abortController.signal.paused) {
11141108 this.abortController.continue('Continue button clicked');
@@ -1122,7 +1116,7 @@ export class QuickReply {
11221116 /**@type {HTMLElement}*/
11231117 const executeBtnStop = dom.querySelector('#qr--modal-stop');
11241118 this.editorExecuteBtnStop = executeBtnStop;
11251119 executeBtnStop.addEventListener('click', async () => {
11261120 this.abortController?.abort('Stop button clicked');
11271121 });
11281122
@@ -1131,49 +1125,49 @@ export class QuickReply {
11311125 const inputMirror = dom.querySelector('#qr--modal-send_textarea');
11321126 // @ts-ignore
11331127 inputMirror.value = inputOg.value;
11341128 const inputOgMo = new MutationObserver(muts => {
11351129 if (muts.find(it => [...it.removedNodes].includes(inputMirror) || [...it.removedNodes].find(n => n.contains(inputMirror)))) {
11361130 inputOg.removeEventListener('input', inputOgListener);
11371131 }
11381132 });
11391133 inputOgMo.observe(document.body, { childList: true });
11401134 const inputOgListener = () => {
11411135 // @ts-ignore
11421136 inputMirror.value = inputOg.value;
11431137 };
11441138 inputOg.addEventListener('input', inputOgListener);
11451139 inputMirror.addEventListener('input', () => {
11461140 // @ts-ignore
11471141 inputOg.value = inputMirror.value;
11481142 });
11491143
11501144 /**@type {HTMLElement}*/
11511145 const resumeBtn = dom.querySelector('#qr--modal-resume');
11521146 resumeBtn.addEventListener('click', () => {
11531147 this.debugController?.resume();
11541148 });
11551149 /**@type {HTMLElement}*/
11561150 const stepBtn = dom.querySelector('#qr--modal-step');
11571151 stepBtn.addEventListener('click', () => {
11581152 this.debugController?.step();
11591153 });
11601154 /**@type {HTMLElement}*/
11611155 const stepIntoBtn = dom.querySelector('#qr--modal-stepInto');
11621156 stepIntoBtn.addEventListener('click', () => {
11631157 this.debugController?.stepInto();
11641158 });
11651159 /**@type {HTMLElement}*/
11661160 const stepOutBtn = dom.querySelector('#qr--modal-stepOut');
11671161 stepOutBtn.addEventListener('click', () => {
11681162 this.debugController?.stepOut();
11691163 });
11701164 /**@type {HTMLElement}*/
11711165 const minimizeBtn = dom.querySelector('#qr--modal-minimize');
11721166 minimizeBtn.addEventListener('click', () => {
11731167 this.editorDom.classList.add('qr--minimized');
11741168 });
11751169 const maximizeBtn = dom.querySelector('#qr--modal-maximize');
11761170 maximizeBtn.addEventListener('click', () => {
11771171 this.editorDom.classList.remove('qr--minimized');
11781172 });
11791173 /**@type {boolean}*/
@@ -1182,23 +1176,23 @@ export class QuickReply {
11821176 let wStart;
11831177 /**@type {HTMLElement}*/
11841178 const resizeHandle = dom.querySelector('#qr--resizeHandle');
11851179 resizeHandle.addEventListener('pointerdown', (evt) => {
11861180 if (isResizing) return;
11871181 isResizing = true;
11881182 evt.preventDefault();
11891183 resizeStart = evt.x;
11901184 // @ts-ignore
11911185 wStart = dom.querySelector('#qr--qrOptions').offsetWidth;
11921186 const dragListener = debounce((evt) => {
11931187 const w = wStart + resizeStart - evt.x;
11941188 // @ts-ignore
11951189 dom.querySelector('#qr--qrOptions').style.setProperty('--width', `${w}px`);
11961190 }, 5);
11971191 window.addEventListener('pointerup', () => {
11981192 // @ts-ignore
11991193 window.removeEventListener('pointermove', dragListener);
12001194 isResizing = false;
12011195 }, { once: true });
12021196 // @ts-ignore
12031197 window.addEventListener('pointermove', dragListener);
12041198 });
@@ -1221,13 +1215,13 @@ export class QuickReply {
12211215 }
12221216 this.clone.style.position = 'fixed';
12231217 this.clone.style.visibility = 'hidden';
12241218 const mo = new MutationObserver(muts => {
12251219 if (muts.find(it => [...it.removedNodes].includes(this.editorMessage) || [...it.removedNodes].find(n => n.contains(this.editorMessage)))) {
12261220 this.clone?.remove();
12271221 this.clone = null;
12281222 }
12291223 });
12301224 mo.observe(document.body, { childList: true });
12311225 }
12321226 document.body.append(this.clone);
12331227 this.clone.style.width = `${inputRect.width}px`;
@@ -1258,7 +1252,7 @@ export class QuickReply {
12581252 }
12591253 async executeFromEditor() {
12601254 if (this.isExecuting) return;
12611255 this.editorPopup.onClosing = () => false;
12621256 const uuidCheck = /^[0-9a-z]{8}(-[0-9a-z]{4}){3}-[0-9a-z]{12}$/;
12631257 const oText = this.message;
12641258 this.isExecuting = true;
@@ -1298,19 +1292,19 @@ export class QuickReply {
12981292 });
12991293 };
13001294 const updateScrollDebounced = updateScroll;
13011295 syntax.addEventListener('wheel', (evt) => {
13021296 updateScrollDebounced(evt);
13031297 });
13041298 // @ts-ignore
13051299 syntax.addEventListener('scroll', (evt) => {
13061300 updateScrollDebounced();
13071301 });
13081302 try {
13091303 this.abortController = new SlashCommandAbortController();
13101304 this.debugController = new SlashCommandDebugController();
13111305 this.debugController.onBreakPoint = async (closure, executor) => {
13121306 this.editorDom.classList.add('qr--isPaused');
13131307 syntax.innerHTML = hljs.highlight(`${closure.fullText}${closure.fullText.slice(-1) == '\n' ? ' ' : ''}`, { language: 'stscript', ignoreIllegals: true })?.value;
13141308 this.editorMessageLabel.innerHTML = '';
13151309 if (uuidCheck.test(closure.source)) {
13161310 const p0 = document.createElement('span'); {
@@ -1318,7 +1312,7 @@ export class QuickReply {
13181312 this.editorMessageLabel.append(p0);
13191313 }
13201314 const p1 = document.createElement('strong'); {
13211315 p1.textContent = executor.source.slice(0, 5);
13221316 this.editorMessageLabel.append(p1);
13231317 }
13241318 const p2 = document.createElement('span'); {
@@ -1340,7 +1334,7 @@ export class QuickReply {
13401334 /**
13411335 * @param {SlashCommandScope} scope
13421336 */
13431337 const buildVars = (scope, isCurrent = false) => {
13441338 if (!isCurrent) {
13451339 ci--;
13461340 }
@@ -1358,7 +1352,7 @@ export class QuickReply {
13581352 }
13591353 wrap.append(namedTitle);
13601354 }
13611355 const keys = new Set([...Object.keys(this.debugController.namedArguments ?? {}), ...(executor.namedArgumentList ?? []).map(it => it.name)]);
13621356 for (const key of keys) {
13631357 if (key[0] == '_') continue;
13641358 const item = document.createElement('div'); {
@@ -1371,7 +1365,7 @@ export class QuickReply {
13711365 const vUnresolved = document.createElement('div'); {
13721366 vUnresolved.classList.add('qr--val');
13731367 vUnresolved.classList.add('qr--singleCol');
13741368 const val = executor.namedArgumentList.find(it => it.name == key)?.value;
13751369 if (val instanceof SlashCommandClosure) {
13761370 vUnresolved.classList.add('qr--closure');
13771371 vUnresolved.title = val.rawText;
@@ -1437,7 +1431,7 @@ export class QuickReply {
14371431 // @ts-ignore
14381432 while (unnamed.length < executor.unnamedArgumentList?.length ?? 0) unnamed.push(undefined);
14391433 // @ts-ignore
14401434 unnamed = unnamed.map((it, idx) => [executor.unnamedArgumentList?.[idx], it]);
14411435 // @ts-ignore
14421436 for (const arg of unnamed) {
14431437 i++;
@@ -1511,7 +1505,7 @@ export class QuickReply {
15111505 title.textContent = isCurrent ? 'Current Scope' : 'Parent Scope';
15121506 if (c.source == source) {
15131507 let hi;
15141508 title.addEventListener('pointerenter', () => {
15151509 const loc = this.getEditorPosition(Math.max(0, c.executorList[0].start - 1), c.executorList.slice(-1)[0].end, c.fullText);
15161510 const layer = syntax.getBoundingClientRect();
15171511 hi = document.createElement('div');
@@ -1522,7 +1516,7 @@ export class QuickReply {
15221516 hi.style.height = `${loc.bottom - loc.top}px`;
15231517 syntax.append(hi);
15241518 });
15251519 title.addEventListener('pointerleave', () => hi?.remove());
15261520 }
15271521 wrap.append(title);
15281522 }
@@ -1635,7 +1629,7 @@ export class QuickReply {
16351629 }
16361630 return wrap;
16371631 };
16381632 const buildStack = () => {
16391633 const wrap = document.createElement('div'); {
16401634 wrap.classList.add('qr--stack');
16411635 const title = document.createElement('div'); {
@@ -1651,7 +1645,7 @@ export class QuickReply {
16511645 item.classList.add('qr--item');
16521646 if (executor.source == source) {
16531647 let hi;
16541648 item.addEventListener('pointerenter', () => {
16551649 const loc = this.getEditorPosition(Math.max(0, executor.start - 1), executor.end, c.fullText);
16561650 const layer = syntax.getBoundingClientRect();
16571651 hi = document.createElement('div');
@@ -1662,7 +1656,7 @@ export class QuickReply {
16621656 hi.style.height = `${loc.bottom - loc.top}px`;
16631657 syntax.append(hi);
16641658 });
16651659 item.addEventListener('pointerleave', () => hi?.remove());
16661660 }
16671661 const cmd = document.createElement('div'); {
16681662 cmd.classList.add('qr--cmd');
@@ -1678,7 +1672,7 @@ export class QuickReply {
16781672 if (uuidCheck.test(executor.source)) {
16791673 const p1 = document.createElement('span'); {
16801674 p1.classList.add('qr--fixed');
16811675 p1.textContent = executor.source.slice(0, 5);
16821676 src.append(p1);
16831677 }
16841678 const p2 = document.createElement('span'); {
@@ -1756,7 +1750,7 @@ export class QuickReply {
17561750 this.editorMessageLabel.innerHTML = '';
17571751 this.editorMessageLabel.textContent = 'Message / Command: ';
17581752 this.editorMessage.value = oText;
17591753 this.editorMessage.dispatchEvent(new Event('input', { bubbles: true }));
17601754 this.editorExecutePromise = null;
17611755 this.editorExecuteBtn.classList.remove('qr--busy');
17621756 this.editorDom.classList.remove('qr--isExecuting');
@@ -1769,8 +1763,6 @@ export class QuickReply {
17691763 }
17701764
17711765
1772-
1773-
17741766 delete() {
17751767 if (this.onDelete) {
17761768 this.unrender();
@@ -1870,7 +1862,7 @@ export class QuickReply {
18701862 this.updateContext();
18711863 }
18721864 removeContextLink(setName) {
18731865 const idx = this.contextList.findIndex(it => it.set.name == setName);
18741866 if (idx > -1) {
18751867 this.contextList.splice(idx, 1);
18761868 this.updateContext();
@@ -1908,8 +1900,6 @@ export class QuickReply {
19081900 }
19091901
19101902
1911-
1912-
19131903 toJSON() {
19141904 return {
19151905 id: this.id,
public/scripts/extensions/quick-reply/src/QuickReplyConfig.js+12 -20
@@ -13,25 +13,21 @@ export class QuickReplyConfig {
1313 /**@type {HTMLElement}*/ setListDom;
1414
1515
16-
17-
1816 static from(props) {
1917 props.setList = props.setList?.map(it => QuickReplySetLink.from(it))?.filter(it => it.set) ?? [];
2018 const instance = Object.assign(new this(), props);
2119 instance.init();
2220 return instance;
2321 }
2422
2523
26-
27-
2824 init() {
2925 this.setList.forEach(it => this.hookQuickReplyLink(it));
3026 }
3127
3228
3329 hasSet(qrs) {
3430 return this.setList.find(it => it.set == qrs) != null;
3531 }
3632 addSet(qrs, isVisible = true) {
3733 if (!this.hasSet(qrs)) {
@@ -45,7 +41,7 @@ export class QuickReplyConfig {
4541 }
4642 }
4743 removeSet(qrs) {
4844 const idx = this.setList.findIndex(it => it.set == qrs);
4945 if (idx > -1) {
5046 this.setList.splice(idx, 1);
5147 this.update();
@@ -54,13 +50,11 @@ export class QuickReplyConfig {
5450 }
5551
5652
57-
58-
5953 renderSettingsInto(/**@type {HTMLElement}*/root) {
6054 /**@type {HTMLElement}*/
6155 this.setListDom = root.querySelector('.qr--setList');
6256 root.querySelector('.qr--setListAdd').addEventListener('click', () => {
6357 const newSet = QuickReplySet.list.find(qr => !this.setList.find(qrl => qrl.set == qr));
6458 if (newSet) {
6559 this.addSet(newSet);
6660 } else {
@@ -74,14 +68,14 @@ export class QuickReplyConfig {
7468 // @ts-ignore
7569 $(this.setListDom).sortable({
7670 delay: getSortableDelay(),
7771 stop: () => this.onSetListSort(),
7872 });
7973 this.setList.filter(it => !it.set.isDeleted).forEach((qrl, idx) => this.setListDom.append(qrl.renderSettings(idx)));
8074 }
8175
8276
8377 onSetListSort() {
8478 this.setList = Array.from(this.setListDom.children).map((it, idx) => {
8579 const qrl = this.setList[Number(it.getAttribute('data-order'))];
8680 qrl.index = idx;
8781 it.setAttribute('data-order', String(idx));
@@ -91,15 +85,13 @@ export class QuickReplyConfig {
9185 }
9286
9387
94-
95-
9688 /**
9789 * @param {QuickReplySetLink} qrl
9890 */
9991 hookQuickReplyLink(qrl) {
10092 qrl.onDelete = () => this.deleteQuickReplyLink(qrl);
10193 qrl.onUpdate = () => this.update();
10294 qrl.onRequestEditSet = () => this.requestEditSet(qrl.set);
10395 }
10496
10597 deleteQuickReplyLink(qrl) {
public/scripts/extensions/quick-reply/src/QuickReplyContextLink.js+0 -2
@@ -8,8 +8,6 @@ export class QuickReplyContextLink {
88 }
99
1010
11-
12-
1311 /**@type {QuickReplySet}*/ set;
1412 /**@type {Boolean}*/ isChained = false;
1513
public/scripts/extensions/quick-reply/src/QuickReplySet.js+25 -26
@@ -24,7 +24,7 @@ export class QuickReplySet {
2424 * @param {string} name - name of the QuickReplySet
2525 */
2626 static get(name) {
2727 return this.list.find(it => it.name == name);
2828 }
2929
3030 /**@type {string}*/ name;
@@ -42,11 +42,11 @@ export class QuickReplySet {
4242 /**@type {HTMLElement}*/ settingsDom;
4343
4444 constructor() {
4545 this.save = debounceAsync(() => this.performSave(), 200);
4646 }
4747
4848 init() {
4949 this.qrList.forEach(qr => this.hookQuickReply(qr));
5050 }
5151
5252 unrender() {
@@ -60,7 +60,7 @@ export class QuickReplySet {
6060 this.dom = root;
6161 root.classList.add('qr--buttons');
6262 this.updateColor();
6363 this.qrList.filter(qr => !qr.isHidden).forEach(qr => {
6464 root.append(qr.render());
6565 });
6666 }
@@ -70,7 +70,7 @@ export class QuickReplySet {
7070 rerender() {
7171 if (!this.dom) return;
7272 this.dom.innerHTML = '';
7373 this.qrList.filter(qr => !qr.isHidden).forEach(qr => {
7474 this.dom.append(qr.render());
7575 });
7676 }
@@ -95,7 +95,7 @@ export class QuickReplySet {
9595 if (!this.settingsDom) {
9696 this.settingsDom = document.createElement('div'); {
9797 this.settingsDom.classList.add('qr--set-qrListContents');
9898 this.qrList.forEach((qr, idx) => {
9999 this.renderSettingsItem(qr, idx);
100100 });
101101 }
@@ -138,12 +138,12 @@ export class QuickReplySet {
138138 */
139139 async executeWithOptions(qr, options = {}) {
140140 options = Object.assign({
141141 message: null,
142142 isAutoExecute: false,
143143 isEditor: false,
144144 isRun: false,
145145 scope: null,
146146 executionOptions: {},
147147 }, options);
148148 const execOptions = options.executionOptions;
149149 /**@type {HTMLTextAreaElement}*/
@@ -208,9 +208,8 @@ export class QuickReplySet {
208208 }
209209
210210 addQuickReply(data = {}) {
211211 const id = Math.max(this.idIndex, this.qrList.reduce((max, qr) => Math.max(max, qr.id), 0)) + 1;
212- data.id =
212+ data.id = this.idIndex = id + 1;
213- this.idIndex = id + 1;
214213 const qr = QuickReply.from(data);
215214 this.qrList.push(qr);
216215 this.hookQuickReply(qr);
@@ -257,11 +256,11 @@ export class QuickReplySet {
257256 */
258257 hookQuickReply(qr) {
259258 // @ts-ignore
260259 qr.onDebug = () => this.debug(qr);
261260 qr.onExecute = (_, options) => this.executeWithOptions(qr, options);
262261 qr.onDelete = () => this.removeQuickReply(qr);
263262 qr.onUpdate = () => this.save();
264263 qr.onInsertBefore = (qrJson) => {
265264 this.addQuickReplyFromText(qrJson);
266265 const newQr = this.qrList.pop();
267266 this.qrList.splice(this.qrList.indexOf(qr), 0, newQr);
@@ -270,7 +269,7 @@ export class QuickReplySet {
270269 }
271270 this.save();
272271 };
273272 qr.onTransfer = async () => {
274273 /**@type {HTMLSelectElement} */
275274 let sel;
276275 let isCopy = false;
@@ -301,14 +300,14 @@ export class QuickReplySet {
301300 sel.append(opt);
302301 }
303302 }
304303 sel.addEventListener('keyup', (evt) => {
305304 if (evt.key == 'Shift') {
306305 // @ts-ignore
307306 (dlg.dom ?? dlg.dlg).classList.remove('qr--isCopy');
308307 return;
309308 }
310309 });
311310 sel.addEventListener('keydown', (evt) => {
312311 if (evt.key == 'Shift') {
313312 // @ts-ignore
314313 (dlg.dom ?? dlg.dlg).classList.add('qr--isCopy');
@@ -330,12 +329,12 @@ export class QuickReplySet {
330329 dom.append(hintP);
331330 }
332331 }
333332 const dlg = new Popup(dom, POPUP_TYPE.CONFIRM, null, { okButton: 'Transfer', cancelButton: 'Cancel' });
334333 const copyBtn = document.createElement('div'); {
335334 copyBtn.classList.add('qr--copy');
336335 copyBtn.classList.add('menu_button');
337336 copyBtn.textContent = 'Copy';
338337 copyBtn.addEventListener('click', () => {
339338 isCopy = true;
340339 dlg.completeAffirmative();
341340 });
@@ -346,7 +345,7 @@ export class QuickReplySet {
346345 sel.focus();
347346 await prom;
348347 if (dlg.result == POPUP_RESULT.AFFIRMATIVE) {
349348 const qrs = QuickReplySet.list.find(it => it.name == sel.value);
350349 qrs.addQuickReply(qr.toJSON());
351350 if (!isCopy) {
352351 qr.delete();
public/scripts/extensions/quick-reply/src/QuickReplySetLink.js+6 -14
@@ -9,8 +9,6 @@ export class QuickReplySetLink {
99 }
1010
1111
12-
13-
1412 /**@type {QuickReplySet}*/ set;
1513 /**@type {Boolean}*/ isVisible = true;
1614
@@ -23,8 +21,6 @@ export class QuickReplySetLink {
2321 /**@type {HTMLElement}*/ settingsDom;
2422
2523
26-
27-
2824 renderSettings(idx) {
2925 this.index = idx;
3026 const item = document.createElement('div'); {
@@ -40,12 +36,12 @@ export class QuickReplySetLink {
4036 const set = document.createElement('select'); {
4137 set.classList.add('qr--set');
4238 // fix for jQuery sortable breaking childrens' touch events
4339 set.addEventListener('touchstart', (evt) => evt.stopPropagation());
4440 set.addEventListener('change', () => {
4541 this.set = QuickReplySet.get(set.value);
4642 this.update();
4743 });
4844 QuickReplySet.list.toSorted((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).forEach(qrs => {
4945 const opt = document.createElement('option'); {
5046 opt.value = qrs.name;
5147 opt.textContent = qrs.name;
@@ -61,7 +57,7 @@ export class QuickReplySetLink {
6157 const cb = document.createElement('input'); {
6258 cb.type = 'checkbox';
6359 cb.checked = this.isVisible;
6460 cb.addEventListener('click', () => {
6561 this.isVisible = cb.checked;
6662 this.update();
6763 });
@@ -76,7 +72,7 @@ export class QuickReplySetLink {
7672 edit.classList.add('fa-solid');
7773 edit.classList.add('fa-pencil');
7874 edit.title = 'Edit quick reply set';
7975 edit.addEventListener('click', () => this.requestEditSet());
8076 item.append(edit);
8177 }
8278 const del = document.createElement('div'); {
@@ -86,7 +82,7 @@ export class QuickReplySetLink {
8682 del.classList.add('fa-solid');
8783 del.classList.add('fa-trash-can');
8884 del.title = 'Remove quick reply set';
8985 del.addEventListener('click', () => this.delete());
9086 item.append(del);
9187 }
9288 }
@@ -98,8 +94,6 @@ export class QuickReplySetLink {
9894 }
9995
10096
101-
102-
10397 update() {
10498 if (this.onUpdate) {
10599 this.onUpdate(this);
@@ -118,8 +112,6 @@ export class QuickReplySetLink {
118112 }
119113
120114
121-
122-
123115 toJSON() {
124116 return {
125117 set: this.set.name,
public/scripts/extensions/quick-reply/src/QuickReplySettings.js+2 -8
@@ -15,8 +15,6 @@ export class QuickReplySettings {
1515 }
1616
1717
18-
19-
2018 /**@type {Boolean}*/ isEnabled = false;
2119 /**@type {Boolean}*/ isCombined = false;
2220 /**@type {Boolean}*/ isPopout = false;
@@ -50,8 +48,6 @@ export class QuickReplySettings {
5048 /**@type {Function}*/ onRequestEditSet;
5149
5250
53-
54-
5551 init() {
5652 this.hookConfig(this.config);
5753 this.hookConfig(this.chatConfig);
@@ -60,8 +56,8 @@ export class QuickReplySettings {
6056
6157 hookConfig(config) {
6258 if (config) {
6359 config.onUpdate = () => this.save();
6460 config.onRequestEditSet = (qrs) => this.requestEditSet(qrs);
6561 }
6662 }
6763 unhookConfig(config) {
@@ -72,8 +68,6 @@ export class QuickReplySettings {
7268 }
7369
7470
75-
76-
7771 save() {
7872 extension_settings.quickReplyV2 = this.toJSON();
7973 saveSettingsDebounced();
public/scripts/extensions/quick-reply/src/SlashCommandHandler.js+13 -21
@@ -16,15 +16,11 @@ export class SlashCommandHandler {
1616 /** @type {QuickReplyApi} */ api;
1717
1818
19-
20-
2119 constructor(/** @type {QuickReplyApi} */api) {
2220 this.api = api;
2321 }
2422
2523
26-
27-
2824 init() {
2925 function getExecutionIcons(/** @type {QuickReply} */ qr) {
3026 let icons = '';
@@ -56,7 +52,7 @@ export class SlashCommandHandler {
5652 qrIds: (executor) => QuickReplySet.get(String(executor.namedArgumentList.find(x => x.name == 'set')?.value))?.qrList.map(qr => {
5753 const icons = getExecutionIcons(qr);
5854 const message = `${qr.automationId ? `[${qr.automationId}]` : ''}${icons ? `[auto: ${icons}]` : ''} ${qr.title || qr.message}`.trim();
5955 return new SlashCommandEnumValue(qr.label, message, enumTypes.enum, enumIcons.qr, null, () => qr.id.toString(), true);
6056 }) ?? [],
6157
6258 /** All QRs as a set.name string, to be able to execute, for example via the /run command */
@@ -352,7 +348,7 @@ export class SlashCommandHandler {
352348 return '';
353349 },
354350 returns: 'updated quick reply',
355351 namedArgumentList: [...qrUpdateArgs, ...qrArgs.map(it => {
356352 if (it.name == 'label') {
357353 const clone = SlashCommandNamedArgument.fromProps(it);
358354 clone.isRequired = false;
@@ -691,16 +687,16 @@ export class SlashCommandHandler {
691687 if (!args.from) throw new Error('/import requires from= to be set.');
692688 if (!value) throw new Error('/import requires the unnamed argument to be set.');
693689 let qr = [...this.api.listGlobalSets(), ...this.api.listChatSets()]
694690 .map(it => this.api.getSetByName(it)?.qrList ?? [])
695691 .flat()
696692 .find(it => it.label == args.from)
697693 ;
698694 if (!qr) {
699695 let [setName, ...qrNameParts] = args.from.split('.');
700696 let qrName = qrNameParts.join('.');
701697 let qrs = QuickReplySet.get(setName);
702698 if (qrs) {
703699 qr = qrs.qrList.find(it => it.label == qrName);
704700 }
705701 }
706702 if (qr) {
@@ -709,23 +705,23 @@ export class SlashCommandHandler {
709705 if (args._debugController) {
710706 closure.source = args.from;
711707 }
712708 const testCandidates = (executor) => {
713709 return (
714710 executor.namedArgumentList.find(arg => arg.name == 'key')
715711 && executor.unnamedArgumentList.length > 0
716712 && executor.unnamedArgumentList[0].value instanceof SlashCommandClosure
717713 ) || (
718714 !executor.namedArgumentList.find(arg => arg.name == 'key')
719715 && executor.unnamedArgumentList.length > 1
720716 && executor.unnamedArgumentList[1].value instanceof SlashCommandClosure
721717 );
722718 };
723719 const candidates = closure.executorList
724720 .filter(executor => ['let', 'var'].includes(executor.command.name))
725721 .filter(testCandidates)
726722 .map(executor => ({
727723 key: executor.namedArgumentList.find(arg => arg.name == 'key')?.value ?? executor.unnamedArgumentList[0].value,
728724 value: executor.unnamedArgumentList[executor.namedArgumentList.find(arg => arg.name == 'key') ? 0 : 1].value,
729725 }))
730726 ;
731727 for (let i = 0; i < value.length; i++) {
@@ -735,7 +731,7 @@ export class SlashCommandHandler {
735731 dstName = value[i + 2];
736732 i += 2;
737733 }
738734 const pick = candidates.find(it => it.key == srcName);
739735 if (!pick) throw new Error(`No scoped closure named "${srcName}" found in "${args.from}"`);
740736 if (args._scope.existsVariableInScope(dstName)) {
741737 args._scope.setVariable(dstName, pick.value);
@@ -783,8 +779,6 @@ export class SlashCommandHandler {
783779 }
784780
785781
786-
787-
788782 getSetByName(name) {
789783 const set = this.api.getSetByName(name);
790784 if (!set) {
@@ -802,8 +796,6 @@ export class SlashCommandHandler {
802796 }
803797
804798
805-
806-
807799 async executeQuickReplyByIndex(idx) {
808800 try {
809801 return await this.api.executeQuickReplyByIndex(idx);
public/scripts/extensions/quick-reply/src/ui/ButtonUi.js+6 -14
@@ -10,15 +10,11 @@ export class ButtonUi {
1010 /**@type {HTMLElement}*/ popoutDom;
1111
1212
13-
14-
1513 constructor(/**@type {QuickReplySettings}*/settings) {
1614 this.settings = settings;
1715 }
1816
1917
20-
21-
2218 render() {
2319 if (this.settings.isPopout) {
2420 return this.renderPopout();
@@ -57,8 +53,6 @@ export class ButtonUi {
5753 }
5854
5955
60-
61-
6256 renderBar() {
6357 if (!this.dom) {
6458 let buttonHolder;
@@ -75,7 +69,7 @@ export class ButtonUi {
7569 popout.classList.add('menu_button');
7670 popout.classList.add('fa-solid');
7771 popout.classList.add('fa-window-restore');
7872 popout.addEventListener('click', () => {
7973 this.settings.isPopout = true;
8074 this.refresh();
8175 this.settings.save();
@@ -91,8 +85,8 @@ export class ButtonUi {
9185 }
9286 }
9387 [...this.settings.config.setList, ...(this.settings.chatConfig?.setList ?? []), ...(this.settings.charConfig?.setList ?? [])]
9488 .filter(link => link.isVisible)
9589 .forEach(link => buttonHolder.append(link.set.render()))
9690 ;
9791 }
9892 }
@@ -100,8 +94,6 @@ export class ButtonUi {
10094 }
10195
10296
103-
104-
10597 renderPopout() {
10698 if (!this.popoutDom) {
10799 let buttonHolder;
@@ -130,7 +122,7 @@ export class ButtonUi {
130122 close.classList.add('fa-solid');
131123 close.classList.add('fa-circle-xmark');
132124 close.classList.add('hoverglow');
133125 close.addEventListener('click', () => {
134126 this.settings.isPopout = false;
135127 this.refresh();
136128 this.settings.save();
@@ -151,8 +143,8 @@ export class ButtonUi {
151143 }
152144 }
153145 [...this.settings.config.setList, ...(this.settings.chatConfig?.setList ?? []), ...(this.settings.charConfig?.setList ?? [])]
154146 .filter(link => link.isVisible)
155147 .forEach(link => buttonHolder.append(link.set.render()))
156148 ;
157149 root.append(body);
158150 }
public/scripts/extensions/quick-reply/src/ui/SettingsUi.js+30 -38
@@ -29,24 +29,18 @@ export class SettingsUi {
2929 /**@type {HTMLSelectElement}*/ currentSet;
3030
3131
32-
33-
3432 constructor(/**@type {QuickReplySettings}*/settings) {
3533 this.settings = settings;
3634 settings.onRequestEditSet = (qrs) => this.selectQrSet(qrs);
3735 }
3836
3937
40-
41-
42-
43-
4438 rerender() {
4539 if (!this.dom) return;
4640 const content = this.dom.querySelector('.inline-drawer-content');
4741 content.innerHTML = '';
4842 // @ts-ignore
4943 Array.from(this.template.querySelector('.inline-drawer-content').cloneNode(true).children).forEach(el => {
5044 content.append(el);
5145 });
5246 this.prepareDom();
@@ -75,15 +69,15 @@ export class SettingsUi {
7569 // general settings
7670 this.isEnabled = this.dom.querySelector('#qr--isEnabled');
7771 this.isEnabled.checked = this.settings.isEnabled;
7872 this.isEnabled.addEventListener('click', () => this.onIsEnabled());
7973
8074 this.isCombined = this.dom.querySelector('#qr--isCombined');
8175 this.isCombined.checked = this.settings.isCombined;
8276 this.isCombined.addEventListener('click', () => this.onIsCombined());
8377
8478 this.showPopoutButton = this.dom.querySelector('#qr--showPopoutButton');
8579 this.showPopoutButton.checked = this.settings.showPopoutButton;
8680 this.showPopoutButton.addEventListener('click', () => this.onShowPopoutButton());
8781 }
8882
8983 prepareGlobalSetList() {
@@ -131,29 +125,29 @@ export class SettingsUi {
131125 prepareQrEditor() {
132126 // qr editor
133127 this.dom.querySelector('#qr--set-rename').addEventListener('click', async () => this.renameQrSet());
134128 this.dom.querySelector('#qr--set-new').addEventListener('click', async () => this.addQrSet());
135129 /**@type {HTMLInputElement}*/
136130 const importFile = this.dom.querySelector('#qr--set-importFile');
137131 importFile.addEventListener('change', async () => {
138132 await this.importQrSet(importFile.files);
139133 importFile.value = null;
140134 });
141135 this.dom.querySelector('#qr--set-import').addEventListener('click', () => importFile.click());
142136 this.dom.querySelector('#qr--set-export').addEventListener('click', async () => this.exportQrSet());
143137 this.dom.querySelector('#qr--set-duplicate').addEventListener('click', async () => this.duplicateQrSet());
144138 this.dom.querySelector('#qr--set-delete').addEventListener('click', async () => this.deleteQrSet());
145139 this.dom.querySelector('#qr--set-add').addEventListener('click', async () => {
146140 this.currentQrSet.addQuickReply();
147141 });
148142 this.dom.querySelector('#qr--set-paste').addEventListener('click', async () => {
149143 const text = await navigator.clipboard.readText();
150144 this.currentQrSet.addQuickReplyFromText(text);
151145 });
152146 this.dom.querySelector('#qr--set-importQr').addEventListener('click', async () => {
153147 const inp = document.createElement('input'); {
154148 inp.type = 'file';
155149 inp.accept = '.json';
156150 inp.addEventListener('change', async () => {
157151 if (inp.files.length > 0) {
158152 for (const file of inp.files) {
159153 const text = await file.text();
@@ -166,8 +160,8 @@ export class SettingsUi {
166160 });
167161 this.qrList = this.dom.querySelector('#qr--set-qrList');
168162 this.currentSet = this.dom.querySelector('#qr--set');
169163 this.currentSet.addEventListener('change', () => this.onQrSetChange());
170164 QuickReplySet.list.toSorted((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).forEach(qrs => {
171165 const opt = document.createElement('option'); {
172166 opt.value = qrs.name;
173167 opt.textContent = qrs.name;
@@ -175,19 +169,19 @@ export class SettingsUi {
175169 }
176170 });
177171 this.disableSend = this.dom.querySelector('#qr--disableSend');
178172 this.disableSend.addEventListener('click', () => {
179173 const qrs = this.currentQrSet;
180174 qrs.disableSend = this.disableSend.checked;
181175 qrs.save();
182176 });
183177 this.placeBeforeInput = this.dom.querySelector('#qr--placeBeforeInput');
184178 this.placeBeforeInput.addEventListener('click', () => {
185179 const qrs = this.currentQrSet;
186180 qrs.placeBeforeInput = this.placeBeforeInput.checked;
187181 qrs.save();
188182 });
189183 this.injectInput = this.dom.querySelector('#qr--injectInput');
190184 this.injectInput.addEventListener('click', () => {
191185 const qrs = this.currentQrSet;
192186 qrs.injectInput = this.injectInput.checked;
193187 qrs.save();
@@ -196,7 +190,7 @@ export class SettingsUi {
196190 this.color = this.dom.querySelector('#qr--color');
197191 // @ts-ignore
198192 this.color.color = this.currentQrSet?.color ?? 'transparent';
199193 this.color.addEventListener('change', (evt) => {
200194 if (!this.dom.closest('body')) return;
201195 const qrs = this.currentQrSet;
202196 if (initialColorChange) {
@@ -211,7 +205,7 @@ export class SettingsUi {
211205 this.currentQrSet.updateColor();
212206 });
213207 // @ts-ignore
214208 this.dom.querySelector('#qr--colorClear').addEventListener('click', (evt) => {
215209 const qrs = this.currentQrSet;
216210 // @ts-ignore
217211 this.color.color = 'transparent';
@@ -219,7 +213,7 @@ export class SettingsUi {
219213 this.currentQrSet.updateColor();
220214 });
221215 this.onlyBorderColor = this.dom.querySelector('#qr--onlyBorderColor');
222216 this.onlyBorderColor.addEventListener('click', () => {
223217 const qrs = this.currentQrSet;
224218 qrs.onlyBorderColor = this.onlyBorderColor.checked;
225219 qrs.save();
@@ -242,7 +236,7 @@ export class SettingsUi {
242236 $(qrsDom).sortable({
243237 delay: getSortableDelay(),
244238 handle: '.drag-handle',
245239 stop: () => this.onQrListSort(),
246240 });
247241 }
248242
@@ -256,8 +250,6 @@ export class SettingsUi {
256250 }
257251
258252
259-
260-
261253 async onIsEnabled() {
262254 this.settings.isEnabled = this.isEnabled.checked;
263255 this.settings.save();
@@ -274,7 +266,7 @@ export class SettingsUi {
274266 }
275267
276268 async onGlobalSetListSort() {
277269 this.settings.config.setList = Array.from(this.globalSetList.children).map((it, idx) => {
278270 const set = this.settings.config.setList[Number(it.getAttribute('data-order'))];
279271 it.setAttribute('data-order', String(idx));
280272 return set;
@@ -283,7 +275,7 @@ export class SettingsUi {
283275 }
284276
285277 async onChatSetListSort() {
286278 this.settings.chatConfig.setList = Array.from(this.chatSetList.children).map((it, idx) => {
287279 const set = this.settings.chatConfig.setList[Number(it.getAttribute('data-order'))];
288280 it.setAttribute('data-order', String(idx));
289281 return set;
@@ -292,14 +284,14 @@ export class SettingsUi {
292284 }
293285
294286 updateOrder(list) {
295287 Array.from(list.children).forEach((it, idx) => {
296288 it.setAttribute('data-order', idx);
297289 });
298290 }
299291
300292 async onQrListSort() {
301293 this.currentQrSet.qrList = Array.from(this.qrList.querySelectorAll('.qr--set-item')).map((it, idx) => {
302294 const qr = this.currentQrSet.qrList.find(qr => qr.id == Number(it.getAttribute('data-id')));
303295 it.setAttribute('data-order', String(idx));
304296 return qr;
305297 });
@@ -408,7 +400,7 @@ export class SettingsUi {
408400 const qrs = new QuickReplySet();
409401 qrs.name = name;
410402 qrs.addQuickReply();
411403 const idx = QuickReplySet.list.findIndex(it => it.name.toLowerCase().localeCompare(name.toLowerCase()) == 1);
412404 if (idx > -1) {
413405 QuickReplySet.list.splice(idx, 0, qrs);
414406 } else {
@@ -448,7 +440,7 @@ export class SettingsUi {
448440 } else {
449441 /**@type {QuickReplySet}*/
450442 const qrs = QuickReplySet.from(JSON.parse(JSON.stringify(props)));
451443 qrs.qrList = props.qrList.map(it => QuickReply.from(it));
452444 qrs.init();
453445 const oldQrs = QuickReplySet.get(props.name);
454446 if (oldQrs) {
@@ -466,7 +458,7 @@ export class SettingsUi {
466458 this.prepareCharacterSetList();
467459 }
468460 } else {
469461 const idx = QuickReplySet.list.findIndex(it => it.name.toLowerCase().localeCompare(qrs.name.toLowerCase()) == 1);
470462 if (idx > -1) {
471463 QuickReplySet.list.splice(idx, 0, qrs);
472464 } else {
@@ -496,7 +488,7 @@ export class SettingsUi {
496488 }
497489
498490 exportQrSet() {
499491 const blob = new Blob([JSON.stringify(this.currentQrSet)], { type: 'application/json' });
500492 const url = URL.createObjectURL(blob);
501493 const a = document.createElement('a'); {
502494 a.href = url;
public/scripts/extensions/quick-reply/src/ui/ctx/ContextMenu.js+0 -4
@@ -11,8 +11,6 @@ export class ContextMenu {
1111 /**@type {HTMLElement}*/ menu;
1212
1313
14-
15-
1614 constructor(/**@type {QuickReply}*/qr) {
1715 // this.itemList = items;
1816 this.itemList = this.build(qr).children;
@@ -104,8 +102,6 @@ export class ContextMenu {
104102 }
105103
106104
107-
108-
109105 show({ clientX, clientY }) {
110106 if (this.isActive) return;
111107 this.isActive = true;
public/scripts/extensions/quick-reply/src/ui/ctx/MenuItem.js+0 -3
@@ -15,8 +15,6 @@ export class MenuItem {
1515 /**@type {function}*/ onExpand;
1616
1717
18-
19-
2018 /**
2119 *
2220 * @param {?string} icon
@@ -80,7 +78,6 @@ export class MenuItem {
8078 }
8179 item.addEventListener('mouseover', () => sub.show(item));
8280 item.addEventListener('mouseleave', () => sub.hide());
83-
8481 }
8582 }
8683 }
public/scripts/extensions/quick-reply/src/ui/ctx/SubMenu.js+0 -4
@@ -9,8 +9,6 @@ export class SubMenu {
99 /**@type {HTMLElement}*/ root;
1010
1111
12-
13-
1412 constructor(/**@type {MenuItem[]}*/items) {
1513 this.itemList = items;
1614 }
@@ -29,8 +27,6 @@ export class SubMenu {
2927 }
3028
3129
32-
33-
3430 show(/**@type {HTMLElement}*/parent) {
3531 if (this.isActive) return;
3632 this.isActive = true;
public/scripts/extensions/regex/index.js+0 -1
@@ -1031,7 +1031,6 @@ function executeRegexScriptForDebugging(script, text) {
10311031 const trailingText = text.substring(lastIndex);
10321032 outputText += trailingText;
10331033 highlightedOutput += escapeHtml(trailingText);
1034-
10351034 } catch (e) {
10361035 err = (err ? err + '; ' : '') + `Replace error: ${e.message}`;
10371036 outputText = text; // Fallback
public/scripts/extensions/token-counter/index.js+0 -1
@@ -115,5 +115,4 @@ jQuery(() => {
115115 returns: 'number of tokens',
116116 helpString: 'Counts the number of tokens in the current chat.',
117117 }));
118-
119118});
public/scripts/extensions/tts/alltalk.js+0 -1
@@ -1043,7 +1043,6 @@ class AllTalkTtsProvider {
10431043 // V2: Combine the endpoint with the relative path
10441044 return `${this.settings.provider_endpoint}${data.output_file_url}`;
10451045 }
1046-
10471046 } catch (error) {
10481047 console.error('[fetchTtsGeneration] Exception caught:', error);
10491048 throw error;
public/scripts/extensions/tts/chatterbox.js+0 -3
@@ -239,7 +239,6 @@ class ChatterboxTtsProvider {
239239 }
240240
241241 this.setupEventListeners();
242-
243242 } catch (error) {
244243 console.error('Error loading Chatterbox settings:', error);
245244 this.updateStatus('Offline');
@@ -518,7 +517,6 @@ class ChatterboxTtsProvider {
518517 });
519518
520519 await audio.play();
521-
522520 } catch (error) {
523521 console.error('Error previewing voice:', error);
524522 this.updateStatus('Ready');
@@ -627,7 +625,6 @@ class ChatterboxTtsProvider {
627625
628626 // Return the response directly - SillyTavern expects a Response object
629627 return response;
630-
631628 } catch (error) {
632629 console.error('Error in generateTts:', error);
633630 this.updateStatus('Ready');
public/scripts/extensions/tts/coqui.js+12 -13
@@ -160,7 +160,7 @@ class CoquiTtsProvider {
160160 .then(response => response.json())
161161 .then(json => {
162162 coquiApiModels = json;
163163 console.debug(DEBUG_PREFIX, 'initialized coqui-api model list to', coquiApiModels);
164164 /*
165165 $('#coqui_api_language')
166166 .find('option')
@@ -180,7 +180,7 @@ class CoquiTtsProvider {
180180 .then(response => response.json())
181181 .then(json => {
182182 coquiApiModelsFull = json;
183183 console.debug(DEBUG_PREFIX, 'initialized coqui-api full model list to', coquiApiModelsFull);
184184 /*
185185 $('#coqui_api_full_language')
186186 .find('option')
@@ -197,7 +197,7 @@ class CoquiTtsProvider {
197197 }
198198
199199 // Perform a simple readiness check by trying to fetch voiceIds
200200 async checkReady() {
201201 throwIfModuleMissing();
202202 await this.fetchTtsVoiceObjects();
203203 }
@@ -384,12 +384,12 @@ class CoquiTtsProvider {
384384 .append('<option value="none">Select model language</option>')
385385 .val('none');
386386
387387 for (let language in coquiApiModels) {
388388 let languageLabel = language;
389389 if (language in languageLabels)
390390 languageLabel = languageLabels[language];
391391 $('#coqui_api_language').append(new Option(languageLabel, language));
392392 console.log(DEBUG_PREFIX, 'added language', languageLabel, '(', language, ')');
393393 }
394394
395395 $('#coqui_api_model_div').show();
@@ -406,12 +406,12 @@ class CoquiTtsProvider {
406406 .append('<option value="none">Select model language</option>')
407407 .val('none');
408408
409409 for (let language in coquiApiModelsFull) {
410410 let languageLabel = language;
411411 if (language in languageLabels)
412412 languageLabel = languageLabels[language];
413413 $('#coqui_api_language').append(new Option(languageLabel, language));
414414 console.log(DEBUG_PREFIX, 'added language', languageLabel, '(', language, ')');
415415 }
416416
417417 $('#coqui_api_model_div').show();
@@ -450,8 +450,8 @@ class CoquiTtsProvider {
450450 if (model_origin == 'coqui-api-full')
451451 modelDict = coquiApiModelsFull;
452452
453453 for (let model_dataset in modelDict[model_language])
454454 for (let model_name in modelDict[model_language][model_dataset]) {
455455 const model_id = model_dataset + '/' + model_name;
456456 const model_label = model_name + ' (' + model_dataset + ' dataset)';
457457 $('#coqui_api_model_name').append(new Option(model_label, model_id));
@@ -526,7 +526,7 @@ class CoquiTtsProvider {
526526
527527 // Check if already installed and propose to do it otherwise
528528 const model_id = modelDict[model_language][model_dataset][model_name].id;
529529 console.debug(DEBUG_PREFIX, 'Check if model is already installed', model_id);
530530 const result = await CoquiTtsProvider.checkmodel_state(model_id);
531531 const resultJSON = await result.json();
532532 const model_state = resultJSON.model_state;
@@ -583,7 +583,6 @@ class CoquiTtsProvider {
583583 $('#coqui_api_model_install_button').show();
584584 return;
585585 }
586-
587586 }
588587
589588
public/scripts/extensions/tts/cosyvoice.js+0 -6
@@ -110,15 +110,11 @@ class CosyVoiceProvider {
110110 //#################//
111111
112112 async getVoice(voiceName) {
113-
114-
115-
116113 if (this.voices.length == 0) {
117114 this.voices = await this.fetchTtsVoiceObjects();
118115 }
119116
120117
121-
122118 const match = this.voices.filter(
123119 v => v.name == voiceName,
124120 )[0];
@@ -130,7 +126,6 @@ class CosyVoiceProvider {
130126 }
131127
132128
133-
134129 async generateTts(text, voiceId) {
135130 const response = await this.fetchTtsGeneration(text, voiceId);
136131 return response;
@@ -198,7 +193,6 @@ class CosyVoiceProvider {
198193 }
199194
200195
201-
202196 // Interface not used
203197 async fetchTtsFromHistory(history_item_id) {
204198 return Promise.resolve(history_item_id);
public/scripts/extensions/tts/elevenlabs.js+1 -1
@@ -132,7 +132,7 @@ class ElevenLabsTtsProvider {
132132 }
133133
134134 if (Object.hasOwn(settings, 'apiKey')) {
135135 if (settings.apiKey && !secret_state[SECRET_KEYS.ELEVENLABS]) {
136136 await writeSecret(SECRET_KEYS.ELEVENLABS, settings.apiKey);
137137 }
138138 delete settings.apiKey;
public/scripts/extensions/tts/google-native.js+0 -2
@@ -124,7 +124,6 @@ export class GoogleNativeTtsProvider {
124124 console.info(`Google TTS: Loaded ${this.voices.length} voices`);
125125
126126 return this.voices;
127-
128127 } catch (error) {
129128 console.error('Failed to fetch Google TTS voices:', error);
130129 throw error;
@@ -151,7 +150,6 @@ export class GoogleNativeTtsProvider {
151150 this.audioElement.src = url;
152151 this.audioElement.play();
153152 this.audioElement.onended = () => URL.revokeObjectURL(url);
154-
155153 } catch (error) {
156154 console.error('TTS Preview Error:', error);
157155 toastr.error(`Could not generate preview: ${error.message}`);
public/scripts/extensions/tts/gpt-sovits-v2.js+0 -8
@@ -115,15 +115,11 @@ class GptSovitsV2Provider {
115115 //#################//
116116
117117 async getVoice(voiceName) {
118-
119-
120-
121118 if (this.voices.length == 0) {
122119 this.voices = await this.fetchTtsVoiceObjects();
123120 }
124121
125122
126-
127123 const match = this.voices.filter(
128124 v => v.name == voiceName,
129125 )[0];
@@ -135,7 +131,6 @@ class GptSovitsV2Provider {
135131 }
136132
137133
138-
139134 async generateTts(text, voiceId) {
140135 const response = await this.fetchTtsGeneration(text, voiceId);
141136 return response;
@@ -171,8 +166,6 @@ class GptSovitsV2Provider {
171166 */
172167
173168
174-
175-
176169 async fetchTtsGeneration(inputText, voiceId, lang = null, forceNoStreaming = false) {
177170 console.info(`Generating new TTS for voice_id ${voiceId}`);
178171
@@ -215,7 +208,6 @@ class GptSovitsV2Provider {
215208 }
216209
217210
218-
219211 // Interface not used
220212 async fetchTtsFromHistory(history_item_id) {
221213 return Promise.resolve(history_item_id);
public/scripts/extensions/tts/gsvi.js+0 -9
@@ -1,4 +1,3 @@
1-
21import { saveTtsProviderSettings } from './index.js';
32
43export { GSVITtsProvider };
@@ -60,11 +59,9 @@ class GSVITtsProvider {
6059 const characterList = await response.json();
6160 this.characterList = characterList;
6261 this.voices = Object.keys(characterList);
63-
6462 }
6563
6664
67-
6865 get settingsHtml() {
6966 let html = `
7067 <label for="gsvi_api_language">Text Language</label>
@@ -142,11 +139,8 @@ class GSVITtsProvider {
142139 $('#gsvi_batch_size_output').text(this.settings.batch_size);
143140
144141
145-
146-
147142 // Persist settings changes
148143 saveTtsProviderSettings();
149-
150144 }
151145
152146 async loadSettings(settings) {
@@ -197,7 +191,6 @@ class GSVITtsProvider {
197191 }
198192
199193
200-
201194 // Perform a simple readiness check by trying to fetch voiceIds
202195 async checkReady() {
203196 await Promise.allSettled([this.fetchCharacterList()]);
@@ -256,12 +249,10 @@ class GSVITtsProvider {
256249
257250
258251 return `${this.settings.provider_endpoint}/tts?${params.toString()}`;
259-
260252 }
261253
262254 // Interface not used by GSVI TTS
263255 async fetchTtsFromHistory(history_item_id) {
264256 return Promise.resolve(history_item_id);
265257 }
266-
267258}
public/scripts/extensions/tts/index.js+0 -4
@@ -611,7 +611,6 @@ async function processTtsQueue() {
611611
612612 // Pass the full voiceMapKey (e.g., "User ("Quotes")") as well with character name
613613 await tts(segmentText, voiceId, char, voiceMapKey);
614-
615614 } catch (error) {
616615 toastr.error(error.toString());
617616 console.error(error);
@@ -707,7 +706,6 @@ async function processTtsQueue() {
707706
708707 // Clear current job so the segmented jobs can be processed
709708 currentTtsJob = null;
710-
711709 } catch (error) {
712710 toastr.error(error.toString());
713711 console.error(error);
@@ -1286,7 +1284,6 @@ export function getCharacters(unrestricted) {
12861284 }
12871285
12881286 return characters;
1289-
12901287}
12911288
12921289export function sanitizeId(input) {
@@ -1314,7 +1311,6 @@ function parseVoiceMap(voiceMapString) {
13141311}
13151312
13161313
1317-
13181314/**
13191315 * Apply voiceMap based on current voiceMapEntries
13201316 */
public/scripts/extensions/tts/kokoro-worker.js+1 -1
@@ -7,7 +7,7 @@ let ready = false;
77let voices = [];
88
99// Handle messages from the main thread
1010self.onmessage = async function (e) {
1111 const { action, data } = e.data;
1212
1313 switch (action) {
public/scripts/extensions/tts/minimax.js+0 -2
@@ -837,7 +837,6 @@ class MiniMaxTtsProvider {
837837 // Backend handles all the complex processing and returns audio data directly
838838 console.debug('MiniMax TTS: Audio response received from backend');
839839 return response;
840-
841840 } catch (error) {
842841 console.error('Error in MiniMax TTS generation:', error);
843842 throw error;
@@ -954,7 +953,6 @@ class MiniMaxTtsProvider {
954953 this.audioElement.onended = null;
955954 this.audioElement.onerror = null;
956955 };
957-
958956 } catch (error) {
959957 console.error('MiniMax TTS Preview Error:', error);
960958 toastr.error(`Could not generate preview: ${error.message}`);
public/scripts/extensions/tts/openai.js+0 -1
@@ -146,7 +146,6 @@ class OpenAITtsProvider {
146146 }
147147
148148 populateCharacterInstructions() {
149-
150149 const currentCharacters = $('.tts_voicemap_block_char span').map((i, el) => $(el).text()).get();
151150
152151 $('#openai-character-instructions').empty();
public/scripts/extensions/tts/silerotts.js+0 -1
@@ -172,5 +172,4 @@ class SileroTtsProvider {
172172 async fetchTtsFromHistory(history_item_id) {
173173 return Promise.resolve(history_item_id);
174174 }
175-
176175}
public/scripts/extensions/tts/xtts.js+0 -1
@@ -323,5 +323,4 @@ class XTTSTtsProvider {
323323 async fetchTtsFromHistory(history_item_id) {
324324 return Promise.resolve(history_item_id);
325325 }
326-
327326}
public/scripts/extensions/vectors/index.js+0 -1
@@ -1456,7 +1456,6 @@ async function onViewStatsClick() {
14561456 messageElement.addClass('vectorized');
14571457 }
14581458 }
1459-
14601459}
14611460
14621461async function onVectorizeAllFilesClick() {
public/scripts/f-localStorage.js+0 -1
@@ -13,7 +13,6 @@ export function SaveLocal(target, val) {
1313export function LoadLocal(target) {
1414 console.debug('LoadLocal -- ' + target);
1515 return localStorage.getItem(target);
16-
1716}
1817/**
1918 * @deprecated THIS FUNCTION IS OBSOLETE. DO NOT USE
public/scripts/filters.js+0 -1
@@ -76,7 +76,6 @@ export const fuzzySearchCategories = Object.freeze({
7676 * data = filterHelper.applyFilters(data);
7777 */
7878export class FilterHelper {
79-
8079 /**
8180 * Cache fuzzy search weighting scores for re-usability, sorting and stuff
8281 *
public/scripts/group-chats.js+0 -1
@@ -2477,7 +2477,6 @@ jQuery(() => {
24772477 const value = $(this).prop('checked');
24782478 hideMutedSprites = value;
24792479 onHideMutedSpritesClick(value);
2480-
24812480 });
24822481 $('#send_textarea').on('keyup', onSendTextareaInput);
24832482 $('#groupCurrentMemberPopoutButton').on('click', doCurMemberListPopout);
public/scripts/input-md-formatting.js+4 -5
@@ -59,7 +59,8 @@ export function initInputMarkdown() {
5959 let cursorShift = charsToAdd.length;
6060 let selectedTextandPossibleFormatting = textarea.value.substring(start - possiblePreviousFormattingMargin, end + possiblePreviousFormattingMargin).trim();
6161
6262 if (isTextSelected) { //if text is selected
63+ //if text is selected
6364 selectedText = textarea.value.substring(start, end);
6465 if (selectedTextandPossibleFormatting === charsToAdd + selectedText + charsToAdd) {
6566 // If the selected text is already formatted, remove the formatting
@@ -90,7 +91,8 @@ export function initInputMarkdown() {
9091 textarea.focus();
9192 document.execCommand('insertText', false, charsToAdd + selectedText + charsToAdd + possibleAddedSpace);
9293 }
9394 } else {// No text is selected
95+ // No text is selected
9496 //check 1 character before and after the cursor for non-space characters
9597
9698 if (beforeCaret !== ' ' && afterCaret !== ' ' && afterCaret !== '' && beforeCaret !== '') { //look for caret in the middle of a word
@@ -116,7 +118,6 @@ export function initInputMarkdown() {
116118 }
117119
118120 if (charsToAdd + discoveredWord + charsToAdd === discoveredWordWithPossibleFormatting) {
119-
120121 // Replace the expanded selection with the original discovered word
121122 textarea.focus();
122123 document.execCommand('insertText', false, discoveredWord);
@@ -126,8 +127,6 @@ export function initInputMarkdown() {
126127 textarea.focus();
127128 document.execCommand('insertText', false, charsToAdd + discoveredWord + charsToAdd);
128129 }
129-
130-
131130 } else { //caret is not inside a word, so just add the formatting
132131 textarea.focus();
133132 textarea.setSelectionRange(start, end);
public/scripts/instruct-mode.js+0 -1
@@ -798,7 +798,6 @@ jQuery(() => {
798798 $('#instruct_system_sequence').prop('readOnly', false);
799799 $('#instruct_system_suffix').prop('readOnly', false);
800800 }
801-
802801 });
803802
804803 $('#instruct_enabled').on('change', function () {
public/scripts/openai.js+0 -4
@@ -2279,7 +2279,6 @@ function appendElectronHubOptions(model_list, groupModels = false) {
22792279 appendOption(model);
22802280 });
22812281 }
2282-
22832282}
22842283
22852284function electronHubSortBy(data, property = 'alphabetically') {
@@ -3985,7 +3984,6 @@ function loadOpenAISettings(data, settings) {
39853984 option.value = i;
39863985 option.text = item;
39873986 $('#settings_preset_openai').append(option);
3988-
39893987 });
39903988 openai_setting_names = settingNames;
39913989
@@ -4896,7 +4894,6 @@ function getSiliconflowMaxContext(model, isUnlocked) {
48964894
48974895 // Return context size if model found, otherwise default to 32k
48984896 return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || max_32k;
4899-
49004897}
49014898
49024899/**
@@ -5041,7 +5038,6 @@ async function onModelChange() {
50415038 console.log('Claude model changed to', value);
50425039 oai_settings.claude_model = value;
50435040 $('#model_claude_select').val(oai_settings.claude_model);
5044-
50455041 }
50465042
50475043 if ($(this).is('#model_openai_select')) {
public/scripts/personas.js+0 -2
@@ -1593,7 +1593,6 @@ export async function showCharConnections() {
15931593 highlightPersonas: true,
15941594 targetedChar: getCurrentConnectionObj(),
15951595 shiftClickHandler: (element, ev) => {
1596-
15971596 const personaId = $(element).attr('data-pid');
15981597
15991598 /** @type {PersonaConnection[]} */
@@ -1845,7 +1844,6 @@ async function lockPersonaCallback(_args, value) {
18451844 if (isFalseBoolean(value)) {
18461845 await setPersonaLockState(false, type);
18471846 return 'false';
1848-
18491847 }
18501848
18511849 return '';
public/scripts/popup.js+0 -1
@@ -478,7 +478,6 @@ export class Popup {
478478 break;
479479 }
480480 }
481-
482481 };
483482 this.dlg.addEventListener('keydown', keyListener.bind(this));
484483 }
public/scripts/power-user.js+1 -8
@@ -536,7 +536,6 @@ function switchSwipeNumAllMessages() {
536536var originalSliderValues = [];
537537
538538async function switchLabMode({ noReset = false } = {}) {
539-
540539 /* if (power_user.enableZenSliders && power_user.enableLabMode) {
541540 toastr.warning("Can't start Lab Mode while Zen Sliders are active")
542541 return
@@ -571,8 +570,6 @@ async function switchLabMode({ noReset = false } = {}) {
571570 $('#amount_gen').attr('min', '1')
572571 .attr('max', '99999')
573572 .attr('step', '1');
574-
575-
576573 } else if (!noReset) {
577574 //re apply the original sliders values to each input
578575 originalSliderValues.forEach(function (slider) {
@@ -628,7 +625,6 @@ async function switchZenSliders() {
628625 });
629626 $('div[id$="_zenslider"]').remove();
630627 }
631-
632628}
633629async function CreateZenSliders(elmnt) {
634630 var originalSlider = elmnt;
@@ -1178,7 +1174,6 @@ function applyShadowWidth() {
11781174 document.documentElement.style.setProperty('--shadowWidth', String(power_user.shadow_width));
11791175 $('#shadow_width_counter').val(power_user.shadow_width);
11801176 $('#shadow_width').val(power_user.shadow_width);
1181-
11821177}
11831178
11841179function applyFontScale(type) {
@@ -2954,7 +2949,6 @@ function setAvgBG() {
29542949 } */
29552950
29562951 function getAverageRGB(imgEl) {
2957-
29582952 var blockSize = 5, // only visit every 5 pixels
29592953 defaultRGB = { r: 0, g: 0, b: 0 }, // for non-supporting envs
29602954 canvas = document.createElement('canvas'),
@@ -2994,7 +2988,6 @@ function setAvgBG() {
29942988 rgb.b = ~~(rgb.b / count);
29952989
29962990 return rgb;
2997-
29982991 }
29992992
30002993 /**
@@ -4035,7 +4028,7 @@ jQuery(() => {
40354028 return;
40364029 }
40374030
40384031 eventSource.once(event_types.SETTINGS_UPDATED, function () {
40394032 toastr.warning(
40404033 t`Click here to reload.`,
40414034 t`Toggling the Experimental Macro Engine requires a reload.`,
public/scripts/preset-manager.js+0 -1
@@ -514,7 +514,6 @@ class PresetManager {
514514 console.error('Preset could not be renamed', error);
515515 throw new Error('Preset could not be renamed');
516516 }
517-
518517 }
519518
520519 /**
public/scripts/reasoning.js+0 -1
@@ -865,7 +865,6 @@ function selectReasoningTemplateCallback(args, name) {
865865 UI.$select.val(foundName).trigger('change');
866866 !quiet && toastr.success(`Reasoning template "${foundName}" selected`);
867867 return foundName;
868-
869868}
870869
871870function registerReasoningSlashCommands() {
public/scripts/samplerSelect.js+0 -1
@@ -203,7 +203,6 @@ function setSamplerListListeners() {
203203
204204 console.log(samplerName, relatedDOMElement.data(SELECT_SAMPLER.DATA), shouldDisplay);
205205 });
206-
207206}
208207
209208function isElementVisibleInDOM(element) {
public/scripts/showdown-underscore.js+1 -1
@@ -9,7 +9,7 @@ export const markdownUnderscoreExt = () => {
99 return [{
1010 type: 'output',
1111 regex: new RegExp('(<code(?:\\s+[^>]*)?>[\\s\\S]*?<\\/code>|<style(?:\\s+[^>]*)?>[\\s\\S]*?<\\/style>)|\\b(?<!_)_(?!_)(.*?)(?<!_)_(?!_)\\b', 'gi'),
1212 replace: function (match, tagContent, italicContent) {
1313 if (tagContent) {
1414 // If it's inside <code> or <style> tags, return unchanged
1515 return match;
public/scripts/slash-commands.js+0 -2
@@ -4916,7 +4916,6 @@ export async function sendNarratorMessage(args, text) {
49164916}
49174917
49184918export async function promptQuietForLoudResponse(who, text) {
4919-
49204919 let character_id = getContext().characterId;
49214920 if (who === 'sys') {
49224921 text = 'System: ' + text;
@@ -4955,7 +4954,6 @@ export async function promptQuietForLoudResponse(who, text) {
49554954 addOneMessage(message);
49564955 await eventSource.emit(event_types.USER_MESSAGE_RENDERED, (chat.length - 1));
49574956 await saveChatConditional();
4958-
49594957}
49604958
49614959async function sendCommentMessage(args, text) {
public/scripts/slash-commands/SlashCommand.js+3 -6
@@ -26,7 +26,6 @@ import { SlashCommandScope } from './SlashCommandScope.js';
2626*/
2727
2828
29-
3029export class SlashCommand {
3130 /**
3231 * Creates a SlashCommand from a properties object.
@@ -48,8 +47,6 @@ export class SlashCommand {
4847 }
4948
5049
51-
52-
5350 /**@type {string}*/ name;
5451 /**@type {(namedArguments:NamedArguments, unnamedArguments:UnnamedArguments)=>string|SlashCommandClosure|Promise<string|SlashCommandClosure>}*/ callback;
5552 /**@type {string}*/ helpString;
@@ -86,7 +83,7 @@ export class SlashCommand {
8683 name.classList.add('name');
8784 name.classList.add('monospace');
8885 name.textContent = '/';
8986 key.split('').forEach(char => {
9087 const span = document.createElement('span'); {
9188 span.textContent = char;
9289 name.append(span);
@@ -229,7 +226,7 @@ export class SlashCommand {
229226 const unnamedArguments = cmd.unnamedArgumentList ?? [];
230227 const returnType = cmd.returns ?? 'void';
231228 const helpString = cmd.helpString ?? 'NO DETAILS';
232229 const aliasList = [cmd.name, ...(cmd.aliases ?? [])].filter(it => it != key);
233230 const specs = document.createElement('div'); {
234231 specs.classList.add('specs');
235232 const head = document.createElement('div'); {
@@ -257,7 +254,7 @@ export class SlashCommand {
257254 this.isExtension ? 'Extension' : 'Core',
258255 this.isThirdParty ? 'Third Party' : (this.isExtension ? 'Core' : null),
259256 this.source,
260257 ].filter(it => it).join('\n');
261258 head.append(src);
262259 }
263260 if (this.rawQuotes) {
public/scripts/slash-commands/SlashCommandArgument.js+1 -2
@@ -5,7 +5,6 @@ import { SlashCommandExecutor } from './SlashCommandExecutor.js';
55import { SlashCommandScope } from './SlashCommandScope.js';
66
77
8-
98/**@readonly*/
109/**@enum {string}*/
1110export const ARGUMENT_TYPE = {
@@ -68,7 +67,7 @@ export class SlashCommandArgument {
6867 this.isRequired = isRequired ?? false;
6968 this.acceptsMultiple = acceptsMultiple ?? false;
7069 this.defaultValue = defaultValue;
7170 this.enumList = (enums ? Array.isArray(enums) ? enums : [enums] : []).map(it => {
7271 if (it instanceof SlashCommandEnumValue) return it;
7372 return new SlashCommandEnumValue(it);
7473 });
public/scripts/slash-commands/SlashCommandAutoCompleteNameResult.js+13 -13
@@ -22,11 +22,11 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
2222 executor.start,
2323 Object
2424 .keys(commands)
2525 .map(key => new SlashCommandCommandAutoCompleteOption(commands[key], key))
2626 ,
2727 false,
2828 () => `No matching slash commands for "/${this.name}"`,
2929 () => 'No slash commands found!',
3030 );
3131 this.executor = executor;
3232 this.scope = scope;
@@ -63,7 +63,7 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
6363 if (!Array.isArray(this.executor.command?.namedArgumentList)) {
6464 return null;
6565 }
6666 const notProvidedNamedArguments = this.executor.command.namedArgumentList.filter(arg => !this.executor.namedArgumentList.find(it => it.name == arg.name));
6767 let name;
6868 let value;
6969 let start;
@@ -73,13 +73,13 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
7373 const namedArgsFollowedBySpace = text[this.executor.endNamedArgs] == ' ';
7474 if (this.executor.startNamedArgs <= index && this.executor.endNamedArgs + (namedArgsFollowedBySpace ? 1 : 0) >= index) {
7575 // cursor is somewhere within the named arguments (including final space)
7676 argAssign = this.executor.namedArgumentList.find(it => it.start <= index && it.end >= index);
7777 if (argAssign) {
7878 const [argName, ...v] = text.slice(argAssign.start, index).split(getSplitRegex());
7979 name = argName;
8080 value = v.join('');
8181 start = argAssign.start;
8282 cmdArg = this.executor.command.namedArgumentList.find(it => [it.name, `${it.name}=`].includes(argAssign.name));
8383 if (cmdArg) notProvidedNamedArguments.push(cmdArg);
8484 } else {
8585 name = '';
@@ -106,13 +106,13 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
106106 // if cursor is already behind "=" check for enums
107107 const enumList = cmdArg?.enumProvider?.(this.executor, this.scope) ?? cmdArg?.enumList;
108108 if (cmdArg && enumList?.length) {
109109 if (isSelect && enumList.find(it => it.value == value) && argAssign && argAssign.end == index) {
110110 return null;
111111 }
112112 const result = new AutoCompleteSecondaryNameResult(
113113 value,
114114 start + name.length,
115115 enumList.map(it => SlashCommandEnumAutoCompleteOption.from(this.executor.command, it)),
116116 true,
117117 );
118118 result.isRequired = true;
@@ -125,10 +125,10 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
125125 const result = new AutoCompleteSecondaryNameResult(
126126 name,
127127 start,
128128 notProvidedNamedArguments.map(it => new SlashCommandNamedArgumentAutoCompleteOption(it, this.executor.command)),
129129 false,
130130 );
131131 result.isRequired = notProvidedNamedArguments.find(it => it.isRequired) != null;
132132 return result;
133133 }
134134
@@ -147,7 +147,7 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
147147 let argAssign;
148148 if (this.executor.startUnnamedArgs <= index && this.executor.endUnnamedArgs + 1 >= index) {
149149 // cursor is somwehere in the unnamed args
150150 const idx = this.executor.unnamedArgumentList.findIndex(it => it.start <= index && it.end >= index);
151151 if (idx > -1) {
152152 argAssign = this.executor.unnamedArgumentList[idx];
153153 cmdArg = this.executor.command.unnamedArgumentList[idx];
@@ -179,10 +179,10 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
179179 const result = new AutoCompleteSecondaryNameResult(
180180 value,
181181 start,
182182 enumList.map(it => SlashCommandEnumAutoCompleteOption.from(this.executor.command, it)),
183183 false,
184184 );
185185 const isCompleteValue = enumList.find(it => it.value == value);
186186 const isSelectedValue = isSelect && isCompleteValue;
187187 result.isRequired = cmdArg.isRequired && !isSelectedValue;
188188 result.forceMatch = cmdArg.forceEnum;
public/scripts/slash-commands/SlashCommandBrowser.js+15 -15
@@ -25,7 +25,7 @@ export class SlashCommandBrowser {
2525 inp.classList.add('text_pole');
2626 inp.type = 'search';
2727 inp.placeholder = 'Search slash commands - use quotes to search "literal" instead of fuzzy';
2828 inp.addEventListener('input', () => {
2929 this.details?.remove();
3030 this.details = null;
3131 let query = inp.value.trim();
@@ -38,7 +38,7 @@ export class SlashCommandBrowser {
3838 const match = queryRegex.exec(query);
3939 if (!match) break;
4040 if (match[1] !== undefined) {
4141 fuzzyList.push(new RegExp(`^(.*?)${match[1].split('').map(char => `(${escapeRegex(char)})`).join('(.*?)')}(.*?)$`, 'i'));
4242 } else if (match[2] !== undefined) {
4343 quotedList.push(match[2]);
4444 }
@@ -47,17 +47,17 @@ export class SlashCommandBrowser {
4747 for (const cmd of this.cmdList) {
4848 const targets = [
4949 cmd.name,
5050 ...cmd.namedArgumentList.map(it => it.name),
5151 ...cmd.namedArgumentList.map(it => it.description),
5252 ...cmd.namedArgumentList.map(it => it.enumList.map(e => e.value)).flat(),
5353 ...cmd.namedArgumentList.map(it => it.typeList).flat(),
5454 ...cmd.unnamedArgumentList.map(it => it.description),
5555 ...cmd.unnamedArgumentList.map(it => it.enumList.map(e => e.value)).flat(),
5656 ...cmd.unnamedArgumentList.map(it => it.typeList).flat(),
5757 ...cmd.aliases,
5858 cmd.helpString,
5959 ];
6060 const find = () => targets.find(t => (fuzzyList.find(f => f.test(t)) ?? quotedList.find(q => t.includes(q))) !== undefined) !== undefined;
6161 if (fuzzyList.length + quotedList.length === 0 || find()) {
6262 this.itemMap[cmd.name].classList.remove('isFiltered');
6363 } else {
@@ -85,7 +85,7 @@ export class SlashCommandBrowser {
8585 const item = cmd.renderHelpItem();
8686 this.itemMap[cmd.name] = item;
8787 let details;
8888 item.addEventListener('click', () => {
8989 if (!details) {
9090 details = document.createElement('div'); {
9191 details.classList.add('autoComplete-detailsWrap');
@@ -97,7 +97,7 @@ export class SlashCommandBrowser {
9797 }
9898 }
9999 if (this.details !== details) {
100100 Array.from(list.querySelectorAll('.selected')).forEach(it => it.classList.remove('selected'));
101101 item.classList.add('selected');
102102 this.details?.remove();
103103 container.append(details);
@@ -122,13 +122,13 @@ export class SlashCommandBrowser {
122122 }
123123 parent.append(this.dom);
124124
125125 this.mo = new MutationObserver(muts => {
126126 if (muts.find(mut => Array.from(mut.removedNodes).find(it => it === this.dom || it.contains(this.dom)))) {
127127 this.mo.disconnect();
128128 window.removeEventListener('keydown', boundHandler);
129129 }
130130 });
131131 this.mo.observe(document.querySelector('#chat'), { childList: true, subtree: true });
132132 const boundHandler = this.handleKeyDown.bind(this);
133133 window.addEventListener('keydown', boundHandler);
134134 return this.dom;
public/scripts/slash-commands/SlashCommandClosure.js+17 -17
@@ -37,7 +37,7 @@ export class SlashCommandClosure {
3737
3838 /**@type {number}*/
3939 get commandCount() {
4040 return this.executorList.map(executor => executor.commandCount).reduce((sum, cur) => sum + cur, 0);
4141 }
4242
4343 constructor(parent) {
@@ -156,7 +156,7 @@ export class SlashCommandClosure {
156156 let isList = false;
157157 let listValues = [];
158158 scope = scope ?? this.scope;
159159 const escapeMacro = (it, isAnchored = false) => {
160160 const regexText = escapeRegex(it.key.replace(/\*/g, '~~~WILDCARD~~~'))
161161 .replaceAll('~~~WILDCARD~~~', '(?:(?:(?!(?:::|}})).)*)')
162162 ;
@@ -165,7 +165,7 @@ export class SlashCommandClosure {
165165 }
166166 return regexText;
167167 };
168168 const macroList = scope.macroList.toSorted((a, b) => {
169169 if (a.key.includes('*') && !b.key.includes('*')) return 1;
170170 if (!a.key.includes('*') && b.key.includes('*')) return -1;
171171 if (a.key.includes('*') && b.key.includes('*')) return b.key.indexOf('*') - a.key.indexOf('*');
@@ -174,7 +174,7 @@ export class SlashCommandClosure {
174174 if (power_user.experimental_macro_engine) {
175175 return this.substituteWithMacroEngine(text, scope, macroList);
176176 }
177177 const macros = macroList.map(it => escapeMacro(it)).join('|');
178178 const re = new RegExp(`(?<pipe>{{pipe}})|(?:{{var::(?<var>[^\\s]+?)(?:::(?<varIndex>(?!}}).+))?}})|(?:{{(?<macro>${macros})}})`);
179179 let done = '';
180180 let remaining = text;
@@ -182,7 +182,7 @@ export class SlashCommandClosure {
182182 const match = re.exec(remaining);
183183 const before = substituteParams(remaining.slice(0, match.index));
184184 const after = remaining.slice(match.index + match[0].length);
185185 const replacer = match.groups.pipe ? scope.pipe : match.groups.var ? scope.getVariable(match.groups.var, match.groups.index) : macroList.find(it => it.key == match.groups.macro || new RegExp(escapeMacro(it, true)).test(match.groups.macro))?.value;
186186 if (replacer instanceof SlashCommandClosure) {
187187 replacer.abortController = this.abortController;
188188 replacer.breakController = this.breakController;
@@ -253,7 +253,7 @@ export class SlashCommandClosure {
253253 return step.value;
254254 }
255255
256256 async * executeDirect() {
257257 this.debugController?.down(this);
258258 // closure arguments
259259 for (const arg of this.argumentList) {
@@ -325,10 +325,10 @@ export class SlashCommandClosure {
325325 // breakpoint has to yield before arguments are resolved if one of the
326326 // arguments is an immediate closure, otherwise you cannot step into the
327327 // immediate closure
328328 const hasImmediateClosureInNamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.namedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
329329 const hasImmediateClosureInUnnamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.unnamedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
330330 if (hasImmediateClosureInNamedArgs || hasImmediateClosureInUnnamedArgs) {
331331 this.debugController.isStepping = yield { closure: this, executor: step.value };
332332 } else {
333333 this.debugController.isStepping = true;
334334 this.debugController.stepStack[this.debugController.stepStack.length - 1] = true;
@@ -338,10 +338,10 @@ export class SlashCommandClosure {
338338 this.debugController.isSteppingInto = false;
339339 // if stepping, have to yield before arguments are resolved if one of the arguments
340340 // is an immediate closure, otherwise you cannot step into the immediate closure
341341 const hasImmediateClosureInNamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.namedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
342342 const hasImmediateClosureInUnnamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.unnamedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
343343 if (hasImmediateClosureInNamedArgs || hasImmediateClosureInUnnamedArgs) {
344344 this.debugController.isStepping = yield { closure: this, executor: step.value };
345345 }
346346 }
347347 // resolve args
@@ -354,7 +354,7 @@ export class SlashCommandClosure {
354354 }
355355 } else if (!step.done && this.debugController?.testStepping(this)) {
356356 this.debugController.isSteppingInto = false;
357357 this.debugController.isStepping = yield { closure: this, executor: step.value };
358358 }
359359 // execute executor
360360 step = await stepper.next();
@@ -377,7 +377,7 @@ export class SlashCommandClosure {
377377 * - after arguments are resolved
378378 * - after execution
379379 */
380380 async * executeStep() {
381381 let done = 0;
382382 let isFirst = true;
383383 for (const executor of this.executorList) {
@@ -429,7 +429,7 @@ export class SlashCommandClosure {
429429 // then yield for "before exec"
430430 yield executor;
431431 // followed by command execution
432432 executor.onProgress = (subDone, subTotal) => this.onProgress?.(done + subDone, this.commandCount);
433433 const isStepping = this.debugController?.testStepping(this);
434434 if (this.debugController) {
435435 this.debugController.isStepping = false || this.debugController.isSteppingInto;
@@ -586,7 +586,7 @@ export class SlashCommandClosure {
586586 if (!executor.command.splitUnnamedArgument) {
587587 if (value.length == 1) {
588588 value = value[0];
589589 } else if (!value.find(it => it instanceof SlashCommandClosure)) {
590590 value = value.join('');
591591 }
592592 }
@@ -598,7 +598,7 @@ export class SlashCommandClosure {
598598 ?.replace(/\\\}/g, '}')
599599 ;
600600 } else if (Array.isArray(value)) {
601601 value = value.map(v => {
602602 if (typeof v == 'string') {
603603 return v
604604 ?.replace(/\\\{/g, '{')
public/scripts/slash-commands/SlashCommandCommandAutoCompleteOption.js+0 -2
@@ -10,8 +10,6 @@ export class SlashCommandCommandAutoCompleteOption extends AutoCompleteOption {
1010 }
1111
1212
13-
14-
1513 /**
1614 * @param {SlashCommand} command
1715 * @param {string} name
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js+1 -1
@@ -155,7 +155,7 @@ export const commonEnumProviders = {
155155 ...isAll || types.includes('scope') ? scope.allVariableNames.map(name => new SlashCommandEnumValue(name, null, enumTypes.variable, enumIcons.scopeVariable)) : [],
156156 ...isAll || types.includes('local') ? Object.keys(chat_metadata.variables ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.name, enumIcons.localVariable)) : [],
157157 ...isAll || types.includes('global') ? Object.keys(extension_settings.variables.global ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.macro, enumIcons.globalVariable)) : [],
158158 ].filter((item, idx, list) => idx == list.findIndex(it => it.value == item.value));
159159 },
160160
161161 /**
public/scripts/slash-commands/SlashCommandDebugController.js+4 -9
@@ -18,15 +18,11 @@ export class SlashCommandDebugController {
1818 /** @type {(closure:SlashCommandClosure, executor:SlashCommandExecutor)=>Promise<boolean>} */ onBreakPoint;
1919
2020
21-
22-
2321 testStepping(closure) {
2422 return this.stepStack[this.stack.indexOf(closure)];
2523 }
2624
2725
28-
29-
3026 down(closure) {
3127 this.stack.push(closure);
3228 if (this.stepStack.length < this.stack.length) {
@@ -44,20 +40,19 @@ export class SlashCommandDebugController {
4440 }
4541
4642
47-
4843 resume() {
4944 this.continueResolver?.(false);
5045 this.continuePromise = null;
5146 this.stepStack.forEach((_, idx) => this.stepStack[idx] = false);
5247 }
5348 step() {
5449 this.stepStack.forEach((_, idx) => this.stepStack[idx] = true);
5550 this.continueResolver?.(true);
5651 this.continuePromise = null;
5752 }
5853 stepInto() {
5954 this.isSteppingInto = true;
6055 this.stepStack.forEach((_, idx) => this.stepStack[idx] = true);
6156 this.continueResolver?.(true);
6257 this.continuePromise = null;
6358 }
@@ -69,7 +64,7 @@ export class SlashCommandDebugController {
6964 }
7065
7166 async awaitContinue() {
7267 this.continuePromise ??= new Promise(resolve => {
7368 this.continueResolver = resolve;
7469 });
7570 this.isStepping = await this.continuePromise;
public/scripts/slash-commands/SlashCommandEnumAutoCompleteOption.js+1 -2
@@ -9,7 +9,7 @@ export class SlashCommandEnumAutoCompleteOption extends AutoCompleteOption {
99 * @returns {SlashCommandEnumAutoCompleteOption}
1010 */
1111 static from(cmd, enumValue) {
1212 const mapped = this.valueToOptionMap.find(it => enumValue instanceof it.value)?.option ?? this;
1313 return new mapped(cmd, enumValue);
1414 }
1515 /**@type {{value:(typeof SlashCommandEnumValue), option:(typeof SlashCommandEnumAutoCompleteOption)}[]} */
@@ -18,7 +18,6 @@ export class SlashCommandEnumAutoCompleteOption extends AutoCompleteOption {
1818 /**@type {SlashCommandEnumValue}*/ enumValue;
1919
2020
21-
2221 /**
2322 * @param {SlashCommand} cmd
2423 * @param {SlashCommandEnumValue} enumValue
public/scripts/slash-commands/SlashCommandExecutionError.js+0 -1
@@ -48,7 +48,6 @@ export class SlashCommandExecutionError extends Error {
4848 }
4949
5050
51-
5251 constructor(cause, message, commandName, start, end, commandText, fullText) {
5352 super(message, { cause });
5453 this.commandName = commandName;
public/scripts/slash-commands/SlashCommandExecutor.js+6 -6
@@ -17,10 +17,10 @@ export class SlashCommandExecutor {
1717 get source() { return this.#source; }
1818 set source(value) {
1919 this.#source = value;
2020 for (const arg of this.namedArgumentList.filter(it => it.value instanceof SlashCommandClosure)) {
2121 arg.value.source = value;
2222 }
2323 for (const arg of this.unnamedArgumentList.filter(it => it.value instanceof SlashCommandClosure)) {
2424 arg.value.source = value;
2525 }
2626 }
@@ -31,15 +31,15 @@ export class SlashCommandExecutor {
3131
3232 get commandCount() {
3333 return 1
3434 + this.namedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it =>/**@type {SlashCommandClosure}*/(it.value).commandCount).reduce((cur, sum) => cur + sum, 0)
3535 + this.unnamedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it =>/**@type {SlashCommandClosure}*/(it.value).commandCount).reduce((cur, sum) => cur + sum, 0)
3636 ;
3737 }
3838
3939 set onProgress(value) {
4040 const closures = /**@type {SlashCommandClosure[]}*/([
4141 ...this.namedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it => it.value),
4242 ...this.unnamedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it => it.value),
4343 ]);
4444 for (const closure of closures) {
4545 closure.onProgress = value;
public/scripts/slash-commands/SlashCommandParser.js+20 -20
@@ -65,7 +65,7 @@ export class SlashCommandParser {
6565 static addCommandObject(command) {
6666 const reserved = ['/', '#', ':', 'parser-flag', 'breakpoint'];
6767 for (const start of reserved) {
6868 if (command.name.toLowerCase().startsWith(start) || (command.aliases ?? []).find(a => a.toLowerCase().startsWith(start))) {
6969 throw new Error(`Illegal Name. Slash command name cannot begin with "${start}".`);
7070 }
7171 }
@@ -80,15 +80,15 @@ export class SlashCommandParser {
8080 console.trace('WARN: Duplicate slash command registered!', [command.name, ...command.aliases]);
8181 }
8282
8383 const stack = new Error().stack.split('\n').map(it => it.trim());
8484 command.isExtension = stack.find(it => it.includes('/scripts/extensions/')) != null;
8585 command.isThirdParty = stack.find(it => it.includes('/scripts/extensions/third-party/')) != null;
8686 if (command.isThirdParty) {
8787 command.source = stack.find(it => it.includes('/scripts/extensions/third-party/')).replace(/^.*?\/scripts\/extensions\/third-party\/([^/]+)\/.*$/, '$1');
8888 } else if (command.isExtension) {
8989 command.source = stack.find(it => it.includes('/scripts/extensions/')).replace(/^.*?\/scripts\/extensions\/([^/]+)\/.*$/, '$1');
9090 } else {
9191 const idx = stack.findLastIndex(it => it.includes('at SlashCommandParser.')) + 1;
9292 command.source = stack[idx].replace(/^.*?\/((?:scripts\/)?(?:[^/]+)\.js).*$/, '$1');
9393 }
9494
@@ -153,7 +153,7 @@ export class SlashCommandParser {
153153 description: 'The parser flag to modify.',
154154 typeList: [ARGUMENT_TYPE.STRING],
155155 isRequired: true,
156156 enumList: Object.keys(PARSER_FLAG).map(flag => new SlashCommandEnumValue(flag, help[PARSER_FLAG[flag]])),
157157 }),
158158 SlashCommandArgument.fromProps({
159159 description: 'The state of the parser flag to set.',
@@ -439,7 +439,7 @@ export class SlashCommandParser {
439439 PIPEBREAK,
440440 PIPE,
441441 );
442442 hljs.registerLanguage('stscript', () => ({
443443 case_insensitive: false,
444444 keywords: [],
445445 contains: [
@@ -480,19 +480,19 @@ export class SlashCommandParser {
480480 }
481481 }
482482 const executor = this.commandIndex
483483 .filter(it => it.start <= index && (it.end >= index || it.end == null))
484484 .slice(-1)[0]
485485 ?? null
486486 ;
487487
488488 if (executor) {
489489 const childClosure = this.closureIndex
490490 .find(it => it.start <= index && (it.end >= index || it.end == null) && it.start > executor.start)
491491 ?? null
492492 ;
493493 if (childClosure !== null) return null;
494494 // Check if cursor is inside a macro
495495 const macroEntry = this.macroIndex.findLast(it => it.start <= index && it.end >= index);
496496 if (macroEntry) {
497497 // Build macro info object for shared function
498498 const macroContent = text.slice(macroEntry.start + 2, macroEntry.end - (text.slice(macroEntry.end - 2, macroEntry.end) === '}}' ? 2 : 0));
@@ -522,16 +522,16 @@ export class SlashCommandParser {
522522 if (executor.name == ':') {
523523 const options = this.scopeIndex[this.commandIndex.indexOf(executor)]
524524 ?.allVariableNames
525525 ?.map(it => new SlashCommandVariableAutoCompleteOption(it))
526526 ?? []
527527 ;
528528 try {
529529 if ('quickReplyApi' in globalThis) {
530530 const qrApi = globalThis.quickReplyApi;
531531 options.push(...qrApi.listSets()
532532 .map(set => qrApi.listQuickReplies(set).map(qr => `${set}.${qr}`))
533533 .flat()
534534 .map(qr => new SlashCommandQuickReplyAutoCompleteOption(qr)),
535535 );
536536 }
537537 } catch { /* empty */ }
@@ -540,8 +540,8 @@ export class SlashCommandParser {
540540 executor.start,
541541 options,
542542 true,
543543 () => `No matching variables in scope and no matching Quick Replies for "${result.name}"`,
544544 () => 'No variables in scope and no Quick Replies found.',
545545 );
546546 return result;
547547 }
@@ -741,7 +741,7 @@ export class SlashCommandParser {
741741 return this.testSymbol(':}');
742742 }
743743 parseClosure(isRoot = false) {
744744 const closureIndexEntry = { start: this.index + 1, end: null };
745745 this.closureIndex.push(closureIndexEntry);
746746 let injectPipe = true;
747747 if (!isRoot) this.take(2); // discard opening {:
@@ -1023,14 +1023,14 @@ export class SlashCommandParser {
10231023 cmd.unnamedArgumentList = this.parseUnnamedArgument(cmd.command?.unnamedArgumentList?.length && cmd?.command?.splitUnnamedArgument, cmd?.command?.splitUnnamedArgumentCount, rawQuotes);
10241024 cmd.endUnnamedArgs = this.index;
10251025 if (cmd.name == 'let') {
10261026 const keyArg = cmd.namedArgumentList.find(it => it.name == 'key');
10271027 if (keyArg) {
10281028 this.scope.variableNames.push(keyArg.value.toString());
10291029 } else if (typeof cmd.unnamedArgumentList[0]?.value == 'string') {
10301030 this.scope.variableNames.push(cmd.unnamedArgumentList[0].value);
10311031 }
10321032 } else if (cmd.name == 'import') {
10331033 const value = /**@type {string[]}*/(cmd.unnamedArgumentList.map(it => it.value));
10341034 for (let i = 0; i < value.length; i++) {
10351035 const srcName = value[i];
10361036 let dstName = srcName;
public/scripts/slash-commands/SlashCommandScope.js+3 -5
@@ -5,7 +5,7 @@ export class SlashCommandScope {
55 /** @type {string[]} */ variableNames = [];
66 get allVariableNames() {
77 const names = [...this.variableNames, ...(this.parent?.allVariableNames ?? [])];
88 return names.filter((it, idx) => idx == names.indexOf(it));
99 }
1010 // @ts-ignore
1111 /** @type {object.<string, string|SlashCommandClosure>} */ variables = {};
@@ -13,7 +13,7 @@ export class SlashCommandScope {
1313 /** @type {object.<string, string|SlashCommandClosure>} */ macros = {};
1414 /** @type {{key:string, value:string|SlashCommandClosure}[]} */
1515 get macroList() {
1616 return [...Object.keys(this.macros).map(key => ({ key, value: this.macros[key] })), ...(this.parent?.macroList ?? [])];
1717 }
1818 /** @type {SlashCommandScope} */ parent;
1919 /** @type {string} */ #pipe;
@@ -40,7 +40,7 @@ export class SlashCommandScope {
4040
4141
4242 setMacro(key, value, overwrite = true) {
4343 if (overwrite || !this.macroList.find(it => it.key == key)) {
4444 this.macros[key] = value;
4545 }
4646 }
@@ -109,8 +109,6 @@ export class SlashCommandScope {
109109}
110110
111111
112-
113-
114112export class SlashCommandScopeVariableExistsError extends Error {}
115113
116114
public/scripts/tags.js+0 -1
@@ -2091,7 +2091,6 @@ function onTagAsFolderClick() {
20912091 // If folder display has changed, we have to redraw the character list, otherwise this folders state would not change
20922092 printCharactersDebounced();
20932093 saveSettingsDebounced();
2094-
20952094}
20962095
20972096function updateDrawTagFolder(element, tag) {
public/scripts/textgen-settings.js+2 -3
@@ -802,7 +802,6 @@ async function getStatusTextgen() {
802802 console.info('Status check aborted.', err.reason);
803803 } else {
804804 console.error('Error getting status', err);
805-
806805 }
807806 setOnlineStatus('no_connection');
808807 }
@@ -1126,7 +1125,7 @@ export function initTextGenSettings() {
11261125 * @returns void
11271126 */
11281127function showSamplerControls(apiType = null) {
11291128 $('#textgenerationwebui_api-settings [data-tg-samplers], #textgenerationwebui_api [data-tg-samplers]').each(function (idx, elem) {
11301129 const typeSpecificControlled = $(elem).data('tg-type') !== undefined;
11311130
11321131 if (!typeSpecificControlled) $(this).show();
@@ -1139,7 +1138,7 @@ function showSamplerControls(apiType = null) {
11391138
11401139 if (!samplersActivatedManually?.length || !prioritizeManualSamplerSelect) return;
11411140
11421141 $('#textgenerationwebui_api-settings [data-tg-samplers], #textgenerationwebui_api [data-tg-samplers]').each(function () {
11431142 const tgSamplers = $(this).attr('data-tg-samplers').split(',').map(x => x.trim()).filter(str => str !== '');
11441143
11451144 for (const tgSampler of tgSamplers) {
public/scripts/user.js+0 -4
@@ -455,7 +455,6 @@ async function changeName(handle, name, callback) {
455455
456456 toastr.success('Name changed successfully', 'Name Changed');
457457 callback();
458-
459458 } catch (error) {
460459 console.error('Error changing name:', error);
461460 }
@@ -495,7 +494,6 @@ async function restoreSnapshot(name, callback) {
495494 } catch (error) {
496495 console.error('Error restoring snapshot:', error);
497496 }
498-
499497}
500498
501499/**
@@ -601,7 +599,6 @@ async function viewSettingsSnapshots() {
601599 const content = await loadSnapshotContent(snapshot.name);
602600 contentBlock.val(content);
603601 }
604-
605602 });
606603 template.find('.snapshotList').append(snapshotBlock);
607604 }
@@ -667,7 +664,6 @@ async function resetEverything(callback) {
667664 } catch (error) {
668665 console.error('Error resetting everything:', error);
669666 }
670-
671667}
672668
673669async function openUserProfile() {
public/scripts/utils.js+0 -1
@@ -2310,7 +2310,6 @@ export function highlightRegex(regexStr) {
23102310 flags: new RegExp('(?<=\\/)([gimsuy]*)$', 'g'), // Match trailing flags
23112311 delimiters: new RegExp('^\\/|(?<![\\\\<])\\/', 'g'), // Match leading or trailing delimiters
23122312 };
2313-
23142313 } catch (error) {
23152314 return {
23162315 brackets: new RegExp('(\\\\)?\\[.*?\\]', 'g'), // Non-escaped square brackets
public/scripts/world-info.js+0 -2
@@ -675,7 +675,6 @@ class WorldInfoTimedEffects {
675675 console.log('[WI] Timed effect "delay" applied to entry', entry);
676676 }
677677 }
678-
679678 }
680679
681680 /**
@@ -4495,7 +4494,6 @@ function parseDecorators(content) {
44954494 }
44964495
44974496 return [[], content];
4498-
44994497}
45004498
45014499/**
src/endpoints/assets.js+0 -2
@@ -111,7 +111,6 @@ router.post('/get', async (request, response) => {
111111
112112 try {
113113 if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
114-
115114 ensureFoldersExist(request.user.directories);
116115
117116 const folders = fs.readdirSync(folderPath, { withFileTypes: true })
@@ -346,7 +345,6 @@ router.post('/character', async (request, response) => {
346345 let output = [];
347346 try {
348347 if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
349-
350348 // Live2d assets
351349 if (category == 'live2d') {
352350 const folders = fs.readdirSync(folderPath, { withFileTypes: true });
src/endpoints/backends/text-completions.js+0 -2
@@ -541,7 +541,6 @@ llamacpp.post('/props', async function (request, response) {
541541 console.debug('LlamaCpp props response:', data);
542542
543543 return response.send(data);
544-
545544 } catch (error) {
546545 console.error(error);
547546 return response.sendStatus(500);
@@ -591,7 +590,6 @@ llamacpp.post('/slots', async function (request, response) {
591590 console.debug('LlamaCpp slots response:', data);
592591
593592 return response.send(data);
594-
595593 } catch (error) {
596594 console.error(error);
597595 return response.sendStatus(500);
src/endpoints/backups.js+1 -1
@@ -11,7 +11,7 @@ router.post('/chat/get', async (request, response) => {
1111 const backupModels = [];
1212 const backupFiles = await fsPromises
1313 .readdir(request.user.directories.backups, { withFileTypes: true })
1414 .then(d => d .filter(d => d.isFile() && path.extname(d.name) === '.jsonl' && d.name.startsWith(CHAT_BACKUPS_PREFIX)).map(d => d.name));
1515
1616 for (const name of backupFiles) {
1717 const filePath = path.join(request.user.directories.backups, name);
src/endpoints/characters.js+2 -2
@@ -639,7 +639,6 @@ function charaFormatData(data, directories) {
639639 if (file && file.entries) {
640640 _.set(char, 'data.character_book', convertWorldInfoToCharacterBook(data.world, file.entries));
641641 }
642-
643642 } catch {
644643 console.warn(`Failed to read world info file: ${data.world}. Character book will not be available.`);
645644 }
@@ -921,7 +920,8 @@ async function importFromJson(uploadPath, { request }, preservedFileName) {
921920 let charJSON = JSON.stringify(char);
922921 const result = await writeCharacterData(DEFAULT_AVATAR_PATH, charJSON, pngName, request);
923922 return result ? pngName : '';
924923 } else if (jsonData.char_name !== undefined) {//json Pygmalion notepad
924+ //json Pygmalion notepad
925925 console.info('Importing from gradio json');
926926 jsonData.char_name = sanitize(jsonData.char_name);
927927 if (jsonData.creator_notes) {
src/endpoints/extensions.js+0 -2
@@ -367,7 +367,6 @@ router.post('/version', async (request, response) => {
367367 const { isUpToDate, remoteUrl } = await checkIfRepoIsUpToDate(extensionPath);
368368
369369 return response.send({ currentBranchName, currentCommitHash, isUpToDate, remoteUrl });
370-
371370 } catch (error) {
372371 console.error('Getting extension version failed', error);
373372 return response.status(500).send(`Server Error: ${error.message}`);
@@ -406,7 +405,6 @@ router.post('/delete', async (request, response) => {
406405 console.info(`Extension has been deleted at ${extensionPath}`);
407406
408407 return response.send(`Extension has been deleted at ${extensionPath}`);
409-
410408 } catch (error) {
411409 console.error('Deleting custom content failed', error);
412410 return response.status(500).send(`Server Error: ${error.message}`);
src/endpoints/groups.js+1 -1
@@ -51,7 +51,7 @@ export async function migrateGroupChatsMetadataFormat(userDirectories) {
5151 if (!needsMigration) {
5252 continue;
5353 }
5454 if (!fs.existsSync(backupPath)) {
5555 await fsPromises.mkdir(backupPath, { recursive: true });
5656 }
5757 await fsPromises.copyFile(groupFilePath, path.join(backupPath, groupFile.name));
src/endpoints/horde.js+0 -2
@@ -256,7 +256,6 @@ router.post('/caption-image', async (request, response) => {
256256 console.info(status);
257257
258258 if (status.state === HordeAsyncRequestStates.done) {
259-
260259 if (status.forms === undefined) {
261260 console.error('Image interrogation request failed: no forms found.');
262261 return response.sendStatus(500);
@@ -278,7 +277,6 @@ router.post('/caption-image', async (request, response) => {
278277 return response.sendStatus(503);
279278 }
280279 }
281-
282280 } catch (error) {
283281 console.error(error);
284282 response.sendStatus(500);
src/endpoints/image-metadata.js+0 -1
@@ -442,7 +442,6 @@ router.post('/', async function (request, response) {
442442 }
443443
444444 return response.status(400).json({ error: 'Invalid request format.' });
445-
446445 } catch (error) {
447446 console.error('[ImageMetadata] API error:', error);
448447 return response.status(500).json({ error: 'Internal server error.' });
src/endpoints/minimax.js+0 -2
@@ -189,7 +189,6 @@ router.post('/generate-voice', async (request, response) => {
189189 response.setHeader('Content-Length', audioBytes.length);
190190
191191 return response.send(Buffer.from(audioBytes));
192-
193192 } catch (conversionError) {
194193 console.error('MiniMax TTS: Audio conversion error:', conversionError);
195194 return response.status(500).json({ error: `Audio data conversion failed: ${conversionError.message}` });
@@ -222,7 +221,6 @@ router.post('/generate-voice', async (request, response) => {
222221 console.error('MiniMax TTS: No valid audio data in response:', responseData);
223222 return response.status(500).json({ error: `API Error: ${errorMessage}` });
224223 }
225-
226224 } catch (error) {
227225 console.error('MiniMax TTS generation failed:', error);
228226 return response.status(500).json({ error: 'Internal server error' });
src/endpoints/stable-diffusion.js+0 -1
@@ -158,7 +158,6 @@ router.post('/samplers', async (request, response) => {
158158 const data = await result.json();
159159 const names = data.map(x => x.name);
160160 return response.send(names);
161-
162161 } catch (error) {
163162 console.error(error);
164163 return response.sendStatus(500);
src/endpoints/thumbnails.js+0 -1
@@ -301,7 +301,6 @@ publicRouter.get('/', async function (request, response) {
301301
302302 // Send a 404 so the frontend can display a placeholder
303303 return response.sendStatus(404);
304-
305304 } catch (error) {
306305 console.error('Failed getting thumbnail', error);
307306 return response.sendStatus(500);
src/prompt-converters.js+1 -2
@@ -118,7 +118,6 @@ export function postProcessPrompt(messages, type, names) {
118118 * @copyright Prompt Conversion script taken from RisuAI by kwaroran (GPLv3).
119119 */
120120export function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, withSysPromptSupport, useSystemPrompt, addSysHumanMsg, excludePrefixes) {
121-
122121 //Prepare messages for claude.
123122 //When 'Exclude Human/Assistant prefixes' checked, setting messages role to the 'system'(last message is exception).
124123 if (messages.length > 0) {
@@ -1278,7 +1277,7 @@ export function calculateGoogleBudgetTokens(maxTokens, reasoningEffort, model) {
12781277 return getGemini3ProBudget();
12791278 }
12801279
12811280 if (/gemini-3-flash/.test(model) ) {
12821281 return getGemini3FlashBudget();
12831282 }
12841283
src/util.js+0 -1
@@ -1012,7 +1012,6 @@ export async function canResolve(name, useIPv6 = true, useIPv4 = true) {
10121012 }
10131013
10141014 return v6Resolved || v4Resolved;
1015-
10161015 } catch (error) {
10171016 return false;
10181017 }