Chore: Add code formatting conventions as eslint rules (#5158)
* Add code formatting conventions as eslint rules * Improve formatting in addQuickReply
This commit is contained in:
@@ -102,5 +102,28 @@ module.exports = {
|
||||
// These rules should eventually be enabled.
|
||||
'no-async-promise-executor': 'off',
|
||||
'no-inner-declarations': 'off',
|
||||
'brace-style': 'off',
|
||||
// Additional formatting rules based on codebase conventions
|
||||
'array-bracket-spacing': ['error', 'never'],
|
||||
'computed-property-spacing': ['error', 'never'],
|
||||
'block-spacing': ['error', 'always'],
|
||||
'keyword-spacing': ['error', { before: true, after: true }],
|
||||
'space-before-blocks': ['error', 'always'],
|
||||
'space-before-function-paren': ['error', { anonymous: 'always', named: 'never', asyncArrow: 'always' }],
|
||||
'space-in-parens': ['error', 'never'],
|
||||
'comma-spacing': ['error', { before: false, after: true }],
|
||||
'key-spacing': ['error', { beforeColon: false, afterColon: true }],
|
||||
'func-call-spacing': ['error', 'never'],
|
||||
'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1, maxBOF: 0 }],
|
||||
'padded-blocks': ['error', 'never'],
|
||||
'no-whitespace-before-property': 'error',
|
||||
'space-unary-ops': ['error', { words: true, nonwords: false }],
|
||||
'arrow-spacing': ['error', { before: true, after: true }],
|
||||
'template-curly-spacing': ['error', 'never'],
|
||||
'rest-spread-spacing': ['error', 'never'],
|
||||
'generator-star-spacing': ['error', { before: false, after: true }],
|
||||
'yield-star-spacing': ['error', { before: false, after: true }],
|
||||
'template-tag-spacing': ['error', 'never'],
|
||||
'switch-colon-spacing': ['error', { after: true, before: false }],
|
||||
},
|
||||
};
|
||||
|
||||
+2
-14
@@ -2516,7 +2516,6 @@ export function addOneMessage(mes, { type = undefined, insertAfter = null, scrol
|
||||
* @returns {JQuery<HTMLElement>} Rendered HTMLElement.
|
||||
*/
|
||||
export function updateMessageElement(mes, { messageId = chat.length - 1, messageElement = messageTemplate.clone(), adjustMediaScroll = SCROLL_BEHAVIOR.NONE } = {}) {
|
||||
|
||||
let avatarImg = getThumbnailUrl('persona', user_avatar);
|
||||
|
||||
//for non-user messages
|
||||
@@ -3709,9 +3708,9 @@ class StreamingProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Generator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[], state: any }, void, void>}
|
||||
* @returns {AsyncGenerator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[], state: any }, void, void>}
|
||||
*/
|
||||
*nullStreamingGeneration() {
|
||||
async* nullStreamingGeneration() {
|
||||
throw new Error('Generation function for streaming is not hooked up');
|
||||
}
|
||||
|
||||
@@ -4862,7 +4861,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
|
||||
// Add quiet generation prompt at depth 0
|
||||
if (quiet_prompt && quiet_prompt.length) {
|
||||
|
||||
// here name1 is forced for all quiet prompts..why?
|
||||
const name = name1;
|
||||
//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
|
||||
if (!isAborted && power_user.auto_swipe && generatedTextFiltered(getMessage)) {
|
||||
is_send_press = false;
|
||||
return await swipe(null, SWIPE_DIRECTION.RIGHT, { source: SWIPE_SOURCE.AUTO_SWIPE, repeated: true, forceMesId: chat.length - 1 });
|
||||
|
||||
}
|
||||
|
||||
console.debug('/api/chats/save called by /Generate');
|
||||
@@ -6517,7 +6514,6 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
|
||||
!fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
|
||||
addOneMessage(chat[chat_id], { type: 'swipe' });
|
||||
!fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
|
||||
|
||||
} else {
|
||||
console.debug('entering chat update routine for non-swipe post');
|
||||
const newMessage = {};
|
||||
@@ -8247,7 +8243,6 @@ export async function getChatsFromFiles(data, isGroupChat) {
|
||||
currentChat.shift();
|
||||
}
|
||||
chat_dict[file_name] = currentChat;
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -9588,7 +9583,6 @@ export async function createOrEditCharacter(e) {
|
||||
select_rm_info('char_create', avatarId, oldSelectedChar);
|
||||
|
||||
crop_data = undefined;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating character', error);
|
||||
toastr.error(t`Failed to create character`);
|
||||
@@ -9984,7 +9978,6 @@ export async function swipe(event, direction, { source, repeated, message = chat
|
||||
duration: 0, //used to be 100 //Disabled on Cohee's request. https://github.com/SillyTavern/SillyTavern/pull/4610/files#r2408731744
|
||||
queue: false,
|
||||
progress: function (animation, progress, remainingMs) {
|
||||
|
||||
if (is_animation_scroll) chatElement.scrollTop(getMessageBottomHeight(thisMesDiv));
|
||||
},
|
||||
complete: function () {
|
||||
@@ -10001,7 +9994,6 @@ export async function swipe(event, direction, { source, repeated, message = chat
|
||||
* @param {boolean} [skipSwipeOut=false]
|
||||
*/
|
||||
async function animateSwipe(run_generate = false, skipSwipeOut = false) {
|
||||
|
||||
if (!skipSwipeOut) {
|
||||
//Swipe out.
|
||||
await animateSwipeTransition(mesId, { xEnd: `${swipeRange}px`, duration: swipeDuration });
|
||||
@@ -10069,7 +10061,6 @@ export async function swipe(event, direction, { source, repeated, message = chat
|
||||
|
||||
//If the swipe is not being deleted.
|
||||
if (source != SWIPE_SOURCE.DELETE && source != SWIPE_SOURCE.BACK) {
|
||||
|
||||
// Make sure ad-hoc changes to extras are saved before swiping away
|
||||
syncMesToSwipe(mesId);
|
||||
|
||||
@@ -10382,7 +10373,6 @@ export async function doNewChat({ deleteCurrentChat = false } = {}) {
|
||||
await createOrEditCharacter(new CustomEvent('newChat'));
|
||||
if (deleteCurrentChat) await delChat(chat_file_for_del + '.jsonl');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -11407,9 +11397,7 @@ jQuery(async function () {
|
||||
|
||||
divchat.style.borderRadius = '';
|
||||
divchat.style.backgroundColor = '';
|
||||
|
||||
} else {
|
||||
|
||||
divchat.style.borderRadius = '10px'; // Adjust the value to control the roundness of the corners
|
||||
divchat.style.backgroundColor = ''; // Set the background color to your preference
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class CharacterContextMenu {
|
||||
* @param {number} characterId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
static persona = async (characterId) => void(await convertCharacterToPersona(characterId));
|
||||
static persona = async (characterId) => void (await convertCharacterToPersona(characterId));
|
||||
|
||||
/**
|
||||
* Delete one or more characters,
|
||||
@@ -754,7 +754,7 @@ class BulkEditOverlay {
|
||||
|
||||
handleContextMenuShow = (event) => {
|
||||
event.preventDefault();
|
||||
const [x,y] = this.#getContextMenuPosition(event);
|
||||
const [x, y] = this.#getContextMenuPosition(event);
|
||||
CharacterContextMenu.show(x, y);
|
||||
this.#contextMenuOpen = true;
|
||||
};
|
||||
|
||||
@@ -986,7 +986,6 @@ class PromptManager {
|
||||
* @returns {void}
|
||||
*/
|
||||
addPrompt(prompt, identifier) {
|
||||
|
||||
if (typeof prompt !== 'object' || prompt === null) throw new Error('Object is not a prompt');
|
||||
|
||||
const newPrompt = {
|
||||
@@ -1318,7 +1317,6 @@ class PromptManager {
|
||||
this.updatePromptByIdentifier(identifier, prompt);
|
||||
debouncedSaveServiceSettings().then(() => this.render());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,7 +101,6 @@ observer.observe(document.documentElement, observerConfig);
|
||||
* @returns {string} - A human-readable string that represents the time spent generating characters.
|
||||
*/
|
||||
export function humanizeGenTime(total_gen_time) {
|
||||
|
||||
//convert time_spent to humanized format of "_ Hours, _ Minutes, _ Seconds" from milliseconds
|
||||
let time_spent = total_gen_time || 0;
|
||||
time_spent = Math.floor(time_spent / 1000);
|
||||
@@ -1274,8 +1273,6 @@ export function initRossMods() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (event.ctrlKey && /^[1-9]$/.test(event.key)) {
|
||||
// This will eventually be to trigger quick replies
|
||||
// event.preventDefault();
|
||||
|
||||
@@ -80,8 +80,6 @@ export class AutoComplete {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {HTMLTextAreaElement|HTMLInputElement} textarea The textarea to receive autocomplete.
|
||||
* @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 {
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (this.isForceHidden) {
|
||||
// hidden with escape
|
||||
return this.hide();
|
||||
@@ -465,7 +462,6 @@ export class AutoComplete {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create updated DOM.
|
||||
*/
|
||||
@@ -514,7 +510,6 @@ export class AutoComplete {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update position of DOM.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
export class AutoCompleteFuzzyScore {
|
||||
/**@type {number}*/ start;
|
||||
/**@type {number}*/ longestConsecutive;
|
||||
|
||||
@@ -2,7 +2,6 @@ import { AutoCompleteNameResultBase } from './AutoCompleteNameResultBase.js';
|
||||
import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js';
|
||||
|
||||
|
||||
|
||||
export class AutoCompleteNameResult extends AutoCompleteNameResultBase {
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { AutoCompleteOption } from './AutoCompleteOption.js';
|
||||
|
||||
|
||||
|
||||
export class AutoCompleteNameResultBase {
|
||||
/**@type {string} */ name;
|
||||
/**@type {number} */ start;
|
||||
/**@type {AutoCompleteOption[]} */ optionList = [];
|
||||
/**@type {boolean} */ canBeQuoted = false;
|
||||
/**@type {()=>string} */ makeNoMatchText = ()=>`No matches found for "${this.name}"`;
|
||||
/**@type {()=>string} */ makeNoOptionsText = ()=>'No options';
|
||||
/**@type {()=>string} */ makeNoMatchText = () => `No matches found for "${this.name}"`;
|
||||
/**@type {()=>string} */ makeNoOptionsText = () => 'No options';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js';
|
||||
|
||||
|
||||
|
||||
export class AutoCompleteOption {
|
||||
/** @type {string} */ name;
|
||||
/** @type {string} */ typeIcon;
|
||||
@@ -72,7 +71,7 @@ export class AutoCompleteOption {
|
||||
name.classList.add('name');
|
||||
name.classList.add('monospace');
|
||||
name.textContent = noSlash ? '' : '/';
|
||||
key.split('').forEach(char=>{
|
||||
key.split('').forEach(char => {
|
||||
const span = document.createElement('span'); {
|
||||
span.textContent = char;
|
||||
name.append(span);
|
||||
|
||||
@@ -55,7 +55,7 @@ function onSelectAllButtonClick() {
|
||||
|
||||
if (!atLeastOneSelected) {
|
||||
// If none was selected, trigger click on all to deselect all of them
|
||||
for(const character of characters) {
|
||||
for (const character of characters) {
|
||||
const checked = $(character).find('.bulk_select_checkbox:checked') ?? false;
|
||||
if (checked && character instanceof HTMLElement) {
|
||||
characterGroupOverlay.toggleSingleCharacter(character);
|
||||
|
||||
@@ -150,7 +150,6 @@ function onCfgMenuItemClick() {
|
||||
setTimeout(function () {
|
||||
$('#cfgConfig').hide();
|
||||
}, animation_duration);
|
||||
|
||||
}
|
||||
//duplicate options menu close handler from script.js
|
||||
//because this listener takes priority
|
||||
|
||||
@@ -199,7 +199,7 @@ class BackupsBrowser {
|
||||
const deleteButton = document.createElement('div');
|
||||
deleteButton.classList.add('right_menu_button', 'fa-solid', 'fa-trash');
|
||||
deleteButton.title = t`Delete backup`;
|
||||
deleteButton.addEventListener('click',async () => {
|
||||
deleteButton.addEventListener('click', async () => {
|
||||
const isDeleted = await this.deleteBackup(backup.file_name);
|
||||
if (isDeleted) {
|
||||
listItem.remove();
|
||||
|
||||
@@ -251,7 +251,6 @@ class DataMaidDialog {
|
||||
categoryElement.remove();
|
||||
this.displayEmptyPlaceholder();
|
||||
});
|
||||
|
||||
});
|
||||
categoryElement.querySelectorAll('.dataMaidItemDelete').forEach(button => {
|
||||
button.addEventListener('click', async () => {
|
||||
|
||||
@@ -94,8 +94,7 @@ async function downloadAssetsList(url) {
|
||||
updateCurrentAssets().then(async function () {
|
||||
fetch(url, { cache: 'no-cache' })
|
||||
.then(response => response.json())
|
||||
.then(async function(json) {
|
||||
|
||||
.then(async function (json) {
|
||||
availableAssets = {};
|
||||
$('#assets_menu').empty();
|
||||
|
||||
|
||||
@@ -1414,7 +1414,6 @@ export async function getExpressionsList({ filterAvailable = false } = {}) {
|
||||
});
|
||||
|
||||
if (apiResult.ok) {
|
||||
|
||||
const data = await apiResult.json();
|
||||
expressionsList = data.labels;
|
||||
return expressionsList;
|
||||
@@ -1488,7 +1487,6 @@ function chooseSpriteForExpression(spriteFolderName, expression, { prevExpressio
|
||||
}
|
||||
|
||||
return spriteFile;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2333,7 +2331,7 @@ function migrateSettings() {
|
||||
name: 'expression-folder-override',
|
||||
aliases: ['spriteoverride', 'costume'],
|
||||
callback: setSpriteFolderCommand,
|
||||
namedArgumentList:[
|
||||
namedArgumentList: [
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'Character name to set a subfolder for. If not provided, the character who last sent a message will be used.',
|
||||
|
||||
@@ -791,7 +791,6 @@ async function listGalleryCommand(args) {
|
||||
|
||||
const items = await getGalleryItems(url);
|
||||
return JSON.stringify(items.map(it => it.src));
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
@@ -10,22 +10,18 @@ export class QuickReplyApi {
|
||||
/** @type {SettingsUi} */ settingsUi;
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(/** @type {QuickReplySettings} */settings, /** @type {SettingsUi} */settingsUi) {
|
||||
this.settings = settings;
|
||||
this.settingsUi = settingsUi;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {QuickReply} qr
|
||||
* @returns {QuickReplySet}
|
||||
*/
|
||||
getSetByQr(qr) {
|
||||
return QuickReplySet.list.find(it=>it.qrList.includes(qr));
|
||||
return QuickReplySet.list.find(it => it.qrList.includes(qr));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,13 +44,11 @@ export class QuickReplyApi {
|
||||
getQrByLabel(setName, label) {
|
||||
const set = this.getSetByName(setName);
|
||||
if (!set) return;
|
||||
if (Number.isInteger(label)) return set.qrList.find(it=>it.id == label);
|
||||
return set.qrList.find(it=>it.label == label);
|
||||
if (Number.isInteger(label)) return set.qrList.find(it => it.id == label);
|
||||
return set.qrList.find(it => it.label == label);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes a quick reply by its index and returns the result.
|
||||
*
|
||||
@@ -63,7 +57,7 @@ export class QuickReplyApi {
|
||||
*/
|
||||
async executeQuickReplyByIndex(idx) {
|
||||
const qr = [...this.settings.config.setList, ...(this.settings.chatConfig?.setList ?? [])]
|
||||
.map(it=>it.set.qrList)
|
||||
.map(it => it.set.qrList)
|
||||
.flat()[idx]
|
||||
;
|
||||
if (qr) {
|
||||
@@ -400,7 +394,7 @@ export class QuickReplyApi {
|
||||
if (oldSet) {
|
||||
QuickReplySet.list.splice(QuickReplySet.list.indexOf(oldSet), 1, set);
|
||||
} else {
|
||||
const idx = QuickReplySet.list.findIndex(it=>it.name.localeCompare(name) == 1);
|
||||
const idx = QuickReplySet.list.findIndex(it => it.name.localeCompare(name) == 1);
|
||||
if (idx > -1) {
|
||||
QuickReplySet.list.splice(idx, 0, set);
|
||||
} else {
|
||||
@@ -460,7 +454,7 @@ export class QuickReplyApi {
|
||||
* @returns array with the names of all quick reply sets
|
||||
*/
|
||||
listSets() {
|
||||
return QuickReplySet.list.map(it=>it.name);
|
||||
return QuickReplySet.list.map(it => it.name);
|
||||
}
|
||||
/**
|
||||
* Gets a list of all globally active quick reply sets.
|
||||
@@ -468,7 +462,7 @@ export class QuickReplyApi {
|
||||
* @returns array with the names of all quick reply sets
|
||||
*/
|
||||
listGlobalSets() {
|
||||
return this.settings.config.setList.map(it=>it.set.name);
|
||||
return this.settings.config.setList.map(it => it.set.name);
|
||||
}
|
||||
/**
|
||||
* Gets a list of all quick reply sets activated by the current chat.
|
||||
@@ -476,7 +470,7 @@ export class QuickReplyApi {
|
||||
* @returns array with the names of all quick reply sets
|
||||
*/
|
||||
listChatSets() {
|
||||
return this.settings.chatConfig?.setList?.flatMap(it=>it.set.name) ?? [];
|
||||
return this.settings.chatConfig?.setList?.flatMap(it => it.set.name) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,7 +484,7 @@ export class QuickReplyApi {
|
||||
if (!set) {
|
||||
throw new Error(`No quick reply set with name "${name}" found.`);
|
||||
}
|
||||
return set.qrList.map(it=>it.label);
|
||||
return set.qrList.map(it => it.label);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,8 +14,6 @@ import { selected_group } from '../../group-chats.js';
|
||||
export { debounceAsync };
|
||||
|
||||
|
||||
|
||||
|
||||
const _VERBOSE = true;
|
||||
export const debug = (...msg) => _VERBOSE ? console.debug('[QR2]', ...msg) : null;
|
||||
export const log = (...msg) => _VERBOSE ? console.log('[QR2]', ...msg) : null;
|
||||
@@ -54,8 +52,6 @@ let autoExec;
|
||||
export let quickReplyApi;
|
||||
|
||||
|
||||
|
||||
|
||||
const loadSets = async () => {
|
||||
const response = await fetch('/api/settings/get', {
|
||||
method: 'POST',
|
||||
@@ -72,7 +68,7 @@ const loadSets = async () => {
|
||||
set.disableSend = set.quickActionEnabled ?? false;
|
||||
set.placeBeforeInput = set.placeBeforeInputEnabled ?? false;
|
||||
set.injectInput = set.AutoInputInject ?? false;
|
||||
set.qrList = set.quickReplySlots.map((slot,idx)=>{
|
||||
set.qrList = set.quickReplySlots.map((slot, idx) => {
|
||||
const qr = {};
|
||||
qr.id = idx + 1;
|
||||
qr.label = slot.label ?? '';
|
||||
@@ -87,7 +83,7 @@ const loadSets = async () => {
|
||||
qr.executeOnNewChat = slot.autoExecute_newChat ?? false;
|
||||
qr.executeBeforeGeneration = slot.autoExecute_beforeGeneration ?? false;
|
||||
qr.automationId = slot.automationId ?? '';
|
||||
qr.contextList = (slot.contextMenu ?? []).map(it=>({
|
||||
qr.contextList = (slot.contextMenu ?? []).map(it => ({
|
||||
set: it.preset,
|
||||
isChained: it.chain,
|
||||
}));
|
||||
@@ -99,8 +95,8 @@ const loadSets = async () => {
|
||||
}
|
||||
}
|
||||
// need to load QR lists after all sets are loaded to be able to resolve context menu entries
|
||||
setList.forEach((set, idx)=>{
|
||||
QuickReplySet.list[idx].qrList = set.qrList.map(it=>QuickReply.from(it));
|
||||
setList.forEach((set, idx) => {
|
||||
QuickReplySet.list[idx].qrList = set.qrList.map(it => QuickReply.from(it));
|
||||
QuickReplySet.list[idx].init();
|
||||
});
|
||||
log('sets: ', QuickReplySet.list);
|
||||
@@ -140,7 +136,7 @@ const executeIfReadyElseQueue = async (functionToCall, args) => {
|
||||
await functionToCall(...args);
|
||||
} else {
|
||||
log('queueing', { functionToCall, args });
|
||||
executeQueue.push(async()=>await functionToCall(...args));
|
||||
executeQueue.push(async () => await functionToCall(...args));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -183,9 +179,9 @@ const init = async () => {
|
||||
|
||||
buttons = new ButtonUi(settings);
|
||||
buttons.show();
|
||||
settings.onSave = ()=>buttons.refresh();
|
||||
settings.onSave = () => buttons.refresh();
|
||||
|
||||
globalThis.executeQuickReplyByName = async(name, args = {}, options = {}) => {
|
||||
globalThis.executeQuickReplyByName = async (name, args = {}, options = {}) => {
|
||||
let qr = [
|
||||
...settings.config.setList,
|
||||
...(settings.chatConfig?.setList ?? []),
|
||||
@@ -193,14 +189,14 @@ const init = async () => {
|
||||
]
|
||||
.map(it => it.set.qrList)
|
||||
.flat()
|
||||
.find(it=>it.label == name)
|
||||
.find(it => it.label == name)
|
||||
;
|
||||
if (!qr) {
|
||||
let [setName, ...qrName] = name.split('.');
|
||||
qrName = qrName.join('.');
|
||||
let qrs = QuickReplySet.get(setName);
|
||||
if (qrs) {
|
||||
qr = qrs.qrList.find(it=>it.label == qrName);
|
||||
qr = qrs.qrList.find(it => it.label == qrName);
|
||||
}
|
||||
}
|
||||
if (qr && qr.onExecute) {
|
||||
@@ -215,7 +211,7 @@ const init = async () => {
|
||||
slash.init();
|
||||
autoExec = new AutoExecuteHandler(settings);
|
||||
|
||||
eventSource.on(event_types.APP_READY, async()=>await finalizeInit());
|
||||
eventSource.on(event_types.APP_READY, async () => await finalizeInit());
|
||||
|
||||
globalThis.quickReplyApi = quickReplyApi;
|
||||
};
|
||||
@@ -275,14 +271,14 @@ const onChatChanged = async (chatIdx) => {
|
||||
|
||||
await autoExec.handleChatChanged();
|
||||
};
|
||||
eventSource.on(event_types.CHAT_CHANGED, (...args)=>executeIfReadyElseQueue(onChatChanged, args));
|
||||
eventSource.on(event_types.CHAT_CHANGED, (...args) => executeIfReadyElseQueue(onChatChanged, args));
|
||||
eventSource.on(event_types.CHARACTER_DELETED, purgeCharacterQuickReplySets);
|
||||
eventSource.on(event_types.CHARACTER_RENAMED, updateCharacterQuickReplySets);
|
||||
|
||||
const onUserMessage = async () => {
|
||||
await autoExec.handleUser();
|
||||
};
|
||||
eventSource.makeFirst(event_types.USER_MESSAGE_RENDERED, (...args)=>executeIfReadyElseQueue(onUserMessage, args));
|
||||
eventSource.makeFirst(event_types.USER_MESSAGE_RENDERED, (...args) => executeIfReadyElseQueue(onUserMessage, args));
|
||||
|
||||
const onAiMessage = async (messageId) => {
|
||||
if (['...'].includes(chat[messageId]?.mes)) {
|
||||
@@ -292,7 +288,7 @@ const onAiMessage = async (messageId) => {
|
||||
|
||||
await autoExec.handleAi();
|
||||
};
|
||||
eventSource.makeFirst(event_types.CHARACTER_MESSAGE_RENDERED, (...args)=>executeIfReadyElseQueue(onAiMessage, args));
|
||||
eventSource.makeFirst(event_types.CHARACTER_MESSAGE_RENDERED, (...args) => executeIfReadyElseQueue(onAiMessage, args));
|
||||
|
||||
const onGroupMemberDraft = async () => {
|
||||
await autoExec.handleGroupMemberDraft();
|
||||
|
||||
@@ -8,8 +8,6 @@ export class AutoExecuteHandler {
|
||||
/** @type {Boolean[]}*/ preventAutoExecuteStack = [];
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(/** @type {QuickReplySettings} */settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
@@ -20,13 +18,11 @@ export class AutoExecuteHandler {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
async performAutoExecute(/** @type {QuickReply[]} */qrList) {
|
||||
for (const qr of qrList) {
|
||||
this.preventAutoExecuteStack.push(qr.preventAutoExecute);
|
||||
try {
|
||||
await qr.execute({ isAutoExecute:true });
|
||||
await qr.execute({ isAutoExecute: true });
|
||||
} catch (ex) {
|
||||
warn(ex);
|
||||
} finally {
|
||||
|
||||
@@ -22,13 +22,11 @@ export class QuickReply {
|
||||
* @param {{ id?: number; contextList?: any; }} props
|
||||
*/
|
||||
static from(props) {
|
||||
props.contextList = (props.contextList ?? []).map((/** @type {any} */ it)=>QuickReplyContextLink.from(it));
|
||||
props.contextList = (props.contextList ?? []).map((/** @type {any} */ it) => QuickReplyContextLink.from(it));
|
||||
return Object.assign(new this(), props);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**@type {number}*/ id;
|
||||
/**@type {string}*/ icon;
|
||||
/**@type {string}*/ label = '';
|
||||
@@ -89,8 +87,6 @@ export class QuickReply {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
unrender() {
|
||||
this.dom?.remove();
|
||||
this.dom = null;
|
||||
@@ -129,7 +125,7 @@ export class QuickReply {
|
||||
menu.show(evt);
|
||||
}
|
||||
});
|
||||
root.addEventListener('click', (evt)=>{
|
||||
root.addEventListener('click', (evt) => {
|
||||
if (evt.ctrlKey) {
|
||||
this.showEditor();
|
||||
return;
|
||||
@@ -169,8 +165,6 @@ export class QuickReply {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
renderSettings(idx) {
|
||||
if (!this.settingsDom) {
|
||||
const item = document.createElement('div'); {
|
||||
@@ -190,7 +184,7 @@ export class QuickReply {
|
||||
addNew.classList.add('fa-solid');
|
||||
addNew.classList.add('fa-plus');
|
||||
addNew.title = 'Add quick reply';
|
||||
addNew.addEventListener('click', ()=>this.onInsertBefore());
|
||||
addNew.addEventListener('click', () => this.onInsertBefore());
|
||||
actions.append(addNew);
|
||||
}
|
||||
const paste = document.createElement('div'); {
|
||||
@@ -201,7 +195,7 @@ export class QuickReply {
|
||||
paste.classList.add('fa-solid');
|
||||
paste.classList.add('fa-paste');
|
||||
paste.title = 'Add quick reply from clipboard';
|
||||
paste.addEventListener('click', async()=>{
|
||||
paste.addEventListener('click', async () => {
|
||||
const text = await navigator.clipboard.readText();
|
||||
this.onInsertBefore(text);
|
||||
});
|
||||
@@ -215,11 +209,11 @@ export class QuickReply {
|
||||
importFile.classList.add('fa-solid');
|
||||
importFile.classList.add('fa-file-import');
|
||||
importFile.title = 'Add quick reply from JSON file';
|
||||
importFile.addEventListener('click', async()=>{
|
||||
importFile.addEventListener('click', async () => {
|
||||
const inp = document.createElement('input'); {
|
||||
inp.type = 'file';
|
||||
inp.accept = '.json';
|
||||
inp.addEventListener('change', async()=>{
|
||||
inp.addEventListener('change', async () => {
|
||||
if (inp.files.length > 0) {
|
||||
for (const file of inp.files) {
|
||||
const text = await file.text();
|
||||
@@ -256,7 +250,7 @@ export class QuickReply {
|
||||
icon.classList.add('fa-solid');
|
||||
icon.classList.add(this.icon);
|
||||
}
|
||||
icon.addEventListener('click', async()=>{
|
||||
icon.addEventListener('click', async () => {
|
||||
let value = await showFontAwesomePicker();
|
||||
this.updateIcon(value);
|
||||
});
|
||||
@@ -267,7 +261,7 @@ export class QuickReply {
|
||||
lbl.classList.add('qr--set-itemLabel');
|
||||
lbl.classList.add('text_pole');
|
||||
lbl.value = this.label;
|
||||
lbl.addEventListener('input', ()=>this.updateLabel(lbl.value));
|
||||
lbl.addEventListener('input', () => this.updateLabel(lbl.value));
|
||||
lblContainer.append(lbl);
|
||||
}
|
||||
itemContent.append(lblContainer);
|
||||
@@ -283,7 +277,7 @@ export class QuickReply {
|
||||
opt.classList.add('fa-solid');
|
||||
opt.textContent = '⁝';
|
||||
opt.title = 'Additional options:\n - large editor\n - context menu\n - auto-execution\n - tooltip';
|
||||
opt.addEventListener('click', ()=>this.showEditor());
|
||||
opt.addEventListener('click', () => this.showEditor());
|
||||
optContainer.append(opt);
|
||||
}
|
||||
itemContent.append(optContainer);
|
||||
@@ -294,7 +288,7 @@ export class QuickReply {
|
||||
mes.classList.add('qr--set-itemMessage');
|
||||
mes.value = this.message;
|
||||
//HACK need to use jQuery to catch the triggered event from the expanded editor
|
||||
$(mes).on('input', ()=>this.updateMessage(mes.value));
|
||||
$(mes).on('input', () => this.updateMessage(mes.value));
|
||||
itemContent.append(mes);
|
||||
}
|
||||
const actions = document.createElement('div'); {
|
||||
@@ -306,7 +300,7 @@ export class QuickReply {
|
||||
move.classList.add('fa-solid');
|
||||
move.classList.add('fa-truck-arrow-right');
|
||||
move.title = 'Move quick reply to other set';
|
||||
move.addEventListener('click', ()=>this.onTransfer(this));
|
||||
move.addEventListener('click', () => this.onTransfer(this));
|
||||
actions.append(move);
|
||||
}
|
||||
const copy = document.createElement('div'); {
|
||||
@@ -316,7 +310,7 @@ export class QuickReply {
|
||||
copy.classList.add('fa-solid');
|
||||
copy.classList.add('fa-copy');
|
||||
copy.title = 'Copy quick reply to clipboard';
|
||||
copy.addEventListener('click', async()=>{
|
||||
copy.addEventListener('click', async () => {
|
||||
await navigator.clipboard.writeText(JSON.stringify(this));
|
||||
copy.classList.add('qr--success');
|
||||
await delay(3010);
|
||||
@@ -331,7 +325,7 @@ export class QuickReply {
|
||||
cut.classList.add('fa-solid');
|
||||
cut.classList.add('fa-cut');
|
||||
cut.title = 'Cut quick reply to clipboard (copy and remove)';
|
||||
cut.addEventListener('click', async()=>{
|
||||
cut.addEventListener('click', async () => {
|
||||
await navigator.clipboard.writeText(JSON.stringify(this));
|
||||
this.delete();
|
||||
});
|
||||
@@ -344,8 +338,8 @@ export class QuickReply {
|
||||
exp.classList.add('fa-solid');
|
||||
exp.classList.add('fa-file-export');
|
||||
exp.title = 'Export quick reply as file';
|
||||
exp.addEventListener('click', ()=>{
|
||||
const blob = new Blob([JSON.stringify(this)], { type:'text' });
|
||||
exp.addEventListener('click', () => {
|
||||
const blob = new Blob([JSON.stringify(this)], { type: 'text' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a'); {
|
||||
a.href = url;
|
||||
@@ -363,7 +357,7 @@ export class QuickReply {
|
||||
del.classList.add('fa-trash-can');
|
||||
del.classList.add('redWarningBG');
|
||||
del.title = 'Remove Quick Reply\n---\nShift+Click to skip confirmation';
|
||||
del.addEventListener('click', async(evt)=>{
|
||||
del.addEventListener('click', async (evt) => {
|
||||
if (!evt.shiftKey) {
|
||||
const result = await Popup.show.confirm(
|
||||
'Remove Quick Reply',
|
||||
@@ -408,7 +402,7 @@ export class QuickReply {
|
||||
else {
|
||||
icon.textContent = '…';
|
||||
}
|
||||
icon.addEventListener('click', async()=>{
|
||||
icon.addEventListener('click', async () => {
|
||||
let value = await showFontAwesomePicker();
|
||||
if (value === null) return;
|
||||
if (this.icon) icon.classList.remove(this.icon);
|
||||
@@ -425,18 +419,18 @@ export class QuickReply {
|
||||
/**@type {HTMLInputElement}*/
|
||||
const showLabel = dom.querySelector('#qr--modal-showLabel');
|
||||
showLabel.checked = this.showLabel;
|
||||
showLabel.addEventListener('click', ()=>{
|
||||
showLabel.addEventListener('click', () => {
|
||||
this.updateShowLabel(showLabel.checked);
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const label = dom.querySelector('#qr--modal-label');
|
||||
label.value = this.label;
|
||||
label.addEventListener('input', ()=>{
|
||||
label.addEventListener('input', () => {
|
||||
this.updateLabel(label.value);
|
||||
});
|
||||
let switcherList;
|
||||
// @ts-ignore
|
||||
dom.querySelector('#qr--modal-switcher').addEventListener('click', (evt)=>{
|
||||
dom.querySelector('#qr--modal-switcher').addEventListener('click', (evt) => {
|
||||
if (switcherList) {
|
||||
switcherList.remove();
|
||||
switcherList = null;
|
||||
@@ -445,15 +439,15 @@ export class QuickReply {
|
||||
const list = document.createElement('ul'); {
|
||||
switcherList = list;
|
||||
list.classList.add('qr--modal-switcherList');
|
||||
const makeList = (qrs)=>{
|
||||
const makeList = (qrs) => {
|
||||
const setItem = document.createElement('li'); {
|
||||
setItem.classList.add('qr--modal-switcherItem');
|
||||
setItem.addEventListener('click', ()=>{
|
||||
setItem.addEventListener('click', () => {
|
||||
list.innerHTML = '';
|
||||
for (const qrs of quickReplyApi.listSets()) {
|
||||
const item = document.createElement('li'); {
|
||||
item.classList.add('qr--modal-switcherItem');
|
||||
item.addEventListener('click', ()=>{
|
||||
item.addEventListener('click', () => {
|
||||
list.innerHTML = '';
|
||||
makeList(quickReplyApi.getSetByName(qrs));
|
||||
});
|
||||
@@ -484,7 +478,7 @@ export class QuickReply {
|
||||
}
|
||||
const addItem = document.createElement('li'); {
|
||||
addItem.classList.add('qr--modal-switcherItem');
|
||||
addItem.addEventListener('click', ()=>{
|
||||
addItem.addEventListener('click', () => {
|
||||
const qr = quickReplyApi.getSetByQr(this).addQuickReply();
|
||||
this.editorPopup.completeAffirmative();
|
||||
qr.showEditor();
|
||||
@@ -505,11 +499,11 @@ export class QuickReply {
|
||||
}
|
||||
list.append(addItem);
|
||||
}
|
||||
for (const qr of qrs.qrList.toSorted((a,b)=>a.label.toLowerCase().localeCompare(b.label.toLowerCase()))) {
|
||||
for (const qr of qrs.qrList.toSorted((a, b) => a.label.toLowerCase().localeCompare(b.label.toLowerCase()))) {
|
||||
const item = document.createElement('li'); {
|
||||
item.classList.add('qr--modal-switcherItem');
|
||||
if (qr == this) item.classList.add('qr--current');
|
||||
else item.addEventListener('click', ()=>{
|
||||
else item.addEventListener('click', () => {
|
||||
this.editorPopup.completeAffirmative();
|
||||
qr.showEditor();
|
||||
});
|
||||
@@ -588,7 +582,7 @@ export class QuickReply {
|
||||
});
|
||||
};
|
||||
const updateScrollDebounced = updateScroll;
|
||||
const updateSyntaxEnabled = ()=>{
|
||||
const updateSyntaxEnabled = () => {
|
||||
if (syntax.checked) {
|
||||
dom.querySelector('#qr--modal-messageHolder').classList.remove('qr--noSyntax');
|
||||
} else {
|
||||
@@ -623,7 +617,7 @@ export class QuickReply {
|
||||
// @ts-ignore
|
||||
if (navigator.keyboard) {
|
||||
// @ts-ignore
|
||||
navigator.keyboard.getLayoutMap().then(it=>dom.querySelector('#qr--modal-commentKey').textContent = it.get('Backslash'));
|
||||
navigator.keyboard.getLayoutMap().then(it => dom.querySelector('#qr--modal-commentKey').textContent = it.get('Backslash'));
|
||||
} else {
|
||||
dom.querySelector('#qr--modal-commentKey').closest('small').remove();
|
||||
}
|
||||
@@ -632,12 +626,12 @@ export class QuickReply {
|
||||
const message = dom.querySelector('#qr--modal-message');
|
||||
this.editorMessage = message;
|
||||
message.value = this.message;
|
||||
const updateMessageDebounced = debounce((value)=>this.updateMessage(value), 10);
|
||||
const updateMessageDebounced = debounce((value) => this.updateMessage(value), 10);
|
||||
message.addEventListener('input', () => {
|
||||
updateMessageDebounced(message.value);
|
||||
updateScrollDebounced();
|
||||
}, { passive:true });
|
||||
const getLineStart = ()=>{
|
||||
}, { passive: true });
|
||||
const getLineStart = () => {
|
||||
const start = message.selectionStart;
|
||||
let lineStart;
|
||||
if (start == 0 || message.value[start - 1] == '\n') {
|
||||
@@ -651,7 +645,7 @@ export class QuickReply {
|
||||
}
|
||||
return lineStart;
|
||||
};
|
||||
message.addEventListener('keydown', async(evt) => {
|
||||
message.addEventListener('keydown', async (evt) => {
|
||||
if (this.isExecuting) return;
|
||||
if (evt.key == 'Tab' && !evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
|
||||
// increase indent
|
||||
@@ -668,13 +662,13 @@ export class QuickReply {
|
||||
document.execCommand('insertText', false, `\t${affectedLines.join('\n\t')}`);
|
||||
message.selectionStart = start + 1;
|
||||
message.selectionEnd = end + affectedLines.length;
|
||||
message.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
message.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
} else if (!(ac.isReplaceable && ac.isActive)) {
|
||||
evt.stopImmediatePropagation();
|
||||
evt.stopPropagation();
|
||||
// document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
|
||||
document.execCommand('insertText', false, '\t');
|
||||
message.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
message.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
}
|
||||
} else if (evt.key == 'Tab' && evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
|
||||
// decrease indent
|
||||
@@ -686,7 +680,7 @@ export class QuickReply {
|
||||
const lineStart = getLineStart();
|
||||
message.selectionStart = lineStart;
|
||||
const affectedLines = message.value.substring(lineStart, end).split('\n');
|
||||
const newText = affectedLines.map(it=>it.replace(/^\t/, '')).join('\n');
|
||||
const newText = affectedLines.map(it => it.replace(/^\t/, '')).join('\n');
|
||||
const delta = affectedLines.join('\n').length - newText.length;
|
||||
// document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
|
||||
if (delta > 0) {
|
||||
@@ -697,7 +691,7 @@ export class QuickReply {
|
||||
}
|
||||
message.selectionStart = start - (affectedLines[0].startsWith('\t') ? 1 : 0);
|
||||
message.selectionEnd = end - delta;
|
||||
message.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
message.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
} else {
|
||||
message.selectionStart = start;
|
||||
}
|
||||
@@ -714,7 +708,7 @@ export class QuickReply {
|
||||
document.execCommand('insertText', false, `\n${indent}`);
|
||||
message.selectionStart = start + 1 + indent.length;
|
||||
message.selectionEnd = message.selectionStart;
|
||||
message.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
message.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
}
|
||||
} else if (evt.key == 'Enter' && evt.ctrlKey && !evt.shiftKey && !evt.altKey) {
|
||||
if (executeShortcut.checked) {
|
||||
@@ -751,7 +745,7 @@ export class QuickReply {
|
||||
parser.parse(message.value, false);
|
||||
const start = message.selectionStart;
|
||||
const end = message.selectionEnd;
|
||||
const comment = parser.commandIndex.findLast(it=>it.name == '*' && (it.start <= start && it.end >= start || it.start <= end && it.end >= end));
|
||||
const comment = parser.commandIndex.findLast(it => it.name == '*' && (it.start <= start && it.end >= start || it.start <= end && it.end >= end));
|
||||
if (comment) {
|
||||
// uncomment
|
||||
let content = message.value.slice(comment.start + 1, comment.end - 1);
|
||||
@@ -778,15 +772,15 @@ export class QuickReply {
|
||||
message.selectionStart = start + 3;
|
||||
message.selectionEnd = end + 3;
|
||||
}
|
||||
message.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
message.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
}
|
||||
});
|
||||
const ac = await setSlashCommandAutoComplete(message, true);
|
||||
message.addEventListener('wheel', (evt)=>{
|
||||
message.addEventListener('wheel', (evt) => {
|
||||
updateScrollDebounced(evt);
|
||||
});
|
||||
// @ts-ignore
|
||||
message.addEventListener('scroll', (evt)=>{
|
||||
message.addEventListener('scroll', (evt) => {
|
||||
updateScrollDebounced();
|
||||
});
|
||||
let preBreakPointStart;
|
||||
@@ -794,7 +788,7 @@ export class QuickReply {
|
||||
/**
|
||||
* @param {SlashCommandBreakPoint} bp
|
||||
*/
|
||||
const removeBreakpoint = (bp)=>{
|
||||
const removeBreakpoint = (bp) => {
|
||||
// start at -1 because "/" is not included in start-end
|
||||
let start = bp.start - 1;
|
||||
// step left until forward slash "/"
|
||||
@@ -812,7 +806,7 @@ export class QuickReply {
|
||||
message.selectionEnd = end;
|
||||
// document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
|
||||
document.execCommand('insertText', false, '');
|
||||
message.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
message.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
let postStart = preBreakPointStart;
|
||||
let postEnd = preBreakPointEnd;
|
||||
// set caret back to where it was
|
||||
@@ -834,12 +828,12 @@ export class QuickReply {
|
||||
// selection end was behind breakpoint: move back by length of removed string
|
||||
postEnd = preBreakPointEnd - (end - start);
|
||||
}
|
||||
return { start:postStart, end:postEnd };
|
||||
return { start: postStart, end: postEnd };
|
||||
};
|
||||
/**
|
||||
* @param {SlashCommandExecutor} cmd
|
||||
*/
|
||||
const addBreakpoint = (cmd)=>{
|
||||
const addBreakpoint = (cmd) => {
|
||||
// start at -1 because "/" is not included in start-end
|
||||
let start = cmd.start - 1;
|
||||
let indent = '';
|
||||
@@ -860,16 +854,16 @@ export class QuickReply {
|
||||
message.selectionEnd = start;
|
||||
// document.execCommand is deprecated (and potentially buggy in some browsers) but the only way to retain undo-history
|
||||
document.execCommand('insertText', false, breakpointText);
|
||||
message.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
message.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
return breakpointText.length;
|
||||
};
|
||||
const toggleBreakpoint = ()=>{
|
||||
const toggleBreakpoint = () => {
|
||||
const idx = message.selectionStart;
|
||||
let postStart = preBreakPointStart;
|
||||
let postEnd = preBreakPointEnd;
|
||||
const parser = new SlashCommandParser();
|
||||
parser.parse(message.value, false);
|
||||
const cmdIdx = parser.commandIndex.findLastIndex(it=>it.start <= idx);
|
||||
const cmdIdx = parser.commandIndex.findLastIndex(it => it.start <= idx);
|
||||
if (cmdIdx > -1) {
|
||||
const cmd = parser.commandIndex[cmdIdx];
|
||||
if (cmd instanceof SlashCommandBreakPoint) {
|
||||
@@ -891,12 +885,12 @@ export class QuickReply {
|
||||
message.selectionEnd = postEnd;
|
||||
}
|
||||
};
|
||||
message.addEventListener('pointerdown', (evt)=>{
|
||||
message.addEventListener('pointerdown', (evt) => {
|
||||
if (!evt.ctrlKey || !evt.altKey) return;
|
||||
preBreakPointStart = message.selectionStart;
|
||||
preBreakPointEnd = message.selectionEnd;
|
||||
});
|
||||
message.addEventListener('pointerup', async(evt)=>{
|
||||
message.addEventListener('pointerup', async (evt) => {
|
||||
if (!evt.ctrlKey || !evt.altKey || message.selectionStart != message.selectionEnd) return;
|
||||
toggleBreakpoint();
|
||||
});
|
||||
@@ -910,11 +904,11 @@ export class QuickReply {
|
||||
});
|
||||
window.addEventListener('resize', resizeListener);
|
||||
updateSyntaxEnabled();
|
||||
const updateSyntax = ()=>{
|
||||
const updateSyntax = () => {
|
||||
if (messageSyntaxInner && syntax.checked) {
|
||||
morphdom(
|
||||
messageSyntaxInner,
|
||||
`<div>${hljs.highlight(`${message.value}${message.value.slice(-1) == '\n' ? ' ' : ''}`, { language:'stscript', ignoreIllegals:true })?.value}</div>`,
|
||||
`<div>${hljs.highlight(`${message.value}${message.value.slice(-1) == '\n' ? ' ' : ''}`, { language: 'stscript', ignoreIllegals: true })?.value}</div>`,
|
||||
{ childrenOnly: true },
|
||||
);
|
||||
updateScrollDebounced();
|
||||
@@ -924,7 +918,7 @@ export class QuickReply {
|
||||
const fpsTime = 1000 / 30;
|
||||
let lastMessageValue = null;
|
||||
let wasSyntax = null;
|
||||
const updateSyntaxLoop = ()=>{
|
||||
const updateSyntaxLoop = () => {
|
||||
const now = Date.now();
|
||||
// fps limit
|
||||
if (now - lastSyntaxUpdate < fpsTime) return requestAnimationFrame(updateSyntaxLoop);
|
||||
@@ -945,7 +939,7 @@ export class QuickReply {
|
||||
updateSyntax();
|
||||
requestAnimationFrame(updateSyntaxLoop);
|
||||
};
|
||||
requestAnimationFrame(()=>updateSyntaxLoop());
|
||||
requestAnimationFrame(() => updateSyntaxLoop());
|
||||
message.style.setProperty('text-shadow', 'none', 'important');
|
||||
updateWrap();
|
||||
updateTabSize();
|
||||
@@ -955,7 +949,7 @@ export class QuickReply {
|
||||
const tpl = dom.querySelector('#qr--ctxItem');
|
||||
const linkList = dom.querySelector('#qr--ctxEditor');
|
||||
const fillQrSetSelect = (/**@type {HTMLSelectElement}*/select, /**@type {QuickReplyContextLink}*/ link) => {
|
||||
[{ name: 'Select a QR set' }, ...QuickReplySet.list.toSorted((a,b)=>a.name.toLowerCase().localeCompare(b.name.toLowerCase()))].forEach(qrs => {
|
||||
[{ name: 'Select a QR set' }, ...QuickReplySet.list.toSorted((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()))].forEach(qrs => {
|
||||
const opt = document.createElement('option'); {
|
||||
opt.value = qrs.name;
|
||||
opt.textContent = qrs.name;
|
||||
@@ -1002,7 +996,7 @@ export class QuickReply {
|
||||
addCtxItem(link, this.contextList.length - 1);
|
||||
});
|
||||
const onContextSort = () => {
|
||||
this.contextList = Array.from(linkList.querySelectorAll('.qr--ctxItem')).map((it,idx) => {
|
||||
this.contextList = Array.from(linkList.querySelectorAll('.qr--ctxItem')).map((it, idx) => {
|
||||
const link = this.contextList[Number(it.getAttribute('data-order'))];
|
||||
it.setAttribute('data-order', String(idx));
|
||||
return link;
|
||||
@@ -1019,63 +1013,63 @@ export class QuickReply {
|
||||
/**@type {HTMLInputElement}*/
|
||||
const preventAutoExecute = dom.querySelector('#qr--preventAutoExecute');
|
||||
preventAutoExecute.checked = this.preventAutoExecute;
|
||||
preventAutoExecute.addEventListener('click', ()=>{
|
||||
preventAutoExecute.addEventListener('click', () => {
|
||||
this.preventAutoExecute = preventAutoExecute.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const isHidden = dom.querySelector('#qr--isHidden');
|
||||
isHidden.checked = this.isHidden;
|
||||
isHidden.addEventListener('click', ()=>{
|
||||
isHidden.addEventListener('click', () => {
|
||||
this.isHidden = isHidden.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const executeOnStartup = dom.querySelector('#qr--executeOnStartup');
|
||||
executeOnStartup.checked = this.executeOnStartup;
|
||||
executeOnStartup.addEventListener('click', ()=>{
|
||||
executeOnStartup.addEventListener('click', () => {
|
||||
this.executeOnStartup = executeOnStartup.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const executeOnUser = dom.querySelector('#qr--executeOnUser');
|
||||
executeOnUser.checked = this.executeOnUser;
|
||||
executeOnUser.addEventListener('click', ()=>{
|
||||
executeOnUser.addEventListener('click', () => {
|
||||
this.executeOnUser = executeOnUser.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const executeOnAi = dom.querySelector('#qr--executeOnAi');
|
||||
executeOnAi.checked = this.executeOnAi;
|
||||
executeOnAi.addEventListener('click', ()=>{
|
||||
executeOnAi.addEventListener('click', () => {
|
||||
this.executeOnAi = executeOnAi.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const executeOnChatChange = dom.querySelector('#qr--executeOnChatChange');
|
||||
executeOnChatChange.checked = this.executeOnChatChange;
|
||||
executeOnChatChange.addEventListener('click', ()=>{
|
||||
executeOnChatChange.addEventListener('click', () => {
|
||||
this.executeOnChatChange = executeOnChatChange.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const executeOnGroupMemberDraft = dom.querySelector('#qr--executeOnGroupMemberDraft');
|
||||
executeOnGroupMemberDraft.checked = this.executeOnGroupMemberDraft;
|
||||
executeOnGroupMemberDraft.addEventListener('click', ()=>{
|
||||
executeOnGroupMemberDraft.addEventListener('click', () => {
|
||||
this.executeOnGroupMemberDraft = executeOnGroupMemberDraft.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const executeBeforeGeneration = dom.querySelector('#qr--executeBeforeGeneration');
|
||||
executeBeforeGeneration.checked = this.executeBeforeGeneration;
|
||||
executeBeforeGeneration.addEventListener('click', ()=>{
|
||||
executeBeforeGeneration.addEventListener('click', () => {
|
||||
this.executeBeforeGeneration = executeBeforeGeneration.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const executeOnNewChat = dom.querySelector('#qr--executeOnNewChat');
|
||||
executeOnNewChat.checked = this.executeOnNewChat;
|
||||
executeOnNewChat.addEventListener('click', ()=>{
|
||||
executeOnNewChat.addEventListener('click', () => {
|
||||
this.executeOnNewChat = executeOnNewChat.checked;
|
||||
this.updateContext();
|
||||
});
|
||||
@@ -1102,13 +1096,13 @@ export class QuickReply {
|
||||
/**@type {HTMLElement}*/
|
||||
const executeBtn = dom.querySelector('#qr--modal-execute');
|
||||
this.editorExecuteBtn = executeBtn;
|
||||
executeBtn.addEventListener('click', async()=>{
|
||||
executeBtn.addEventListener('click', async () => {
|
||||
await this.executeFromEditor();
|
||||
});
|
||||
/**@type {HTMLElement}*/
|
||||
const executeBtnPause = dom.querySelector('#qr--modal-pause');
|
||||
this.editorExecuteBtnPause = executeBtnPause;
|
||||
executeBtnPause.addEventListener('click', async()=>{
|
||||
executeBtnPause.addEventListener('click', async () => {
|
||||
if (this.abortController) {
|
||||
if (this.abortController.signal.paused) {
|
||||
this.abortController.continue('Continue button clicked');
|
||||
@@ -1122,7 +1116,7 @@ export class QuickReply {
|
||||
/**@type {HTMLElement}*/
|
||||
const executeBtnStop = dom.querySelector('#qr--modal-stop');
|
||||
this.editorExecuteBtnStop = executeBtnStop;
|
||||
executeBtnStop.addEventListener('click', async()=>{
|
||||
executeBtnStop.addEventListener('click', async () => {
|
||||
this.abortController?.abort('Stop button clicked');
|
||||
});
|
||||
|
||||
@@ -1131,49 +1125,49 @@ export class QuickReply {
|
||||
const inputMirror = dom.querySelector('#qr--modal-send_textarea');
|
||||
// @ts-ignore
|
||||
inputMirror.value = inputOg.value;
|
||||
const inputOgMo = new MutationObserver(muts=>{
|
||||
if (muts.find(it=>[...it.removedNodes].includes(inputMirror) || [...it.removedNodes].find(n=>n.contains(inputMirror)))) {
|
||||
const inputOgMo = new MutationObserver(muts => {
|
||||
if (muts.find(it => [...it.removedNodes].includes(inputMirror) || [...it.removedNodes].find(n => n.contains(inputMirror)))) {
|
||||
inputOg.removeEventListener('input', inputOgListener);
|
||||
}
|
||||
});
|
||||
inputOgMo.observe(document.body, { childList:true });
|
||||
const inputOgListener = ()=>{
|
||||
inputOgMo.observe(document.body, { childList: true });
|
||||
const inputOgListener = () => {
|
||||
// @ts-ignore
|
||||
inputMirror.value = inputOg.value;
|
||||
};
|
||||
inputOg.addEventListener('input', inputOgListener);
|
||||
inputMirror.addEventListener('input', ()=>{
|
||||
inputMirror.addEventListener('input', () => {
|
||||
// @ts-ignore
|
||||
inputOg.value = inputMirror.value;
|
||||
});
|
||||
|
||||
/**@type {HTMLElement}*/
|
||||
const resumeBtn = dom.querySelector('#qr--modal-resume');
|
||||
resumeBtn.addEventListener('click', ()=>{
|
||||
resumeBtn.addEventListener('click', () => {
|
||||
this.debugController?.resume();
|
||||
});
|
||||
/**@type {HTMLElement}*/
|
||||
const stepBtn = dom.querySelector('#qr--modal-step');
|
||||
stepBtn.addEventListener('click', ()=>{
|
||||
stepBtn.addEventListener('click', () => {
|
||||
this.debugController?.step();
|
||||
});
|
||||
/**@type {HTMLElement}*/
|
||||
const stepIntoBtn = dom.querySelector('#qr--modal-stepInto');
|
||||
stepIntoBtn.addEventListener('click', ()=>{
|
||||
stepIntoBtn.addEventListener('click', () => {
|
||||
this.debugController?.stepInto();
|
||||
});
|
||||
/**@type {HTMLElement}*/
|
||||
const stepOutBtn = dom.querySelector('#qr--modal-stepOut');
|
||||
stepOutBtn.addEventListener('click', ()=>{
|
||||
stepOutBtn.addEventListener('click', () => {
|
||||
this.debugController?.stepOut();
|
||||
});
|
||||
/**@type {HTMLElement}*/
|
||||
const minimizeBtn = dom.querySelector('#qr--modal-minimize');
|
||||
minimizeBtn.addEventListener('click', ()=>{
|
||||
minimizeBtn.addEventListener('click', () => {
|
||||
this.editorDom.classList.add('qr--minimized');
|
||||
});
|
||||
const maximizeBtn = dom.querySelector('#qr--modal-maximize');
|
||||
maximizeBtn.addEventListener('click', ()=>{
|
||||
maximizeBtn.addEventListener('click', () => {
|
||||
this.editorDom.classList.remove('qr--minimized');
|
||||
});
|
||||
/**@type {boolean}*/
|
||||
@@ -1182,23 +1176,23 @@ export class QuickReply {
|
||||
let wStart;
|
||||
/**@type {HTMLElement}*/
|
||||
const resizeHandle = dom.querySelector('#qr--resizeHandle');
|
||||
resizeHandle.addEventListener('pointerdown', (evt)=>{
|
||||
resizeHandle.addEventListener('pointerdown', (evt) => {
|
||||
if (isResizing) return;
|
||||
isResizing = true;
|
||||
evt.preventDefault();
|
||||
resizeStart = evt.x;
|
||||
// @ts-ignore
|
||||
wStart = dom.querySelector('#qr--qrOptions').offsetWidth;
|
||||
const dragListener = debounce((evt)=>{
|
||||
const dragListener = debounce((evt) => {
|
||||
const w = wStart + resizeStart - evt.x;
|
||||
// @ts-ignore
|
||||
dom.querySelector('#qr--qrOptions').style.setProperty('--width', `${w}px`);
|
||||
}, 5);
|
||||
window.addEventListener('pointerup', ()=>{
|
||||
window.addEventListener('pointerup', () => {
|
||||
// @ts-ignore
|
||||
window.removeEventListener('pointermove', dragListener);
|
||||
isResizing = false;
|
||||
}, { once:true });
|
||||
}, { once: true });
|
||||
// @ts-ignore
|
||||
window.addEventListener('pointermove', dragListener);
|
||||
});
|
||||
@@ -1221,13 +1215,13 @@ export class QuickReply {
|
||||
}
|
||||
this.clone.style.position = 'fixed';
|
||||
this.clone.style.visibility = 'hidden';
|
||||
const mo = new MutationObserver(muts=>{
|
||||
if (muts.find(it=>[...it.removedNodes].includes(this.editorMessage) || [...it.removedNodes].find(n=>n.contains(this.editorMessage)))) {
|
||||
const mo = new MutationObserver(muts => {
|
||||
if (muts.find(it => [...it.removedNodes].includes(this.editorMessage) || [...it.removedNodes].find(n => n.contains(this.editorMessage)))) {
|
||||
this.clone?.remove();
|
||||
this.clone = null;
|
||||
}
|
||||
});
|
||||
mo.observe(document.body, { childList:true });
|
||||
mo.observe(document.body, { childList: true });
|
||||
}
|
||||
document.body.append(this.clone);
|
||||
this.clone.style.width = `${inputRect.width}px`;
|
||||
@@ -1258,7 +1252,7 @@ export class QuickReply {
|
||||
}
|
||||
async executeFromEditor() {
|
||||
if (this.isExecuting) return;
|
||||
this.editorPopup.onClosing = ()=>false;
|
||||
this.editorPopup.onClosing = () => false;
|
||||
const uuidCheck = /^[0-9a-z]{8}(-[0-9a-z]{4}){3}-[0-9a-z]{12}$/;
|
||||
const oText = this.message;
|
||||
this.isExecuting = true;
|
||||
@@ -1298,19 +1292,19 @@ export class QuickReply {
|
||||
});
|
||||
};
|
||||
const updateScrollDebounced = updateScroll;
|
||||
syntax.addEventListener('wheel', (evt)=>{
|
||||
syntax.addEventListener('wheel', (evt) => {
|
||||
updateScrollDebounced(evt);
|
||||
});
|
||||
// @ts-ignore
|
||||
syntax.addEventListener('scroll', (evt)=>{
|
||||
syntax.addEventListener('scroll', (evt) => {
|
||||
updateScrollDebounced();
|
||||
});
|
||||
try {
|
||||
this.abortController = new SlashCommandAbortController();
|
||||
this.debugController = new SlashCommandDebugController();
|
||||
this.debugController.onBreakPoint = async(closure, executor)=>{
|
||||
this.debugController.onBreakPoint = async (closure, executor) => {
|
||||
this.editorDom.classList.add('qr--isPaused');
|
||||
syntax.innerHTML = hljs.highlight(`${closure.fullText}${closure.fullText.slice(-1) == '\n' ? ' ' : ''}`, { language:'stscript', ignoreIllegals:true })?.value;
|
||||
syntax.innerHTML = hljs.highlight(`${closure.fullText}${closure.fullText.slice(-1) == '\n' ? ' ' : ''}`, { language: 'stscript', ignoreIllegals: true })?.value;
|
||||
this.editorMessageLabel.innerHTML = '';
|
||||
if (uuidCheck.test(closure.source)) {
|
||||
const p0 = document.createElement('span'); {
|
||||
@@ -1318,7 +1312,7 @@ export class QuickReply {
|
||||
this.editorMessageLabel.append(p0);
|
||||
}
|
||||
const p1 = document.createElement('strong'); {
|
||||
p1.textContent = executor.source.slice(0,5);
|
||||
p1.textContent = executor.source.slice(0, 5);
|
||||
this.editorMessageLabel.append(p1);
|
||||
}
|
||||
const p2 = document.createElement('span'); {
|
||||
@@ -1340,7 +1334,7 @@ export class QuickReply {
|
||||
/**
|
||||
* @param {SlashCommandScope} scope
|
||||
*/
|
||||
const buildVars = (scope, isCurrent = false)=>{
|
||||
const buildVars = (scope, isCurrent = false) => {
|
||||
if (!isCurrent) {
|
||||
ci--;
|
||||
}
|
||||
@@ -1358,7 +1352,7 @@ export class QuickReply {
|
||||
}
|
||||
wrap.append(namedTitle);
|
||||
}
|
||||
const keys = new Set([...Object.keys(this.debugController.namedArguments ?? {}), ...(executor.namedArgumentList ?? []).map(it=>it.name)]);
|
||||
const keys = new Set([...Object.keys(this.debugController.namedArguments ?? {}), ...(executor.namedArgumentList ?? []).map(it => it.name)]);
|
||||
for (const key of keys) {
|
||||
if (key[0] == '_') continue;
|
||||
const item = document.createElement('div'); {
|
||||
@@ -1371,7 +1365,7 @@ export class QuickReply {
|
||||
const vUnresolved = document.createElement('div'); {
|
||||
vUnresolved.classList.add('qr--val');
|
||||
vUnresolved.classList.add('qr--singleCol');
|
||||
const val = executor.namedArgumentList.find(it=>it.name == key)?.value;
|
||||
const val = executor.namedArgumentList.find(it => it.name == key)?.value;
|
||||
if (val instanceof SlashCommandClosure) {
|
||||
vUnresolved.classList.add('qr--closure');
|
||||
vUnresolved.title = val.rawText;
|
||||
@@ -1437,7 +1431,7 @@ export class QuickReply {
|
||||
// @ts-ignore
|
||||
while (unnamed.length < executor.unnamedArgumentList?.length ?? 0) unnamed.push(undefined);
|
||||
// @ts-ignore
|
||||
unnamed = unnamed.map((it,idx)=>[executor.unnamedArgumentList?.[idx], it]);
|
||||
unnamed = unnamed.map((it, idx) => [executor.unnamedArgumentList?.[idx], it]);
|
||||
// @ts-ignore
|
||||
for (const arg of unnamed) {
|
||||
i++;
|
||||
@@ -1511,7 +1505,7 @@ export class QuickReply {
|
||||
title.textContent = isCurrent ? 'Current Scope' : 'Parent Scope';
|
||||
if (c.source == source) {
|
||||
let hi;
|
||||
title.addEventListener('pointerenter', ()=>{
|
||||
title.addEventListener('pointerenter', () => {
|
||||
const loc = this.getEditorPosition(Math.max(0, c.executorList[0].start - 1), c.executorList.slice(-1)[0].end, c.fullText);
|
||||
const layer = syntax.getBoundingClientRect();
|
||||
hi = document.createElement('div');
|
||||
@@ -1522,7 +1516,7 @@ export class QuickReply {
|
||||
hi.style.height = `${loc.bottom - loc.top}px`;
|
||||
syntax.append(hi);
|
||||
});
|
||||
title.addEventListener('pointerleave', ()=>hi?.remove());
|
||||
title.addEventListener('pointerleave', () => hi?.remove());
|
||||
}
|
||||
wrap.append(title);
|
||||
}
|
||||
@@ -1635,7 +1629,7 @@ export class QuickReply {
|
||||
}
|
||||
return wrap;
|
||||
};
|
||||
const buildStack = ()=>{
|
||||
const buildStack = () => {
|
||||
const wrap = document.createElement('div'); {
|
||||
wrap.classList.add('qr--stack');
|
||||
const title = document.createElement('div'); {
|
||||
@@ -1651,7 +1645,7 @@ export class QuickReply {
|
||||
item.classList.add('qr--item');
|
||||
if (executor.source == source) {
|
||||
let hi;
|
||||
item.addEventListener('pointerenter', ()=>{
|
||||
item.addEventListener('pointerenter', () => {
|
||||
const loc = this.getEditorPosition(Math.max(0, executor.start - 1), executor.end, c.fullText);
|
||||
const layer = syntax.getBoundingClientRect();
|
||||
hi = document.createElement('div');
|
||||
@@ -1662,7 +1656,7 @@ export class QuickReply {
|
||||
hi.style.height = `${loc.bottom - loc.top}px`;
|
||||
syntax.append(hi);
|
||||
});
|
||||
item.addEventListener('pointerleave', ()=>hi?.remove());
|
||||
item.addEventListener('pointerleave', () => hi?.remove());
|
||||
}
|
||||
const cmd = document.createElement('div'); {
|
||||
cmd.classList.add('qr--cmd');
|
||||
@@ -1678,7 +1672,7 @@ export class QuickReply {
|
||||
if (uuidCheck.test(executor.source)) {
|
||||
const p1 = document.createElement('span'); {
|
||||
p1.classList.add('qr--fixed');
|
||||
p1.textContent = executor.source.slice(0,5);
|
||||
p1.textContent = executor.source.slice(0, 5);
|
||||
src.append(p1);
|
||||
}
|
||||
const p2 = document.createElement('span'); {
|
||||
@@ -1756,7 +1750,7 @@ export class QuickReply {
|
||||
this.editorMessageLabel.innerHTML = '';
|
||||
this.editorMessageLabel.textContent = 'Message / Command: ';
|
||||
this.editorMessage.value = oText;
|
||||
this.editorMessage.dispatchEvent(new Event('input', { bubbles:true }));
|
||||
this.editorMessage.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
this.editorExecutePromise = null;
|
||||
this.editorExecuteBtn.classList.remove('qr--busy');
|
||||
this.editorDom.classList.remove('qr--isExecuting');
|
||||
@@ -1769,8 +1763,6 @@ export class QuickReply {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
delete() {
|
||||
if (this.onDelete) {
|
||||
this.unrender();
|
||||
@@ -1870,7 +1862,7 @@ export class QuickReply {
|
||||
this.updateContext();
|
||||
}
|
||||
removeContextLink(setName) {
|
||||
const idx = this.contextList.findIndex(it=>it.set.name == setName);
|
||||
const idx = this.contextList.findIndex(it => it.set.name == setName);
|
||||
if (idx > -1) {
|
||||
this.contextList.splice(idx, 1);
|
||||
this.updateContext();
|
||||
@@ -1908,8 +1900,6 @@ export class QuickReply {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id,
|
||||
|
||||
@@ -13,25 +13,21 @@ export class QuickReplyConfig {
|
||||
/**@type {HTMLElement}*/ setListDom;
|
||||
|
||||
|
||||
|
||||
|
||||
static from(props) {
|
||||
props.setList = props.setList?.map(it=>QuickReplySetLink.from(it))?.filter(it=>it.set) ?? [];
|
||||
props.setList = props.setList?.map(it => QuickReplySetLink.from(it))?.filter(it => it.set) ?? [];
|
||||
const instance = Object.assign(new this(), props);
|
||||
instance.init();
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
init() {
|
||||
this.setList.forEach(it=>this.hookQuickReplyLink(it));
|
||||
this.setList.forEach(it => this.hookQuickReplyLink(it));
|
||||
}
|
||||
|
||||
|
||||
hasSet(qrs) {
|
||||
return this.setList.find(it=>it.set == qrs) != null;
|
||||
return this.setList.find(it => it.set == qrs) != null;
|
||||
}
|
||||
addSet(qrs, isVisible = true) {
|
||||
if (!this.hasSet(qrs)) {
|
||||
@@ -45,7 +41,7 @@ export class QuickReplyConfig {
|
||||
}
|
||||
}
|
||||
removeSet(qrs) {
|
||||
const idx = this.setList.findIndex(it=>it.set == qrs);
|
||||
const idx = this.setList.findIndex(it => it.set == qrs);
|
||||
if (idx > -1) {
|
||||
this.setList.splice(idx, 1);
|
||||
this.update();
|
||||
@@ -54,13 +50,11 @@ export class QuickReplyConfig {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
renderSettingsInto(/**@type {HTMLElement}*/root) {
|
||||
/**@type {HTMLElement}*/
|
||||
this.setListDom = root.querySelector('.qr--setList');
|
||||
root.querySelector('.qr--setListAdd').addEventListener('click', ()=>{
|
||||
const newSet = QuickReplySet.list.find(qr=>!this.setList.find(qrl=>qrl.set == qr));
|
||||
root.querySelector('.qr--setListAdd').addEventListener('click', () => {
|
||||
const newSet = QuickReplySet.list.find(qr => !this.setList.find(qrl => qrl.set == qr));
|
||||
if (newSet) {
|
||||
this.addSet(newSet);
|
||||
} else {
|
||||
@@ -74,14 +68,14 @@ export class QuickReplyConfig {
|
||||
// @ts-ignore
|
||||
$(this.setListDom).sortable({
|
||||
delay: getSortableDelay(),
|
||||
stop: ()=>this.onSetListSort(),
|
||||
stop: () => this.onSetListSort(),
|
||||
});
|
||||
this.setList.filter(it=>!it.set.isDeleted).forEach((qrl,idx)=>this.setListDom.append(qrl.renderSettings(idx)));
|
||||
this.setList.filter(it => !it.set.isDeleted).forEach((qrl, idx) => this.setListDom.append(qrl.renderSettings(idx)));
|
||||
}
|
||||
|
||||
|
||||
onSetListSort() {
|
||||
this.setList = Array.from(this.setListDom.children).map((it,idx)=>{
|
||||
this.setList = Array.from(this.setListDom.children).map((it, idx) => {
|
||||
const qrl = this.setList[Number(it.getAttribute('data-order'))];
|
||||
qrl.index = idx;
|
||||
it.setAttribute('data-order', String(idx));
|
||||
@@ -91,15 +85,13 @@ export class QuickReplyConfig {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {QuickReplySetLink} qrl
|
||||
*/
|
||||
hookQuickReplyLink(qrl) {
|
||||
qrl.onDelete = ()=>this.deleteQuickReplyLink(qrl);
|
||||
qrl.onUpdate = ()=>this.update();
|
||||
qrl.onRequestEditSet = ()=>this.requestEditSet(qrl.set);
|
||||
qrl.onDelete = () => this.deleteQuickReplyLink(qrl);
|
||||
qrl.onUpdate = () => this.update();
|
||||
qrl.onRequestEditSet = () => this.requestEditSet(qrl.set);
|
||||
}
|
||||
|
||||
deleteQuickReplyLink(qrl) {
|
||||
|
||||
@@ -8,8 +8,6 @@ export class QuickReplyContextLink {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**@type {QuickReplySet}*/ set;
|
||||
/**@type {Boolean}*/ isChained = false;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export class QuickReplySet {
|
||||
* @param {string} name - name of the QuickReplySet
|
||||
*/
|
||||
static get(name) {
|
||||
return this.list.find(it=>it.name == name);
|
||||
return this.list.find(it => it.name == name);
|
||||
}
|
||||
|
||||
/**@type {string}*/ name;
|
||||
@@ -42,11 +42,11 @@ export class QuickReplySet {
|
||||
/**@type {HTMLElement}*/ settingsDom;
|
||||
|
||||
constructor() {
|
||||
this.save = debounceAsync(()=>this.performSave(), 200);
|
||||
this.save = debounceAsync(() => this.performSave(), 200);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.qrList.forEach(qr=>this.hookQuickReply(qr));
|
||||
this.qrList.forEach(qr => this.hookQuickReply(qr));
|
||||
}
|
||||
|
||||
unrender() {
|
||||
@@ -60,7 +60,7 @@ export class QuickReplySet {
|
||||
this.dom = root;
|
||||
root.classList.add('qr--buttons');
|
||||
this.updateColor();
|
||||
this.qrList.filter(qr=>!qr.isHidden).forEach(qr=>{
|
||||
this.qrList.filter(qr => !qr.isHidden).forEach(qr => {
|
||||
root.append(qr.render());
|
||||
});
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export class QuickReplySet {
|
||||
rerender() {
|
||||
if (!this.dom) return;
|
||||
this.dom.innerHTML = '';
|
||||
this.qrList.filter(qr=>!qr.isHidden).forEach(qr=>{
|
||||
this.qrList.filter(qr => !qr.isHidden).forEach(qr => {
|
||||
this.dom.append(qr.render());
|
||||
});
|
||||
}
|
||||
@@ -95,7 +95,7 @@ export class QuickReplySet {
|
||||
if (!this.settingsDom) {
|
||||
this.settingsDom = document.createElement('div'); {
|
||||
this.settingsDom.classList.add('qr--set-qrListContents');
|
||||
this.qrList.forEach((qr,idx)=>{
|
||||
this.qrList.forEach((qr, idx) => {
|
||||
this.renderSettingsItem(qr, idx);
|
||||
});
|
||||
}
|
||||
@@ -138,12 +138,12 @@ export class QuickReplySet {
|
||||
*/
|
||||
async executeWithOptions(qr, options = {}) {
|
||||
options = Object.assign({
|
||||
message:null,
|
||||
isAutoExecute:false,
|
||||
isEditor:false,
|
||||
isRun:false,
|
||||
scope:null,
|
||||
executionOptions:{},
|
||||
message: null,
|
||||
isAutoExecute: false,
|
||||
isEditor: false,
|
||||
isRun: false,
|
||||
scope: null,
|
||||
executionOptions: {},
|
||||
}, options);
|
||||
const execOptions = options.executionOptions;
|
||||
/**@type {HTMLTextAreaElement}*/
|
||||
@@ -208,9 +208,8 @@ export class QuickReplySet {
|
||||
}
|
||||
|
||||
addQuickReply(data = {}) {
|
||||
const id = Math.max(this.idIndex, this.qrList.reduce((max,qr)=>Math.max(max,qr.id),0)) + 1;
|
||||
data.id =
|
||||
this.idIndex = id + 1;
|
||||
const id = Math.max(this.idIndex, this.qrList.reduce((max, qr) => Math.max(max, qr.id), 0)) + 1;
|
||||
data.id = this.idIndex = id + 1;
|
||||
const qr = QuickReply.from(data);
|
||||
this.qrList.push(qr);
|
||||
this.hookQuickReply(qr);
|
||||
@@ -257,11 +256,11 @@ export class QuickReplySet {
|
||||
*/
|
||||
hookQuickReply(qr) {
|
||||
// @ts-ignore
|
||||
qr.onDebug = ()=>this.debug(qr);
|
||||
qr.onExecute = (_, options)=>this.executeWithOptions(qr, options);
|
||||
qr.onDelete = ()=>this.removeQuickReply(qr);
|
||||
qr.onUpdate = ()=>this.save();
|
||||
qr.onInsertBefore = (qrJson)=>{
|
||||
qr.onDebug = () => this.debug(qr);
|
||||
qr.onExecute = (_, options) => this.executeWithOptions(qr, options);
|
||||
qr.onDelete = () => this.removeQuickReply(qr);
|
||||
qr.onUpdate = () => this.save();
|
||||
qr.onInsertBefore = (qrJson) => {
|
||||
this.addQuickReplyFromText(qrJson);
|
||||
const newQr = this.qrList.pop();
|
||||
this.qrList.splice(this.qrList.indexOf(qr), 0, newQr);
|
||||
@@ -270,7 +269,7 @@ export class QuickReplySet {
|
||||
}
|
||||
this.save();
|
||||
};
|
||||
qr.onTransfer = async()=>{
|
||||
qr.onTransfer = async () => {
|
||||
/**@type {HTMLSelectElement} */
|
||||
let sel;
|
||||
let isCopy = false;
|
||||
@@ -301,14 +300,14 @@ export class QuickReplySet {
|
||||
sel.append(opt);
|
||||
}
|
||||
}
|
||||
sel.addEventListener('keyup', (evt)=>{
|
||||
sel.addEventListener('keyup', (evt) => {
|
||||
if (evt.key == 'Shift') {
|
||||
// @ts-ignore
|
||||
(dlg.dom ?? dlg.dlg).classList.remove('qr--isCopy');
|
||||
return;
|
||||
}
|
||||
});
|
||||
sel.addEventListener('keydown', (evt)=>{
|
||||
sel.addEventListener('keydown', (evt) => {
|
||||
if (evt.key == 'Shift') {
|
||||
// @ts-ignore
|
||||
(dlg.dom ?? dlg.dlg).classList.add('qr--isCopy');
|
||||
@@ -330,12 +329,12 @@ export class QuickReplySet {
|
||||
dom.append(hintP);
|
||||
}
|
||||
}
|
||||
const dlg = new Popup(dom, POPUP_TYPE.CONFIRM, null, { okButton:'Transfer', cancelButton:'Cancel' });
|
||||
const dlg = new Popup(dom, POPUP_TYPE.CONFIRM, null, { okButton: 'Transfer', cancelButton: 'Cancel' });
|
||||
const copyBtn = document.createElement('div'); {
|
||||
copyBtn.classList.add('qr--copy');
|
||||
copyBtn.classList.add('menu_button');
|
||||
copyBtn.textContent = 'Copy';
|
||||
copyBtn.addEventListener('click', ()=>{
|
||||
copyBtn.addEventListener('click', () => {
|
||||
isCopy = true;
|
||||
dlg.completeAffirmative();
|
||||
});
|
||||
@@ -346,7 +345,7 @@ export class QuickReplySet {
|
||||
sel.focus();
|
||||
await prom;
|
||||
if (dlg.result == POPUP_RESULT.AFFIRMATIVE) {
|
||||
const qrs = QuickReplySet.list.find(it=>it.name == sel.value);
|
||||
const qrs = QuickReplySet.list.find(it => it.name == sel.value);
|
||||
qrs.addQuickReply(qr.toJSON());
|
||||
if (!isCopy) {
|
||||
qr.delete();
|
||||
|
||||
@@ -9,8 +9,6 @@ export class QuickReplySetLink {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**@type {QuickReplySet}*/ set;
|
||||
/**@type {Boolean}*/ isVisible = true;
|
||||
|
||||
@@ -23,8 +21,6 @@ export class QuickReplySetLink {
|
||||
/**@type {HTMLElement}*/ settingsDom;
|
||||
|
||||
|
||||
|
||||
|
||||
renderSettings(idx) {
|
||||
this.index = idx;
|
||||
const item = document.createElement('div'); {
|
||||
@@ -40,12 +36,12 @@ export class QuickReplySetLink {
|
||||
const set = document.createElement('select'); {
|
||||
set.classList.add('qr--set');
|
||||
// fix for jQuery sortable breaking childrens' touch events
|
||||
set.addEventListener('touchstart', (evt)=>evt.stopPropagation());
|
||||
set.addEventListener('change', ()=>{
|
||||
set.addEventListener('touchstart', (evt) => evt.stopPropagation());
|
||||
set.addEventListener('change', () => {
|
||||
this.set = QuickReplySet.get(set.value);
|
||||
this.update();
|
||||
});
|
||||
QuickReplySet.list.toSorted((a,b)=>a.name.toLowerCase().localeCompare(b.name.toLowerCase())).forEach(qrs=>{
|
||||
QuickReplySet.list.toSorted((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).forEach(qrs => {
|
||||
const opt = document.createElement('option'); {
|
||||
opt.value = qrs.name;
|
||||
opt.textContent = qrs.name;
|
||||
@@ -61,7 +57,7 @@ export class QuickReplySetLink {
|
||||
const cb = document.createElement('input'); {
|
||||
cb.type = 'checkbox';
|
||||
cb.checked = this.isVisible;
|
||||
cb.addEventListener('click', ()=>{
|
||||
cb.addEventListener('click', () => {
|
||||
this.isVisible = cb.checked;
|
||||
this.update();
|
||||
});
|
||||
@@ -76,7 +72,7 @@ export class QuickReplySetLink {
|
||||
edit.classList.add('fa-solid');
|
||||
edit.classList.add('fa-pencil');
|
||||
edit.title = 'Edit quick reply set';
|
||||
edit.addEventListener('click', ()=>this.requestEditSet());
|
||||
edit.addEventListener('click', () => this.requestEditSet());
|
||||
item.append(edit);
|
||||
}
|
||||
const del = document.createElement('div'); {
|
||||
@@ -86,7 +82,7 @@ export class QuickReplySetLink {
|
||||
del.classList.add('fa-solid');
|
||||
del.classList.add('fa-trash-can');
|
||||
del.title = 'Remove quick reply set';
|
||||
del.addEventListener('click', ()=>this.delete());
|
||||
del.addEventListener('click', () => this.delete());
|
||||
item.append(del);
|
||||
}
|
||||
}
|
||||
@@ -98,8 +94,6 @@ export class QuickReplySetLink {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
update() {
|
||||
if (this.onUpdate) {
|
||||
this.onUpdate(this);
|
||||
@@ -118,8 +112,6 @@ export class QuickReplySetLink {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
set: this.set.name,
|
||||
|
||||
@@ -15,8 +15,6 @@ export class QuickReplySettings {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**@type {Boolean}*/ isEnabled = false;
|
||||
/**@type {Boolean}*/ isCombined = false;
|
||||
/**@type {Boolean}*/ isPopout = false;
|
||||
@@ -50,8 +48,6 @@ export class QuickReplySettings {
|
||||
/**@type {Function}*/ onRequestEditSet;
|
||||
|
||||
|
||||
|
||||
|
||||
init() {
|
||||
this.hookConfig(this.config);
|
||||
this.hookConfig(this.chatConfig);
|
||||
@@ -60,8 +56,8 @@ export class QuickReplySettings {
|
||||
|
||||
hookConfig(config) {
|
||||
if (config) {
|
||||
config.onUpdate = ()=>this.save();
|
||||
config.onRequestEditSet = (qrs)=>this.requestEditSet(qrs);
|
||||
config.onUpdate = () => this.save();
|
||||
config.onRequestEditSet = (qrs) => this.requestEditSet(qrs);
|
||||
}
|
||||
}
|
||||
unhookConfig(config) {
|
||||
@@ -72,8 +68,6 @@ export class QuickReplySettings {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
save() {
|
||||
extension_settings.quickReplyV2 = this.toJSON();
|
||||
saveSettingsDebounced();
|
||||
|
||||
@@ -16,15 +16,11 @@ export class SlashCommandHandler {
|
||||
/** @type {QuickReplyApi} */ api;
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(/** @type {QuickReplyApi} */api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
init() {
|
||||
function getExecutionIcons(/** @type {QuickReply} */ qr) {
|
||||
let icons = '';
|
||||
@@ -56,7 +52,7 @@ export class SlashCommandHandler {
|
||||
qrIds: (executor) => QuickReplySet.get(String(executor.namedArgumentList.find(x => x.name == 'set')?.value))?.qrList.map(qr => {
|
||||
const icons = getExecutionIcons(qr);
|
||||
const message = `${qr.automationId ? `[${qr.automationId}]` : ''}${icons ? `[auto: ${icons}]` : ''} ${qr.title || qr.message}`.trim();
|
||||
return new SlashCommandEnumValue(qr.label, message, enumTypes.enum, enumIcons.qr, null, ()=>qr.id.toString(), true);
|
||||
return new SlashCommandEnumValue(qr.label, message, enumTypes.enum, enumIcons.qr, null, () => qr.id.toString(), true);
|
||||
}) ?? [],
|
||||
|
||||
/** 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 {
|
||||
return '';
|
||||
},
|
||||
returns: 'updated quick reply',
|
||||
namedArgumentList: [...qrUpdateArgs, ...qrArgs.map(it=>{
|
||||
namedArgumentList: [...qrUpdateArgs, ...qrArgs.map(it => {
|
||||
if (it.name == 'label') {
|
||||
const clone = SlashCommandNamedArgument.fromProps(it);
|
||||
clone.isRequired = false;
|
||||
@@ -691,16 +687,16 @@ export class SlashCommandHandler {
|
||||
if (!args.from) throw new Error('/import requires from= to be set.');
|
||||
if (!value) throw new Error('/import requires the unnamed argument to be set.');
|
||||
let qr = [...this.api.listGlobalSets(), ...this.api.listChatSets()]
|
||||
.map(it=>this.api.getSetByName(it)?.qrList ?? [])
|
||||
.map(it => this.api.getSetByName(it)?.qrList ?? [])
|
||||
.flat()
|
||||
.find(it=>it.label == args.from)
|
||||
.find(it => it.label == args.from)
|
||||
;
|
||||
if (!qr) {
|
||||
let [setName, ...qrNameParts] = args.from.split('.');
|
||||
let qrName = qrNameParts.join('.');
|
||||
let qrs = QuickReplySet.get(setName);
|
||||
if (qrs) {
|
||||
qr = qrs.qrList.find(it=>it.label == qrName);
|
||||
qr = qrs.qrList.find(it => it.label == qrName);
|
||||
}
|
||||
}
|
||||
if (qr) {
|
||||
@@ -709,23 +705,23 @@ export class SlashCommandHandler {
|
||||
if (args._debugController) {
|
||||
closure.source = args.from;
|
||||
}
|
||||
const testCandidates = (executor)=>{
|
||||
const testCandidates = (executor) => {
|
||||
return (
|
||||
executor.namedArgumentList.find(arg=>arg.name == 'key')
|
||||
executor.namedArgumentList.find(arg => arg.name == 'key')
|
||||
&& executor.unnamedArgumentList.length > 0
|
||||
&& executor.unnamedArgumentList[0].value instanceof SlashCommandClosure
|
||||
) || (
|
||||
!executor.namedArgumentList.find(arg=>arg.name == 'key')
|
||||
!executor.namedArgumentList.find(arg => arg.name == 'key')
|
||||
&& executor.unnamedArgumentList.length > 1
|
||||
&& executor.unnamedArgumentList[1].value instanceof SlashCommandClosure
|
||||
);
|
||||
};
|
||||
const candidates = closure.executorList
|
||||
.filter(executor=>['let', 'var'].includes(executor.command.name))
|
||||
.filter(executor => ['let', 'var'].includes(executor.command.name))
|
||||
.filter(testCandidates)
|
||||
.map(executor=>({
|
||||
key: executor.namedArgumentList.find(arg=>arg.name == 'key')?.value ?? executor.unnamedArgumentList[0].value,
|
||||
value: executor.unnamedArgumentList[executor.namedArgumentList.find(arg=>arg.name == 'key') ? 0 : 1].value,
|
||||
.map(executor => ({
|
||||
key: executor.namedArgumentList.find(arg => arg.name == 'key')?.value ?? executor.unnamedArgumentList[0].value,
|
||||
value: executor.unnamedArgumentList[executor.namedArgumentList.find(arg => arg.name == 'key') ? 0 : 1].value,
|
||||
}))
|
||||
;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
@@ -735,7 +731,7 @@ export class SlashCommandHandler {
|
||||
dstName = value[i + 2];
|
||||
i += 2;
|
||||
}
|
||||
const pick = candidates.find(it=>it.key == srcName);
|
||||
const pick = candidates.find(it => it.key == srcName);
|
||||
if (!pick) throw new Error(`No scoped closure named "${srcName}" found in "${args.from}"`);
|
||||
if (args._scope.existsVariableInScope(dstName)) {
|
||||
args._scope.setVariable(dstName, pick.value);
|
||||
@@ -783,8 +779,6 @@ export class SlashCommandHandler {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
getSetByName(name) {
|
||||
const set = this.api.getSetByName(name);
|
||||
if (!set) {
|
||||
@@ -802,8 +796,6 @@ export class SlashCommandHandler {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
async executeQuickReplyByIndex(idx) {
|
||||
try {
|
||||
return await this.api.executeQuickReplyByIndex(idx);
|
||||
|
||||
@@ -10,15 +10,11 @@ export class ButtonUi {
|
||||
/**@type {HTMLElement}*/ popoutDom;
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(/**@type {QuickReplySettings}*/settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
if (this.settings.isPopout) {
|
||||
return this.renderPopout();
|
||||
@@ -57,8 +53,6 @@ export class ButtonUi {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
renderBar() {
|
||||
if (!this.dom) {
|
||||
let buttonHolder;
|
||||
@@ -75,7 +69,7 @@ export class ButtonUi {
|
||||
popout.classList.add('menu_button');
|
||||
popout.classList.add('fa-solid');
|
||||
popout.classList.add('fa-window-restore');
|
||||
popout.addEventListener('click', ()=>{
|
||||
popout.addEventListener('click', () => {
|
||||
this.settings.isPopout = true;
|
||||
this.refresh();
|
||||
this.settings.save();
|
||||
@@ -91,8 +85,8 @@ export class ButtonUi {
|
||||
}
|
||||
}
|
||||
[...this.settings.config.setList, ...(this.settings.chatConfig?.setList ?? []), ...(this.settings.charConfig?.setList ?? [])]
|
||||
.filter(link=>link.isVisible)
|
||||
.forEach(link=>buttonHolder.append(link.set.render()))
|
||||
.filter(link => link.isVisible)
|
||||
.forEach(link => buttonHolder.append(link.set.render()))
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -100,8 +94,6 @@ export class ButtonUi {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
renderPopout() {
|
||||
if (!this.popoutDom) {
|
||||
let buttonHolder;
|
||||
@@ -130,7 +122,7 @@ export class ButtonUi {
|
||||
close.classList.add('fa-solid');
|
||||
close.classList.add('fa-circle-xmark');
|
||||
close.classList.add('hoverglow');
|
||||
close.addEventListener('click', ()=>{
|
||||
close.addEventListener('click', () => {
|
||||
this.settings.isPopout = false;
|
||||
this.refresh();
|
||||
this.settings.save();
|
||||
@@ -151,8 +143,8 @@ export class ButtonUi {
|
||||
}
|
||||
}
|
||||
[...this.settings.config.setList, ...(this.settings.chatConfig?.setList ?? []), ...(this.settings.charConfig?.setList ?? [])]
|
||||
.filter(link=>link.isVisible)
|
||||
.forEach(link=>buttonHolder.append(link.set.render()))
|
||||
.filter(link => link.isVisible)
|
||||
.forEach(link => buttonHolder.append(link.set.render()))
|
||||
;
|
||||
root.append(body);
|
||||
}
|
||||
|
||||
@@ -29,24 +29,18 @@ export class SettingsUi {
|
||||
/**@type {HTMLSelectElement}*/ currentSet;
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(/**@type {QuickReplySettings}*/settings) {
|
||||
this.settings = settings;
|
||||
settings.onRequestEditSet = (qrs) => this.selectQrSet(qrs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
rerender() {
|
||||
if (!this.dom) return;
|
||||
const content = this.dom.querySelector('.inline-drawer-content');
|
||||
content.innerHTML = '';
|
||||
// @ts-ignore
|
||||
Array.from(this.template.querySelector('.inline-drawer-content').cloneNode(true).children).forEach(el=>{
|
||||
Array.from(this.template.querySelector('.inline-drawer-content').cloneNode(true).children).forEach(el => {
|
||||
content.append(el);
|
||||
});
|
||||
this.prepareDom();
|
||||
@@ -75,15 +69,15 @@ export class SettingsUi {
|
||||
// general settings
|
||||
this.isEnabled = this.dom.querySelector('#qr--isEnabled');
|
||||
this.isEnabled.checked = this.settings.isEnabled;
|
||||
this.isEnabled.addEventListener('click', ()=>this.onIsEnabled());
|
||||
this.isEnabled.addEventListener('click', () => this.onIsEnabled());
|
||||
|
||||
this.isCombined = this.dom.querySelector('#qr--isCombined');
|
||||
this.isCombined.checked = this.settings.isCombined;
|
||||
this.isCombined.addEventListener('click', ()=>this.onIsCombined());
|
||||
this.isCombined.addEventListener('click', () => this.onIsCombined());
|
||||
|
||||
this.showPopoutButton = this.dom.querySelector('#qr--showPopoutButton');
|
||||
this.showPopoutButton.checked = this.settings.showPopoutButton;
|
||||
this.showPopoutButton.addEventListener('click', ()=>this.onShowPopoutButton());
|
||||
this.showPopoutButton.addEventListener('click', () => this.onShowPopoutButton());
|
||||
}
|
||||
|
||||
prepareGlobalSetList() {
|
||||
@@ -131,29 +125,29 @@ export class SettingsUi {
|
||||
prepareQrEditor() {
|
||||
// qr editor
|
||||
this.dom.querySelector('#qr--set-rename').addEventListener('click', async () => this.renameQrSet());
|
||||
this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet());
|
||||
this.dom.querySelector('#qr--set-new').addEventListener('click', async () => this.addQrSet());
|
||||
/**@type {HTMLInputElement}*/
|
||||
const importFile = this.dom.querySelector('#qr--set-importFile');
|
||||
importFile.addEventListener('change', async()=>{
|
||||
importFile.addEventListener('change', async () => {
|
||||
await this.importQrSet(importFile.files);
|
||||
importFile.value = null;
|
||||
});
|
||||
this.dom.querySelector('#qr--set-import').addEventListener('click', ()=>importFile.click());
|
||||
this.dom.querySelector('#qr--set-import').addEventListener('click', () => importFile.click());
|
||||
this.dom.querySelector('#qr--set-export').addEventListener('click', async () => this.exportQrSet());
|
||||
this.dom.querySelector('#qr--set-duplicate').addEventListener('click', async () => this.duplicateQrSet());
|
||||
this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet());
|
||||
this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{
|
||||
this.dom.querySelector('#qr--set-delete').addEventListener('click', async () => this.deleteQrSet());
|
||||
this.dom.querySelector('#qr--set-add').addEventListener('click', async () => {
|
||||
this.currentQrSet.addQuickReply();
|
||||
});
|
||||
this.dom.querySelector('#qr--set-paste').addEventListener('click', async()=>{
|
||||
this.dom.querySelector('#qr--set-paste').addEventListener('click', async () => {
|
||||
const text = await navigator.clipboard.readText();
|
||||
this.currentQrSet.addQuickReplyFromText(text);
|
||||
});
|
||||
this.dom.querySelector('#qr--set-importQr').addEventListener('click', async()=>{
|
||||
this.dom.querySelector('#qr--set-importQr').addEventListener('click', async () => {
|
||||
const inp = document.createElement('input'); {
|
||||
inp.type = 'file';
|
||||
inp.accept = '.json';
|
||||
inp.addEventListener('change', async()=>{
|
||||
inp.addEventListener('change', async () => {
|
||||
if (inp.files.length > 0) {
|
||||
for (const file of inp.files) {
|
||||
const text = await file.text();
|
||||
@@ -166,8 +160,8 @@ export class SettingsUi {
|
||||
});
|
||||
this.qrList = this.dom.querySelector('#qr--set-qrList');
|
||||
this.currentSet = this.dom.querySelector('#qr--set');
|
||||
this.currentSet.addEventListener('change', ()=>this.onQrSetChange());
|
||||
QuickReplySet.list.toSorted((a,b)=>a.name.toLowerCase().localeCompare(b.name.toLowerCase())).forEach(qrs=>{
|
||||
this.currentSet.addEventListener('change', () => this.onQrSetChange());
|
||||
QuickReplySet.list.toSorted((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).forEach(qrs => {
|
||||
const opt = document.createElement('option'); {
|
||||
opt.value = qrs.name;
|
||||
opt.textContent = qrs.name;
|
||||
@@ -175,19 +169,19 @@ export class SettingsUi {
|
||||
}
|
||||
});
|
||||
this.disableSend = this.dom.querySelector('#qr--disableSend');
|
||||
this.disableSend.addEventListener('click', ()=>{
|
||||
this.disableSend.addEventListener('click', () => {
|
||||
const qrs = this.currentQrSet;
|
||||
qrs.disableSend = this.disableSend.checked;
|
||||
qrs.save();
|
||||
});
|
||||
this.placeBeforeInput = this.dom.querySelector('#qr--placeBeforeInput');
|
||||
this.placeBeforeInput.addEventListener('click', ()=>{
|
||||
this.placeBeforeInput.addEventListener('click', () => {
|
||||
const qrs = this.currentQrSet;
|
||||
qrs.placeBeforeInput = this.placeBeforeInput.checked;
|
||||
qrs.save();
|
||||
});
|
||||
this.injectInput = this.dom.querySelector('#qr--injectInput');
|
||||
this.injectInput.addEventListener('click', ()=>{
|
||||
this.injectInput.addEventListener('click', () => {
|
||||
const qrs = this.currentQrSet;
|
||||
qrs.injectInput = this.injectInput.checked;
|
||||
qrs.save();
|
||||
@@ -196,7 +190,7 @@ export class SettingsUi {
|
||||
this.color = this.dom.querySelector('#qr--color');
|
||||
// @ts-ignore
|
||||
this.color.color = this.currentQrSet?.color ?? 'transparent';
|
||||
this.color.addEventListener('change', (evt)=>{
|
||||
this.color.addEventListener('change', (evt) => {
|
||||
if (!this.dom.closest('body')) return;
|
||||
const qrs = this.currentQrSet;
|
||||
if (initialColorChange) {
|
||||
@@ -211,7 +205,7 @@ export class SettingsUi {
|
||||
this.currentQrSet.updateColor();
|
||||
});
|
||||
// @ts-ignore
|
||||
this.dom.querySelector('#qr--colorClear').addEventListener('click', (evt)=>{
|
||||
this.dom.querySelector('#qr--colorClear').addEventListener('click', (evt) => {
|
||||
const qrs = this.currentQrSet;
|
||||
// @ts-ignore
|
||||
this.color.color = 'transparent';
|
||||
@@ -219,7 +213,7 @@ export class SettingsUi {
|
||||
this.currentQrSet.updateColor();
|
||||
});
|
||||
this.onlyBorderColor = this.dom.querySelector('#qr--onlyBorderColor');
|
||||
this.onlyBorderColor.addEventListener('click', ()=>{
|
||||
this.onlyBorderColor.addEventListener('click', () => {
|
||||
const qrs = this.currentQrSet;
|
||||
qrs.onlyBorderColor = this.onlyBorderColor.checked;
|
||||
qrs.save();
|
||||
@@ -242,7 +236,7 @@ export class SettingsUi {
|
||||
$(qrsDom).sortable({
|
||||
delay: getSortableDelay(),
|
||||
handle: '.drag-handle',
|
||||
stop: ()=>this.onQrListSort(),
|
||||
stop: () => this.onQrListSort(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -256,8 +250,6 @@ export class SettingsUi {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
async onIsEnabled() {
|
||||
this.settings.isEnabled = this.isEnabled.checked;
|
||||
this.settings.save();
|
||||
@@ -274,7 +266,7 @@ export class SettingsUi {
|
||||
}
|
||||
|
||||
async onGlobalSetListSort() {
|
||||
this.settings.config.setList = Array.from(this.globalSetList.children).map((it,idx)=>{
|
||||
this.settings.config.setList = Array.from(this.globalSetList.children).map((it, idx) => {
|
||||
const set = this.settings.config.setList[Number(it.getAttribute('data-order'))];
|
||||
it.setAttribute('data-order', String(idx));
|
||||
return set;
|
||||
@@ -283,7 +275,7 @@ export class SettingsUi {
|
||||
}
|
||||
|
||||
async onChatSetListSort() {
|
||||
this.settings.chatConfig.setList = Array.from(this.chatSetList.children).map((it,idx)=>{
|
||||
this.settings.chatConfig.setList = Array.from(this.chatSetList.children).map((it, idx) => {
|
||||
const set = this.settings.chatConfig.setList[Number(it.getAttribute('data-order'))];
|
||||
it.setAttribute('data-order', String(idx));
|
||||
return set;
|
||||
@@ -292,14 +284,14 @@ export class SettingsUi {
|
||||
}
|
||||
|
||||
updateOrder(list) {
|
||||
Array.from(list.children).forEach((it,idx)=>{
|
||||
Array.from(list.children).forEach((it, idx) => {
|
||||
it.setAttribute('data-order', idx);
|
||||
});
|
||||
}
|
||||
|
||||
async onQrListSort() {
|
||||
this.currentQrSet.qrList = Array.from(this.qrList.querySelectorAll('.qr--set-item')).map((it,idx)=>{
|
||||
const qr = this.currentQrSet.qrList.find(qr=>qr.id == Number(it.getAttribute('data-id')));
|
||||
this.currentQrSet.qrList = Array.from(this.qrList.querySelectorAll('.qr--set-item')).map((it, idx) => {
|
||||
const qr = this.currentQrSet.qrList.find(qr => qr.id == Number(it.getAttribute('data-id')));
|
||||
it.setAttribute('data-order', String(idx));
|
||||
return qr;
|
||||
});
|
||||
@@ -408,7 +400,7 @@ export class SettingsUi {
|
||||
const qrs = new QuickReplySet();
|
||||
qrs.name = name;
|
||||
qrs.addQuickReply();
|
||||
const idx = QuickReplySet.list.findIndex(it=>it.name.toLowerCase().localeCompare(name.toLowerCase()) == 1);
|
||||
const idx = QuickReplySet.list.findIndex(it => it.name.toLowerCase().localeCompare(name.toLowerCase()) == 1);
|
||||
if (idx > -1) {
|
||||
QuickReplySet.list.splice(idx, 0, qrs);
|
||||
} else {
|
||||
@@ -448,7 +440,7 @@ export class SettingsUi {
|
||||
} else {
|
||||
/**@type {QuickReplySet}*/
|
||||
const qrs = QuickReplySet.from(JSON.parse(JSON.stringify(props)));
|
||||
qrs.qrList = props.qrList.map(it=>QuickReply.from(it));
|
||||
qrs.qrList = props.qrList.map(it => QuickReply.from(it));
|
||||
qrs.init();
|
||||
const oldQrs = QuickReplySet.get(props.name);
|
||||
if (oldQrs) {
|
||||
@@ -466,7 +458,7 @@ export class SettingsUi {
|
||||
this.prepareCharacterSetList();
|
||||
}
|
||||
} else {
|
||||
const idx = QuickReplySet.list.findIndex(it=>it.name.toLowerCase().localeCompare(qrs.name.toLowerCase()) == 1);
|
||||
const idx = QuickReplySet.list.findIndex(it => it.name.toLowerCase().localeCompare(qrs.name.toLowerCase()) == 1);
|
||||
if (idx > -1) {
|
||||
QuickReplySet.list.splice(idx, 0, qrs);
|
||||
} else {
|
||||
@@ -496,7 +488,7 @@ export class SettingsUi {
|
||||
}
|
||||
|
||||
exportQrSet() {
|
||||
const blob = new Blob([JSON.stringify(this.currentQrSet)], { type:'application/json' });
|
||||
const blob = new Blob([JSON.stringify(this.currentQrSet)], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a'); {
|
||||
a.href = url;
|
||||
|
||||
@@ -11,8 +11,6 @@ export class ContextMenu {
|
||||
/**@type {HTMLElement}*/ menu;
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(/**@type {QuickReply}*/qr) {
|
||||
// this.itemList = items;
|
||||
this.itemList = this.build(qr).children;
|
||||
@@ -104,8 +102,6 @@ export class ContextMenu {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
show({ clientX, clientY }) {
|
||||
if (this.isActive) return;
|
||||
this.isActive = true;
|
||||
|
||||
@@ -15,8 +15,6 @@ export class MenuItem {
|
||||
/**@type {function}*/ onExpand;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {?string} icon
|
||||
@@ -80,7 +78,6 @@ export class MenuItem {
|
||||
}
|
||||
item.addEventListener('mouseover', () => sub.show(item));
|
||||
item.addEventListener('mouseleave', () => sub.hide());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ export class SubMenu {
|
||||
/**@type {HTMLElement}*/ root;
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(/**@type {MenuItem[]}*/items) {
|
||||
this.itemList = items;
|
||||
}
|
||||
@@ -29,8 +27,6 @@ export class SubMenu {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
show(/**@type {HTMLElement}*/parent) {
|
||||
if (this.isActive) return;
|
||||
this.isActive = true;
|
||||
|
||||
@@ -1031,7 +1031,6 @@ function executeRegexScriptForDebugging(script, text) {
|
||||
const trailingText = text.substring(lastIndex);
|
||||
outputText += trailingText;
|
||||
highlightedOutput += escapeHtml(trailingText);
|
||||
|
||||
} catch (e) {
|
||||
err = (err ? err + '; ' : '') + `Replace error: ${e.message}`;
|
||||
outputText = text; // Fallback
|
||||
|
||||
@@ -115,5 +115,4 @@ jQuery(() => {
|
||||
returns: 'number of tokens',
|
||||
helpString: 'Counts the number of tokens in the current chat.',
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
@@ -1043,7 +1043,6 @@ class AllTalkTtsProvider {
|
||||
// V2: Combine the endpoint with the relative path
|
||||
return `${this.settings.provider_endpoint}${data.output_file_url}`;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('[fetchTtsGeneration] Exception caught:', error);
|
||||
throw error;
|
||||
|
||||
@@ -239,7 +239,6 @@ class ChatterboxTtsProvider {
|
||||
}
|
||||
|
||||
this.setupEventListeners();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading Chatterbox settings:', error);
|
||||
this.updateStatus('Offline');
|
||||
@@ -518,7 +517,6 @@ class ChatterboxTtsProvider {
|
||||
});
|
||||
|
||||
await audio.play();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error previewing voice:', error);
|
||||
this.updateStatus('Ready');
|
||||
@@ -627,7 +625,6 @@ class ChatterboxTtsProvider {
|
||||
|
||||
// Return the response directly - SillyTavern expects a Response object
|
||||
return response;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in generateTts:', error);
|
||||
this.updateStatus('Ready');
|
||||
|
||||
@@ -160,7 +160,7 @@ class CoquiTtsProvider {
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
coquiApiModels = json;
|
||||
console.debug(DEBUG_PREFIX,'initialized coqui-api model list to', coquiApiModels);
|
||||
console.debug(DEBUG_PREFIX, 'initialized coqui-api model list to', coquiApiModels);
|
||||
/*
|
||||
$('#coqui_api_language')
|
||||
.find('option')
|
||||
@@ -180,7 +180,7 @@ class CoquiTtsProvider {
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
coquiApiModelsFull = json;
|
||||
console.debug(DEBUG_PREFIX,'initialized coqui-api full model list to', coquiApiModelsFull);
|
||||
console.debug(DEBUG_PREFIX, 'initialized coqui-api full model list to', coquiApiModelsFull);
|
||||
/*
|
||||
$('#coqui_api_full_language')
|
||||
.find('option')
|
||||
@@ -197,7 +197,7 @@ class CoquiTtsProvider {
|
||||
}
|
||||
|
||||
// Perform a simple readiness check by trying to fetch voiceIds
|
||||
async checkReady(){
|
||||
async checkReady() {
|
||||
throwIfModuleMissing();
|
||||
await this.fetchTtsVoiceObjects();
|
||||
}
|
||||
@@ -384,12 +384,12 @@ class CoquiTtsProvider {
|
||||
.append('<option value="none">Select model language</option>')
|
||||
.val('none');
|
||||
|
||||
for(let language in coquiApiModels) {
|
||||
for (let language in coquiApiModels) {
|
||||
let languageLabel = language;
|
||||
if (language in languageLabels)
|
||||
languageLabel = languageLabels[language];
|
||||
$('#coqui_api_language').append(new Option(languageLabel,language));
|
||||
console.log(DEBUG_PREFIX,'added language',languageLabel,'(',language,')');
|
||||
$('#coqui_api_language').append(new Option(languageLabel, language));
|
||||
console.log(DEBUG_PREFIX, 'added language', languageLabel, '(', language, ')');
|
||||
}
|
||||
|
||||
$('#coqui_api_model_div').show();
|
||||
@@ -406,12 +406,12 @@ class CoquiTtsProvider {
|
||||
.append('<option value="none">Select model language</option>')
|
||||
.val('none');
|
||||
|
||||
for(let language in coquiApiModelsFull) {
|
||||
for (let language in coquiApiModelsFull) {
|
||||
let languageLabel = language;
|
||||
if (language in languageLabels)
|
||||
languageLabel = languageLabels[language];
|
||||
$('#coqui_api_language').append(new Option(languageLabel,language));
|
||||
console.log(DEBUG_PREFIX,'added language',languageLabel,'(',language,')');
|
||||
$('#coqui_api_language').append(new Option(languageLabel, language));
|
||||
console.log(DEBUG_PREFIX, 'added language', languageLabel, '(', language, ')');
|
||||
}
|
||||
|
||||
$('#coqui_api_model_div').show();
|
||||
@@ -450,8 +450,8 @@ class CoquiTtsProvider {
|
||||
if (model_origin == 'coqui-api-full')
|
||||
modelDict = coquiApiModelsFull;
|
||||
|
||||
for(let model_dataset in modelDict[model_language])
|
||||
for(let model_name in modelDict[model_language][model_dataset]) {
|
||||
for (let model_dataset in modelDict[model_language])
|
||||
for (let model_name in modelDict[model_language][model_dataset]) {
|
||||
const model_id = model_dataset + '/' + model_name;
|
||||
const model_label = model_name + ' (' + model_dataset + ' dataset)';
|
||||
$('#coqui_api_model_name').append(new Option(model_label, model_id));
|
||||
@@ -526,7 +526,7 @@ class CoquiTtsProvider {
|
||||
|
||||
// Check if already installed and propose to do it otherwise
|
||||
const model_id = modelDict[model_language][model_dataset][model_name].id;
|
||||
console.debug(DEBUG_PREFIX,'Check if model is already installed',model_id);
|
||||
console.debug(DEBUG_PREFIX, 'Check if model is already installed', model_id);
|
||||
const result = await CoquiTtsProvider.checkmodel_state(model_id);
|
||||
const resultJSON = await result.json();
|
||||
const model_state = resultJSON.model_state;
|
||||
@@ -583,7 +583,6 @@ class CoquiTtsProvider {
|
||||
$('#coqui_api_model_install_button').show();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -110,15 +110,11 @@ class CosyVoiceProvider {
|
||||
//#################//
|
||||
|
||||
async getVoice(voiceName) {
|
||||
|
||||
|
||||
|
||||
if (this.voices.length == 0) {
|
||||
this.voices = await this.fetchTtsVoiceObjects();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const match = this.voices.filter(
|
||||
v => v.name == voiceName,
|
||||
)[0];
|
||||
@@ -130,7 +126,6 @@ class CosyVoiceProvider {
|
||||
}
|
||||
|
||||
|
||||
|
||||
async generateTts(text, voiceId) {
|
||||
const response = await this.fetchTtsGeneration(text, voiceId);
|
||||
return response;
|
||||
@@ -198,7 +193,6 @@ class CosyVoiceProvider {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Interface not used
|
||||
async fetchTtsFromHistory(history_item_id) {
|
||||
return Promise.resolve(history_item_id);
|
||||
|
||||
@@ -132,7 +132,7 @@ class ElevenLabsTtsProvider {
|
||||
}
|
||||
|
||||
if (Object.hasOwn(settings, 'apiKey')) {
|
||||
if (settings.apiKey && !secret_state[SECRET_KEYS.ELEVENLABS]){
|
||||
if (settings.apiKey && !secret_state[SECRET_KEYS.ELEVENLABS]) {
|
||||
await writeSecret(SECRET_KEYS.ELEVENLABS, settings.apiKey);
|
||||
}
|
||||
delete settings.apiKey;
|
||||
|
||||
@@ -124,7 +124,6 @@ export class GoogleNativeTtsProvider {
|
||||
console.info(`Google TTS: Loaded ${this.voices.length} voices`);
|
||||
|
||||
return this.voices;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch Google TTS voices:', error);
|
||||
throw error;
|
||||
@@ -151,7 +150,6 @@ export class GoogleNativeTtsProvider {
|
||||
this.audioElement.src = url;
|
||||
this.audioElement.play();
|
||||
this.audioElement.onended = () => URL.revokeObjectURL(url);
|
||||
|
||||
} catch (error) {
|
||||
console.error('TTS Preview Error:', error);
|
||||
toastr.error(`Could not generate preview: ${error.message}`);
|
||||
|
||||
@@ -115,15 +115,11 @@ class GptSovitsV2Provider {
|
||||
//#################//
|
||||
|
||||
async getVoice(voiceName) {
|
||||
|
||||
|
||||
|
||||
if (this.voices.length == 0) {
|
||||
this.voices = await this.fetchTtsVoiceObjects();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const match = this.voices.filter(
|
||||
v => v.name == voiceName,
|
||||
)[0];
|
||||
@@ -135,7 +131,6 @@ class GptSovitsV2Provider {
|
||||
}
|
||||
|
||||
|
||||
|
||||
async generateTts(text, voiceId) {
|
||||
const response = await this.fetchTtsGeneration(text, voiceId);
|
||||
return response;
|
||||
@@ -171,8 +166,6 @@ class GptSovitsV2Provider {
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
async fetchTtsGeneration(inputText, voiceId, lang = null, forceNoStreaming = false) {
|
||||
console.info(`Generating new TTS for voice_id ${voiceId}`);
|
||||
|
||||
@@ -215,7 +208,6 @@ class GptSovitsV2Provider {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Interface not used
|
||||
async fetchTtsFromHistory(history_item_id) {
|
||||
return Promise.resolve(history_item_id);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import { saveTtsProviderSettings } from './index.js';
|
||||
|
||||
export { GSVITtsProvider };
|
||||
@@ -60,11 +59,9 @@ class GSVITtsProvider {
|
||||
const characterList = await response.json();
|
||||
this.characterList = characterList;
|
||||
this.voices = Object.keys(characterList);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
get settingsHtml() {
|
||||
let html = `
|
||||
<label for="gsvi_api_language">Text Language</label>
|
||||
@@ -142,11 +139,8 @@ class GSVITtsProvider {
|
||||
$('#gsvi_batch_size_output').text(this.settings.batch_size);
|
||||
|
||||
|
||||
|
||||
|
||||
// Persist settings changes
|
||||
saveTtsProviderSettings();
|
||||
|
||||
}
|
||||
|
||||
async loadSettings(settings) {
|
||||
@@ -197,7 +191,6 @@ class GSVITtsProvider {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Perform a simple readiness check by trying to fetch voiceIds
|
||||
async checkReady() {
|
||||
await Promise.allSettled([this.fetchCharacterList()]);
|
||||
@@ -256,12 +249,10 @@ class GSVITtsProvider {
|
||||
|
||||
|
||||
return `${this.settings.provider_endpoint}/tts?${params.toString()}`;
|
||||
|
||||
}
|
||||
|
||||
// Interface not used by GSVI TTS
|
||||
async fetchTtsFromHistory(history_item_id) {
|
||||
return Promise.resolve(history_item_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -611,7 +611,6 @@ async function processTtsQueue() {
|
||||
|
||||
// Pass the full voiceMapKey (e.g., "User ("Quotes")") as well with character name
|
||||
await tts(segmentText, voiceId, char, voiceMapKey);
|
||||
|
||||
} catch (error) {
|
||||
toastr.error(error.toString());
|
||||
console.error(error);
|
||||
@@ -707,7 +706,6 @@ async function processTtsQueue() {
|
||||
|
||||
// Clear current job so the segmented jobs can be processed
|
||||
currentTtsJob = null;
|
||||
|
||||
} catch (error) {
|
||||
toastr.error(error.toString());
|
||||
console.error(error);
|
||||
@@ -1286,7 +1284,6 @@ export function getCharacters(unrestricted) {
|
||||
}
|
||||
|
||||
return characters;
|
||||
|
||||
}
|
||||
|
||||
export function sanitizeId(input) {
|
||||
@@ -1314,7 +1311,6 @@ function parseVoiceMap(voiceMapString) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply voiceMap based on current voiceMapEntries
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@ let ready = false;
|
||||
let voices = [];
|
||||
|
||||
// Handle messages from the main thread
|
||||
self.onmessage = async function(e) {
|
||||
self.onmessage = async function (e) {
|
||||
const { action, data } = e.data;
|
||||
|
||||
switch (action) {
|
||||
|
||||
@@ -837,7 +837,6 @@ class MiniMaxTtsProvider {
|
||||
// Backend handles all the complex processing and returns audio data directly
|
||||
console.debug('MiniMax TTS: Audio response received from backend');
|
||||
return response;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in MiniMax TTS generation:', error);
|
||||
throw error;
|
||||
@@ -954,7 +953,6 @@ class MiniMaxTtsProvider {
|
||||
this.audioElement.onended = null;
|
||||
this.audioElement.onerror = null;
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('MiniMax TTS Preview Error:', error);
|
||||
toastr.error(`Could not generate preview: ${error.message}`);
|
||||
|
||||
@@ -146,7 +146,6 @@ class OpenAITtsProvider {
|
||||
}
|
||||
|
||||
populateCharacterInstructions() {
|
||||
|
||||
const currentCharacters = $('.tts_voicemap_block_char span').map((i, el) => $(el).text()).get();
|
||||
|
||||
$('#openai-character-instructions').empty();
|
||||
|
||||
@@ -172,5 +172,4 @@ class SileroTtsProvider {
|
||||
async fetchTtsFromHistory(history_item_id) {
|
||||
return Promise.resolve(history_item_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -323,5 +323,4 @@ class XTTSTtsProvider {
|
||||
async fetchTtsFromHistory(history_item_id) {
|
||||
return Promise.resolve(history_item_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1456,7 +1456,6 @@ async function onViewStatsClick() {
|
||||
messageElement.addClass('vectorized');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function onVectorizeAllFilesClick() {
|
||||
|
||||
@@ -13,7 +13,6 @@ export function SaveLocal(target, val) {
|
||||
export function LoadLocal(target) {
|
||||
console.debug('LoadLocal -- ' + target);
|
||||
return localStorage.getItem(target);
|
||||
|
||||
}
|
||||
/**
|
||||
* @deprecated THIS FUNCTION IS OBSOLETE. DO NOT USE
|
||||
|
||||
@@ -76,7 +76,6 @@ export const fuzzySearchCategories = Object.freeze({
|
||||
* data = filterHelper.applyFilters(data);
|
||||
*/
|
||||
export class FilterHelper {
|
||||
|
||||
/**
|
||||
* Cache fuzzy search weighting scores for re-usability, sorting and stuff
|
||||
*
|
||||
|
||||
@@ -2477,7 +2477,6 @@ jQuery(() => {
|
||||
const value = $(this).prop('checked');
|
||||
hideMutedSprites = value;
|
||||
onHideMutedSpritesClick(value);
|
||||
|
||||
});
|
||||
$('#send_textarea').on('keyup', onSendTextareaInput);
|
||||
$('#groupCurrentMemberPopoutButton').on('click', doCurMemberListPopout);
|
||||
|
||||
@@ -59,7 +59,8 @@ export function initInputMarkdown() {
|
||||
let cursorShift = charsToAdd.length;
|
||||
let selectedTextandPossibleFormatting = textarea.value.substring(start - possiblePreviousFormattingMargin, end + possiblePreviousFormattingMargin).trim();
|
||||
|
||||
if (isTextSelected) { //if text is selected
|
||||
if (isTextSelected) {
|
||||
//if text is selected
|
||||
selectedText = textarea.value.substring(start, end);
|
||||
if (selectedTextandPossibleFormatting === charsToAdd + selectedText + charsToAdd) {
|
||||
// If the selected text is already formatted, remove the formatting
|
||||
@@ -90,7 +91,8 @@ export function initInputMarkdown() {
|
||||
textarea.focus();
|
||||
document.execCommand('insertText', false, charsToAdd + selectedText + charsToAdd + possibleAddedSpace);
|
||||
}
|
||||
} else {// No text is selected
|
||||
} else {
|
||||
// No text is selected
|
||||
//check 1 character before and after the cursor for non-space characters
|
||||
|
||||
if (beforeCaret !== ' ' && afterCaret !== ' ' && afterCaret !== '' && beforeCaret !== '') { //look for caret in the middle of a word
|
||||
@@ -116,7 +118,6 @@ export function initInputMarkdown() {
|
||||
}
|
||||
|
||||
if (charsToAdd + discoveredWord + charsToAdd === discoveredWordWithPossibleFormatting) {
|
||||
|
||||
// Replace the expanded selection with the original discovered word
|
||||
textarea.focus();
|
||||
document.execCommand('insertText', false, discoveredWord);
|
||||
@@ -126,8 +127,6 @@ export function initInputMarkdown() {
|
||||
textarea.focus();
|
||||
document.execCommand('insertText', false, charsToAdd + discoveredWord + charsToAdd);
|
||||
}
|
||||
|
||||
|
||||
} else { //caret is not inside a word, so just add the formatting
|
||||
textarea.focus();
|
||||
textarea.setSelectionRange(start, end);
|
||||
|
||||
@@ -798,7 +798,6 @@ jQuery(() => {
|
||||
$('#instruct_system_sequence').prop('readOnly', false);
|
||||
$('#instruct_system_suffix').prop('readOnly', false);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$('#instruct_enabled').on('change', function () {
|
||||
|
||||
@@ -2279,7 +2279,6 @@ function appendElectronHubOptions(model_list, groupModels = false) {
|
||||
appendOption(model);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function electronHubSortBy(data, property = 'alphabetically') {
|
||||
@@ -3985,7 +3984,6 @@ function loadOpenAISettings(data, settings) {
|
||||
option.value = i;
|
||||
option.text = item;
|
||||
$('#settings_preset_openai').append(option);
|
||||
|
||||
});
|
||||
openai_setting_names = settingNames;
|
||||
|
||||
@@ -4896,7 +4894,6 @@ function getSiliconflowMaxContext(model, isUnlocked) {
|
||||
|
||||
// Return context size if model found, otherwise default to 32k
|
||||
return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || max_32k;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5041,7 +5038,6 @@ async function onModelChange() {
|
||||
console.log('Claude model changed to', value);
|
||||
oai_settings.claude_model = value;
|
||||
$('#model_claude_select').val(oai_settings.claude_model);
|
||||
|
||||
}
|
||||
|
||||
if ($(this).is('#model_openai_select')) {
|
||||
|
||||
@@ -1593,7 +1593,6 @@ export async function showCharConnections() {
|
||||
highlightPersonas: true,
|
||||
targetedChar: getCurrentConnectionObj(),
|
||||
shiftClickHandler: (element, ev) => {
|
||||
|
||||
const personaId = $(element).attr('data-pid');
|
||||
|
||||
/** @type {PersonaConnection[]} */
|
||||
@@ -1845,7 +1844,6 @@ async function lockPersonaCallback(_args, value) {
|
||||
if (isFalseBoolean(value)) {
|
||||
await setPersonaLockState(false, type);
|
||||
return 'false';
|
||||
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
@@ -478,7 +478,6 @@ export class Popup {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
this.dlg.addEventListener('keydown', keyListener.bind(this));
|
||||
}
|
||||
|
||||
@@ -536,7 +536,6 @@ function switchSwipeNumAllMessages() {
|
||||
var originalSliderValues = [];
|
||||
|
||||
async function switchLabMode({ noReset = false } = {}) {
|
||||
|
||||
/* if (power_user.enableZenSliders && power_user.enableLabMode) {
|
||||
toastr.warning("Can't start Lab Mode while Zen Sliders are active")
|
||||
return
|
||||
@@ -571,8 +570,6 @@ async function switchLabMode({ noReset = false } = {}) {
|
||||
$('#amount_gen').attr('min', '1')
|
||||
.attr('max', '99999')
|
||||
.attr('step', '1');
|
||||
|
||||
|
||||
} else if (!noReset) {
|
||||
//re apply the original sliders values to each input
|
||||
originalSliderValues.forEach(function (slider) {
|
||||
@@ -628,7 +625,6 @@ async function switchZenSliders() {
|
||||
});
|
||||
$('div[id$="_zenslider"]').remove();
|
||||
}
|
||||
|
||||
}
|
||||
async function CreateZenSliders(elmnt) {
|
||||
var originalSlider = elmnt;
|
||||
@@ -1178,7 +1174,6 @@ function applyShadowWidth() {
|
||||
document.documentElement.style.setProperty('--shadowWidth', String(power_user.shadow_width));
|
||||
$('#shadow_width_counter').val(power_user.shadow_width);
|
||||
$('#shadow_width').val(power_user.shadow_width);
|
||||
|
||||
}
|
||||
|
||||
function applyFontScale(type) {
|
||||
@@ -2954,7 +2949,6 @@ function setAvgBG() {
|
||||
} */
|
||||
|
||||
function getAverageRGB(imgEl) {
|
||||
|
||||
var blockSize = 5, // only visit every 5 pixels
|
||||
defaultRGB = { r: 0, g: 0, b: 0 }, // for non-supporting envs
|
||||
canvas = document.createElement('canvas'),
|
||||
@@ -2994,7 +2988,6 @@ function setAvgBG() {
|
||||
rgb.b = ~~(rgb.b / count);
|
||||
|
||||
return rgb;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4035,7 +4028,7 @@ jQuery(() => {
|
||||
return;
|
||||
}
|
||||
|
||||
eventSource.once(event_types.SETTINGS_UPDATED, function() {
|
||||
eventSource.once(event_types.SETTINGS_UPDATED, function () {
|
||||
toastr.warning(
|
||||
t`Click here to reload.`,
|
||||
t`Toggling the Experimental Macro Engine requires a reload.`,
|
||||
|
||||
@@ -514,7 +514,6 @@ class PresetManager {
|
||||
console.error('Preset could not be renamed', error);
|
||||
throw new Error('Preset could not be renamed');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -865,7 +865,6 @@ function selectReasoningTemplateCallback(args, name) {
|
||||
UI.$select.val(foundName).trigger('change');
|
||||
!quiet && toastr.success(`Reasoning template "${foundName}" selected`);
|
||||
return foundName;
|
||||
|
||||
}
|
||||
|
||||
function registerReasoningSlashCommands() {
|
||||
|
||||
@@ -203,7 +203,6 @@ function setSamplerListListeners() {
|
||||
|
||||
console.log(samplerName, relatedDOMElement.data(SELECT_SAMPLER.DATA), shouldDisplay);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function isElementVisibleInDOM(element) {
|
||||
|
||||
@@ -9,7 +9,7 @@ export const markdownUnderscoreExt = () => {
|
||||
return [{
|
||||
type: 'output',
|
||||
regex: new RegExp('(<code(?:\\s+[^>]*)?>[\\s\\S]*?<\\/code>|<style(?:\\s+[^>]*)?>[\\s\\S]*?<\\/style>)|\\b(?<!_)_(?!_)(.*?)(?<!_)_(?!_)\\b', 'gi'),
|
||||
replace: function(match, tagContent, italicContent) {
|
||||
replace: function (match, tagContent, italicContent) {
|
||||
if (tagContent) {
|
||||
// If it's inside <code> or <style> tags, return unchanged
|
||||
return match;
|
||||
|
||||
@@ -4916,7 +4916,6 @@ export async function sendNarratorMessage(args, text) {
|
||||
}
|
||||
|
||||
export async function promptQuietForLoudResponse(who, text) {
|
||||
|
||||
let character_id = getContext().characterId;
|
||||
if (who === 'sys') {
|
||||
text = 'System: ' + text;
|
||||
@@ -4955,7 +4954,6 @@ export async function promptQuietForLoudResponse(who, text) {
|
||||
addOneMessage(message);
|
||||
await eventSource.emit(event_types.USER_MESSAGE_RENDERED, (chat.length - 1));
|
||||
await saveChatConditional();
|
||||
|
||||
}
|
||||
|
||||
async function sendCommentMessage(args, text) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import { SlashCommandScope } from './SlashCommandScope.js';
|
||||
*/
|
||||
|
||||
|
||||
|
||||
export class SlashCommand {
|
||||
/**
|
||||
* Creates a SlashCommand from a properties object.
|
||||
@@ -48,8 +47,6 @@ export class SlashCommand {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**@type {string}*/ name;
|
||||
/**@type {(namedArguments:NamedArguments, unnamedArguments:UnnamedArguments)=>string|SlashCommandClosure|Promise<string|SlashCommandClosure>}*/ callback;
|
||||
/**@type {string}*/ helpString;
|
||||
@@ -86,7 +83,7 @@ export class SlashCommand {
|
||||
name.classList.add('name');
|
||||
name.classList.add('monospace');
|
||||
name.textContent = '/';
|
||||
key.split('').forEach(char=>{
|
||||
key.split('').forEach(char => {
|
||||
const span = document.createElement('span'); {
|
||||
span.textContent = char;
|
||||
name.append(span);
|
||||
@@ -229,7 +226,7 @@ export class SlashCommand {
|
||||
const unnamedArguments = cmd.unnamedArgumentList ?? [];
|
||||
const returnType = cmd.returns ?? 'void';
|
||||
const helpString = cmd.helpString ?? 'NO DETAILS';
|
||||
const aliasList = [cmd.name, ...(cmd.aliases ?? [])].filter(it=>it != key);
|
||||
const aliasList = [cmd.name, ...(cmd.aliases ?? [])].filter(it => it != key);
|
||||
const specs = document.createElement('div'); {
|
||||
specs.classList.add('specs');
|
||||
const head = document.createElement('div'); {
|
||||
@@ -257,7 +254,7 @@ export class SlashCommand {
|
||||
this.isExtension ? 'Extension' : 'Core',
|
||||
this.isThirdParty ? 'Third Party' : (this.isExtension ? 'Core' : null),
|
||||
this.source,
|
||||
].filter(it=>it).join('\n');
|
||||
].filter(it => it).join('\n');
|
||||
head.append(src);
|
||||
}
|
||||
if (this.rawQuotes) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { SlashCommandExecutor } from './SlashCommandExecutor.js';
|
||||
import { SlashCommandScope } from './SlashCommandScope.js';
|
||||
|
||||
|
||||
|
||||
/**@readonly*/
|
||||
/**@enum {string}*/
|
||||
export const ARGUMENT_TYPE = {
|
||||
@@ -68,7 +67,7 @@ export class SlashCommandArgument {
|
||||
this.isRequired = isRequired ?? false;
|
||||
this.acceptsMultiple = acceptsMultiple ?? false;
|
||||
this.defaultValue = defaultValue;
|
||||
this.enumList = (enums ? Array.isArray(enums) ? enums : [enums] : []).map(it=>{
|
||||
this.enumList = (enums ? Array.isArray(enums) ? enums : [enums] : []).map(it => {
|
||||
if (it instanceof SlashCommandEnumValue) return it;
|
||||
return new SlashCommandEnumValue(it);
|
||||
});
|
||||
|
||||
@@ -22,11 +22,11 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
||||
executor.start,
|
||||
Object
|
||||
.keys(commands)
|
||||
.map(key=>new SlashCommandCommandAutoCompleteOption(commands[key], key))
|
||||
.map(key => new SlashCommandCommandAutoCompleteOption(commands[key], key))
|
||||
,
|
||||
false,
|
||||
()=>`No matching slash commands for "/${this.name}"`,
|
||||
()=>'No slash commands found!',
|
||||
() => `No matching slash commands for "/${this.name}"`,
|
||||
() => 'No slash commands found!',
|
||||
);
|
||||
this.executor = executor;
|
||||
this.scope = scope;
|
||||
@@ -63,7 +63,7 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
||||
if (!Array.isArray(this.executor.command?.namedArgumentList)) {
|
||||
return null;
|
||||
}
|
||||
const notProvidedNamedArguments = this.executor.command.namedArgumentList.filter(arg=>!this.executor.namedArgumentList.find(it=>it.name == arg.name));
|
||||
const notProvidedNamedArguments = this.executor.command.namedArgumentList.filter(arg => !this.executor.namedArgumentList.find(it => it.name == arg.name));
|
||||
let name;
|
||||
let value;
|
||||
let start;
|
||||
@@ -73,13 +73,13 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
||||
const namedArgsFollowedBySpace = text[this.executor.endNamedArgs] == ' ';
|
||||
if (this.executor.startNamedArgs <= index && this.executor.endNamedArgs + (namedArgsFollowedBySpace ? 1 : 0) >= index) {
|
||||
// cursor is somewhere within the named arguments (including final space)
|
||||
argAssign = this.executor.namedArgumentList.find(it=>it.start <= index && it.end >= index);
|
||||
argAssign = this.executor.namedArgumentList.find(it => it.start <= index && it.end >= index);
|
||||
if (argAssign) {
|
||||
const [argName, ...v] = text.slice(argAssign.start, index).split(getSplitRegex());
|
||||
name = argName;
|
||||
value = v.join('');
|
||||
start = argAssign.start;
|
||||
cmdArg = this.executor.command.namedArgumentList.find(it=>[it.name, `${it.name}=`].includes(argAssign.name));
|
||||
cmdArg = this.executor.command.namedArgumentList.find(it => [it.name, `${it.name}=`].includes(argAssign.name));
|
||||
if (cmdArg) notProvidedNamedArguments.push(cmdArg);
|
||||
} else {
|
||||
name = '';
|
||||
@@ -106,13 +106,13 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
||||
// if cursor is already behind "=" check for enums
|
||||
const enumList = cmdArg?.enumProvider?.(this.executor, this.scope) ?? cmdArg?.enumList;
|
||||
if (cmdArg && enumList?.length) {
|
||||
if (isSelect && enumList.find(it=>it.value == value) && argAssign && argAssign.end == index) {
|
||||
if (isSelect && enumList.find(it => it.value == value) && argAssign && argAssign.end == index) {
|
||||
return null;
|
||||
}
|
||||
const result = new AutoCompleteSecondaryNameResult(
|
||||
value,
|
||||
start + name.length,
|
||||
enumList.map(it=>SlashCommandEnumAutoCompleteOption.from(this.executor.command, it)),
|
||||
enumList.map(it => SlashCommandEnumAutoCompleteOption.from(this.executor.command, it)),
|
||||
true,
|
||||
);
|
||||
result.isRequired = true;
|
||||
@@ -125,10 +125,10 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
||||
const result = new AutoCompleteSecondaryNameResult(
|
||||
name,
|
||||
start,
|
||||
notProvidedNamedArguments.map(it=>new SlashCommandNamedArgumentAutoCompleteOption(it, this.executor.command)),
|
||||
notProvidedNamedArguments.map(it => new SlashCommandNamedArgumentAutoCompleteOption(it, this.executor.command)),
|
||||
false,
|
||||
);
|
||||
result.isRequired = notProvidedNamedArguments.find(it=>it.isRequired) != null;
|
||||
result.isRequired = notProvidedNamedArguments.find(it => it.isRequired) != null;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
||||
let argAssign;
|
||||
if (this.executor.startUnnamedArgs <= index && this.executor.endUnnamedArgs + 1 >= index) {
|
||||
// cursor is somwehere in the unnamed args
|
||||
const idx = this.executor.unnamedArgumentList.findIndex(it=>it.start <= index && it.end >= index);
|
||||
const idx = this.executor.unnamedArgumentList.findIndex(it => it.start <= index && it.end >= index);
|
||||
if (idx > -1) {
|
||||
argAssign = this.executor.unnamedArgumentList[idx];
|
||||
cmdArg = this.executor.command.unnamedArgumentList[idx];
|
||||
@@ -179,10 +179,10 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
||||
const result = new AutoCompleteSecondaryNameResult(
|
||||
value,
|
||||
start,
|
||||
enumList.map(it=>SlashCommandEnumAutoCompleteOption.from(this.executor.command, it)),
|
||||
enumList.map(it => SlashCommandEnumAutoCompleteOption.from(this.executor.command, it)),
|
||||
false,
|
||||
);
|
||||
const isCompleteValue = enumList.find(it=>it.value == value);
|
||||
const isCompleteValue = enumList.find(it => it.value == value);
|
||||
const isSelectedValue = isSelect && isCompleteValue;
|
||||
result.isRequired = cmdArg.isRequired && !isSelectedValue;
|
||||
result.forceMatch = cmdArg.forceEnum;
|
||||
|
||||
@@ -25,7 +25,7 @@ export class SlashCommandBrowser {
|
||||
inp.classList.add('text_pole');
|
||||
inp.type = 'search';
|
||||
inp.placeholder = 'Search slash commands - use quotes to search "literal" instead of fuzzy';
|
||||
inp.addEventListener('input', ()=>{
|
||||
inp.addEventListener('input', () => {
|
||||
this.details?.remove();
|
||||
this.details = null;
|
||||
let query = inp.value.trim();
|
||||
@@ -38,7 +38,7 @@ export class SlashCommandBrowser {
|
||||
const match = queryRegex.exec(query);
|
||||
if (!match) break;
|
||||
if (match[1] !== undefined) {
|
||||
fuzzyList.push(new RegExp(`^(.*?)${match[1].split('').map(char=>`(${escapeRegex(char)})`).join('(.*?)')}(.*?)$`, 'i'));
|
||||
fuzzyList.push(new RegExp(`^(.*?)${match[1].split('').map(char => `(${escapeRegex(char)})`).join('(.*?)')}(.*?)$`, 'i'));
|
||||
} else if (match[2] !== undefined) {
|
||||
quotedList.push(match[2]);
|
||||
}
|
||||
@@ -47,17 +47,17 @@ export class SlashCommandBrowser {
|
||||
for (const cmd of this.cmdList) {
|
||||
const targets = [
|
||||
cmd.name,
|
||||
...cmd.namedArgumentList.map(it=>it.name),
|
||||
...cmd.namedArgumentList.map(it=>it.description),
|
||||
...cmd.namedArgumentList.map(it=>it.enumList.map(e=>e.value)).flat(),
|
||||
...cmd.namedArgumentList.map(it=>it.typeList).flat(),
|
||||
...cmd.unnamedArgumentList.map(it=>it.description),
|
||||
...cmd.unnamedArgumentList.map(it=>it.enumList.map(e=>e.value)).flat(),
|
||||
...cmd.unnamedArgumentList.map(it=>it.typeList).flat(),
|
||||
...cmd.namedArgumentList.map(it => it.name),
|
||||
...cmd.namedArgumentList.map(it => it.description),
|
||||
...cmd.namedArgumentList.map(it => it.enumList.map(e => e.value)).flat(),
|
||||
...cmd.namedArgumentList.map(it => it.typeList).flat(),
|
||||
...cmd.unnamedArgumentList.map(it => it.description),
|
||||
...cmd.unnamedArgumentList.map(it => it.enumList.map(e => e.value)).flat(),
|
||||
...cmd.unnamedArgumentList.map(it => it.typeList).flat(),
|
||||
...cmd.aliases,
|
||||
cmd.helpString,
|
||||
];
|
||||
const find = ()=>targets.find(t=>(fuzzyList.find(f=>f.test(t)) ?? quotedList.find(q=>t.includes(q))) !== undefined) !== undefined;
|
||||
const find = () => targets.find(t => (fuzzyList.find(f => f.test(t)) ?? quotedList.find(q => t.includes(q))) !== undefined) !== undefined;
|
||||
if (fuzzyList.length + quotedList.length === 0 || find()) {
|
||||
this.itemMap[cmd.name].classList.remove('isFiltered');
|
||||
} else {
|
||||
@@ -85,7 +85,7 @@ export class SlashCommandBrowser {
|
||||
const item = cmd.renderHelpItem();
|
||||
this.itemMap[cmd.name] = item;
|
||||
let details;
|
||||
item.addEventListener('click', ()=>{
|
||||
item.addEventListener('click', () => {
|
||||
if (!details) {
|
||||
details = document.createElement('div'); {
|
||||
details.classList.add('autoComplete-detailsWrap');
|
||||
@@ -97,7 +97,7 @@ export class SlashCommandBrowser {
|
||||
}
|
||||
}
|
||||
if (this.details !== details) {
|
||||
Array.from(list.querySelectorAll('.selected')).forEach(it=>it.classList.remove('selected'));
|
||||
Array.from(list.querySelectorAll('.selected')).forEach(it => it.classList.remove('selected'));
|
||||
item.classList.add('selected');
|
||||
this.details?.remove();
|
||||
container.append(details);
|
||||
@@ -122,13 +122,13 @@ export class SlashCommandBrowser {
|
||||
}
|
||||
parent.append(this.dom);
|
||||
|
||||
this.mo = new MutationObserver(muts=>{
|
||||
if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it === this.dom || it.contains(this.dom)))) {
|
||||
this.mo = new MutationObserver(muts => {
|
||||
if (muts.find(mut => Array.from(mut.removedNodes).find(it => it === this.dom || it.contains(this.dom)))) {
|
||||
this.mo.disconnect();
|
||||
window.removeEventListener('keydown', boundHandler);
|
||||
}
|
||||
});
|
||||
this.mo.observe(document.querySelector('#chat'), { childList:true, subtree:true });
|
||||
this.mo.observe(document.querySelector('#chat'), { childList: true, subtree: true });
|
||||
const boundHandler = this.handleKeyDown.bind(this);
|
||||
window.addEventListener('keydown', boundHandler);
|
||||
return this.dom;
|
||||
|
||||
@@ -37,7 +37,7 @@ export class SlashCommandClosure {
|
||||
|
||||
/**@type {number}*/
|
||||
get commandCount() {
|
||||
return this.executorList.map(executor=>executor.commandCount).reduce((sum,cur)=>sum + cur, 0);
|
||||
return this.executorList.map(executor => executor.commandCount).reduce((sum, cur) => sum + cur, 0);
|
||||
}
|
||||
|
||||
constructor(parent) {
|
||||
@@ -156,7 +156,7 @@ export class SlashCommandClosure {
|
||||
let isList = false;
|
||||
let listValues = [];
|
||||
scope = scope ?? this.scope;
|
||||
const escapeMacro = (it, isAnchored = false)=>{
|
||||
const escapeMacro = (it, isAnchored = false) => {
|
||||
const regexText = escapeRegex(it.key.replace(/\*/g, '~~~WILDCARD~~~'))
|
||||
.replaceAll('~~~WILDCARD~~~', '(?:(?:(?!(?:::|}})).)*)')
|
||||
;
|
||||
@@ -165,7 +165,7 @@ export class SlashCommandClosure {
|
||||
}
|
||||
return regexText;
|
||||
};
|
||||
const macroList = scope.macroList.toSorted((a,b)=>{
|
||||
const macroList = scope.macroList.toSorted((a, b) => {
|
||||
if (a.key.includes('*') && !b.key.includes('*')) return 1;
|
||||
if (!a.key.includes('*') && b.key.includes('*')) return -1;
|
||||
if (a.key.includes('*') && b.key.includes('*')) return b.key.indexOf('*') - a.key.indexOf('*');
|
||||
@@ -174,7 +174,7 @@ export class SlashCommandClosure {
|
||||
if (power_user.experimental_macro_engine) {
|
||||
return this.substituteWithMacroEngine(text, scope, macroList);
|
||||
}
|
||||
const macros = macroList.map(it=>escapeMacro(it)).join('|');
|
||||
const macros = macroList.map(it => escapeMacro(it)).join('|');
|
||||
const re = new RegExp(`(?<pipe>{{pipe}})|(?:{{var::(?<var>[^\\s]+?)(?:::(?<varIndex>(?!}}).+))?}})|(?:{{(?<macro>${macros})}})`);
|
||||
let done = '';
|
||||
let remaining = text;
|
||||
@@ -182,7 +182,7 @@ export class SlashCommandClosure {
|
||||
const match = re.exec(remaining);
|
||||
const before = substituteParams(remaining.slice(0, match.index));
|
||||
const after = remaining.slice(match.index + match[0].length);
|
||||
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;
|
||||
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;
|
||||
if (replacer instanceof SlashCommandClosure) {
|
||||
replacer.abortController = this.abortController;
|
||||
replacer.breakController = this.breakController;
|
||||
@@ -253,7 +253,7 @@ export class SlashCommandClosure {
|
||||
return step.value;
|
||||
}
|
||||
|
||||
async * executeDirect() {
|
||||
async* executeDirect() {
|
||||
this.debugController?.down(this);
|
||||
// closure arguments
|
||||
for (const arg of this.argumentList) {
|
||||
@@ -325,10 +325,10 @@ export class SlashCommandClosure {
|
||||
// breakpoint has to yield before arguments are resolved if one of the
|
||||
// arguments is an immediate closure, otherwise you cannot step into the
|
||||
// immediate closure
|
||||
const hasImmediateClosureInNamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.namedArgumentList?.find(it=>it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
const hasImmediateClosureInUnnamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.unnamedArgumentList?.find(it=>it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
const hasImmediateClosureInNamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.namedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
const hasImmediateClosureInUnnamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.unnamedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
if (hasImmediateClosureInNamedArgs || hasImmediateClosureInUnnamedArgs) {
|
||||
this.debugController.isStepping = yield { closure:this, executor:step.value };
|
||||
this.debugController.isStepping = yield { closure: this, executor: step.value };
|
||||
} else {
|
||||
this.debugController.isStepping = true;
|
||||
this.debugController.stepStack[this.debugController.stepStack.length - 1] = true;
|
||||
@@ -338,10 +338,10 @@ export class SlashCommandClosure {
|
||||
this.debugController.isSteppingInto = false;
|
||||
// if stepping, have to yield before arguments are resolved if one of the arguments
|
||||
// is an immediate closure, otherwise you cannot step into the immediate closure
|
||||
const hasImmediateClosureInNamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.namedArgumentList?.find(it=>it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
const hasImmediateClosureInUnnamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.unnamedArgumentList?.find(it=>it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
const hasImmediateClosureInNamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.namedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
const hasImmediateClosureInUnnamedArgs = /**@type {SlashCommandExecutor}*/(step.value)?.unnamedArgumentList?.find(it => it.value instanceof SlashCommandClosure && it.value.executeNow);
|
||||
if (hasImmediateClosureInNamedArgs || hasImmediateClosureInUnnamedArgs) {
|
||||
this.debugController.isStepping = yield { closure:this, executor:step.value };
|
||||
this.debugController.isStepping = yield { closure: this, executor: step.value };
|
||||
}
|
||||
}
|
||||
// resolve args
|
||||
@@ -354,7 +354,7 @@ export class SlashCommandClosure {
|
||||
}
|
||||
} else if (!step.done && this.debugController?.testStepping(this)) {
|
||||
this.debugController.isSteppingInto = false;
|
||||
this.debugController.isStepping = yield { closure:this, executor:step.value };
|
||||
this.debugController.isStepping = yield { closure: this, executor: step.value };
|
||||
}
|
||||
// execute executor
|
||||
step = await stepper.next();
|
||||
@@ -377,7 +377,7 @@ export class SlashCommandClosure {
|
||||
* - after arguments are resolved
|
||||
* - after execution
|
||||
*/
|
||||
async * executeStep() {
|
||||
async* executeStep() {
|
||||
let done = 0;
|
||||
let isFirst = true;
|
||||
for (const executor of this.executorList) {
|
||||
@@ -429,7 +429,7 @@ export class SlashCommandClosure {
|
||||
// then yield for "before exec"
|
||||
yield executor;
|
||||
// followed by command execution
|
||||
executor.onProgress = (subDone, subTotal)=>this.onProgress?.(done + subDone, this.commandCount);
|
||||
executor.onProgress = (subDone, subTotal) => this.onProgress?.(done + subDone, this.commandCount);
|
||||
const isStepping = this.debugController?.testStepping(this);
|
||||
if (this.debugController) {
|
||||
this.debugController.isStepping = false || this.debugController.isSteppingInto;
|
||||
@@ -586,7 +586,7 @@ export class SlashCommandClosure {
|
||||
if (!executor.command.splitUnnamedArgument) {
|
||||
if (value.length == 1) {
|
||||
value = value[0];
|
||||
} else if (!value.find(it=>it instanceof SlashCommandClosure)) {
|
||||
} else if (!value.find(it => it instanceof SlashCommandClosure)) {
|
||||
value = value.join('');
|
||||
}
|
||||
}
|
||||
@@ -598,7 +598,7 @@ export class SlashCommandClosure {
|
||||
?.replace(/\\\}/g, '}')
|
||||
;
|
||||
} else if (Array.isArray(value)) {
|
||||
value = value.map(v=>{
|
||||
value = value.map(v => {
|
||||
if (typeof v == 'string') {
|
||||
return v
|
||||
?.replace(/\\\{/g, '{')
|
||||
|
||||
@@ -10,8 +10,6 @@ export class SlashCommandCommandAutoCompleteOption extends AutoCompleteOption {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {SlashCommand} command
|
||||
* @param {string} name
|
||||
|
||||
@@ -155,7 +155,7 @@ export const commonEnumProviders = {
|
||||
...isAll || types.includes('scope') ? scope.allVariableNames.map(name => new SlashCommandEnumValue(name, null, enumTypes.variable, enumIcons.scopeVariable)) : [],
|
||||
...isAll || types.includes('local') ? Object.keys(chat_metadata.variables ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.name, enumIcons.localVariable)) : [],
|
||||
...isAll || types.includes('global') ? Object.keys(extension_settings.variables.global ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.macro, enumIcons.globalVariable)) : [],
|
||||
].filter((item, idx, list)=>idx == list.findIndex(it=>it.value == item.value));
|
||||
].filter((item, idx, list) => idx == list.findIndex(it => it.value == item.value));
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,15 +18,11 @@ export class SlashCommandDebugController {
|
||||
/** @type {(closure:SlashCommandClosure, executor:SlashCommandExecutor)=>Promise<boolean>} */ onBreakPoint;
|
||||
|
||||
|
||||
|
||||
|
||||
testStepping(closure) {
|
||||
return this.stepStack[this.stack.indexOf(closure)];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
down(closure) {
|
||||
this.stack.push(closure);
|
||||
if (this.stepStack.length < this.stack.length) {
|
||||
@@ -44,20 +40,19 @@ export class SlashCommandDebugController {
|
||||
}
|
||||
|
||||
|
||||
|
||||
resume() {
|
||||
this.continueResolver?.(false);
|
||||
this.continuePromise = null;
|
||||
this.stepStack.forEach((_,idx)=>this.stepStack[idx] = false);
|
||||
this.stepStack.forEach((_, idx) => this.stepStack[idx] = false);
|
||||
}
|
||||
step() {
|
||||
this.stepStack.forEach((_,idx)=>this.stepStack[idx] = true);
|
||||
this.stepStack.forEach((_, idx) => this.stepStack[idx] = true);
|
||||
this.continueResolver?.(true);
|
||||
this.continuePromise = null;
|
||||
}
|
||||
stepInto() {
|
||||
this.isSteppingInto = true;
|
||||
this.stepStack.forEach((_,idx)=>this.stepStack[idx] = true);
|
||||
this.stepStack.forEach((_, idx) => this.stepStack[idx] = true);
|
||||
this.continueResolver?.(true);
|
||||
this.continuePromise = null;
|
||||
}
|
||||
@@ -69,7 +64,7 @@ export class SlashCommandDebugController {
|
||||
}
|
||||
|
||||
async awaitContinue() {
|
||||
this.continuePromise ??= new Promise(resolve=>{
|
||||
this.continuePromise ??= new Promise(resolve => {
|
||||
this.continueResolver = resolve;
|
||||
});
|
||||
this.isStepping = await this.continuePromise;
|
||||
|
||||
@@ -9,7 +9,7 @@ export class SlashCommandEnumAutoCompleteOption extends AutoCompleteOption {
|
||||
* @returns {SlashCommandEnumAutoCompleteOption}
|
||||
*/
|
||||
static from(cmd, enumValue) {
|
||||
const mapped = this.valueToOptionMap.find(it=>enumValue instanceof it.value)?.option ?? this;
|
||||
const mapped = this.valueToOptionMap.find(it => enumValue instanceof it.value)?.option ?? this;
|
||||
return new mapped(cmd, enumValue);
|
||||
}
|
||||
/**@type {{value:(typeof SlashCommandEnumValue), option:(typeof SlashCommandEnumAutoCompleteOption)}[]} */
|
||||
@@ -18,7 +18,6 @@ export class SlashCommandEnumAutoCompleteOption extends AutoCompleteOption {
|
||||
/**@type {SlashCommandEnumValue}*/ enumValue;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {SlashCommand} cmd
|
||||
* @param {SlashCommandEnumValue} enumValue
|
||||
|
||||
@@ -48,7 +48,6 @@ export class SlashCommandExecutionError extends Error {
|
||||
}
|
||||
|
||||
|
||||
|
||||
constructor(cause, message, commandName, start, end, commandText, fullText) {
|
||||
super(message, { cause });
|
||||
this.commandName = commandName;
|
||||
|
||||
@@ -17,10 +17,10 @@ export class SlashCommandExecutor {
|
||||
get source() { return this.#source; }
|
||||
set source(value) {
|
||||
this.#source = value;
|
||||
for (const arg of this.namedArgumentList.filter(it=>it.value instanceof SlashCommandClosure)) {
|
||||
for (const arg of this.namedArgumentList.filter(it => it.value instanceof SlashCommandClosure)) {
|
||||
arg.value.source = value;
|
||||
}
|
||||
for (const arg of this.unnamedArgumentList.filter(it=>it.value instanceof SlashCommandClosure)) {
|
||||
for (const arg of this.unnamedArgumentList.filter(it => it.value instanceof SlashCommandClosure)) {
|
||||
arg.value.source = value;
|
||||
}
|
||||
}
|
||||
@@ -31,15 +31,15 @@ export class SlashCommandExecutor {
|
||||
|
||||
get commandCount() {
|
||||
return 1
|
||||
+ this.namedArgumentList.filter(it=>it.value instanceof SlashCommandClosure).map(it=>/**@type {SlashCommandClosure}*/(it.value).commandCount).reduce((cur, sum)=>cur + sum, 0)
|
||||
+ this.unnamedArgumentList.filter(it=>it.value instanceof SlashCommandClosure).map(it=>/**@type {SlashCommandClosure}*/(it.value).commandCount).reduce((cur, sum)=>cur + sum, 0)
|
||||
+ this.namedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it =>/**@type {SlashCommandClosure}*/(it.value).commandCount).reduce((cur, sum) => cur + sum, 0)
|
||||
+ this.unnamedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it =>/**@type {SlashCommandClosure}*/(it.value).commandCount).reduce((cur, sum) => cur + sum, 0)
|
||||
;
|
||||
}
|
||||
|
||||
set onProgress(value) {
|
||||
const closures = /**@type {SlashCommandClosure[]}*/([
|
||||
...this.namedArgumentList.filter(it=>it.value instanceof SlashCommandClosure).map(it=>it.value),
|
||||
...this.unnamedArgumentList.filter(it=>it.value instanceof SlashCommandClosure).map(it=>it.value),
|
||||
...this.namedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it => it.value),
|
||||
...this.unnamedArgumentList.filter(it => it.value instanceof SlashCommandClosure).map(it => it.value),
|
||||
]);
|
||||
for (const closure of closures) {
|
||||
closure.onProgress = value;
|
||||
|
||||
@@ -65,7 +65,7 @@ export class SlashCommandParser {
|
||||
static addCommandObject(command) {
|
||||
const reserved = ['/', '#', ':', 'parser-flag', 'breakpoint'];
|
||||
for (const start of reserved) {
|
||||
if (command.name.toLowerCase().startsWith(start) || (command.aliases ?? []).find(a=>a.toLowerCase().startsWith(start))) {
|
||||
if (command.name.toLowerCase().startsWith(start) || (command.aliases ?? []).find(a => a.toLowerCase().startsWith(start))) {
|
||||
throw new Error(`Illegal Name. Slash command name cannot begin with "${start}".`);
|
||||
}
|
||||
}
|
||||
@@ -80,15 +80,15 @@ export class SlashCommandParser {
|
||||
console.trace('WARN: Duplicate slash command registered!', [command.name, ...command.aliases]);
|
||||
}
|
||||
|
||||
const stack = new Error().stack.split('\n').map(it=>it.trim());
|
||||
command.isExtension = stack.find(it=>it.includes('/scripts/extensions/')) != null;
|
||||
command.isThirdParty = stack.find(it=>it.includes('/scripts/extensions/third-party/')) != null;
|
||||
const stack = new Error().stack.split('\n').map(it => it.trim());
|
||||
command.isExtension = stack.find(it => it.includes('/scripts/extensions/')) != null;
|
||||
command.isThirdParty = stack.find(it => it.includes('/scripts/extensions/third-party/')) != null;
|
||||
if (command.isThirdParty) {
|
||||
command.source = stack.find(it=>it.includes('/scripts/extensions/third-party/')).replace(/^.*?\/scripts\/extensions\/third-party\/([^/]+)\/.*$/, '$1');
|
||||
command.source = stack.find(it => it.includes('/scripts/extensions/third-party/')).replace(/^.*?\/scripts\/extensions\/third-party\/([^/]+)\/.*$/, '$1');
|
||||
} else if (command.isExtension) {
|
||||
command.source = stack.find(it=>it.includes('/scripts/extensions/')).replace(/^.*?\/scripts\/extensions\/([^/]+)\/.*$/, '$1');
|
||||
command.source = stack.find(it => it.includes('/scripts/extensions/')).replace(/^.*?\/scripts\/extensions\/([^/]+)\/.*$/, '$1');
|
||||
} else {
|
||||
const idx = stack.findLastIndex(it=>it.includes('at SlashCommandParser.')) + 1;
|
||||
const idx = stack.findLastIndex(it => it.includes('at SlashCommandParser.')) + 1;
|
||||
command.source = stack[idx].replace(/^.*?\/((?:scripts\/)?(?:[^/]+)\.js).*$/, '$1');
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ export class SlashCommandParser {
|
||||
description: 'The parser flag to modify.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumList: Object.keys(PARSER_FLAG).map(flag=>new SlashCommandEnumValue(flag, help[PARSER_FLAG[flag]])),
|
||||
enumList: Object.keys(PARSER_FLAG).map(flag => new SlashCommandEnumValue(flag, help[PARSER_FLAG[flag]])),
|
||||
}),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'The state of the parser flag to set.',
|
||||
@@ -439,7 +439,7 @@ export class SlashCommandParser {
|
||||
PIPEBREAK,
|
||||
PIPE,
|
||||
);
|
||||
hljs.registerLanguage('stscript', ()=>({
|
||||
hljs.registerLanguage('stscript', () => ({
|
||||
case_insensitive: false,
|
||||
keywords: [],
|
||||
contains: [
|
||||
@@ -480,19 +480,19 @@ export class SlashCommandParser {
|
||||
}
|
||||
}
|
||||
const executor = this.commandIndex
|
||||
.filter(it=>it.start <= index && (it.end >= index || it.end == null))
|
||||
.filter(it => it.start <= index && (it.end >= index || it.end == null))
|
||||
.slice(-1)[0]
|
||||
?? null
|
||||
;
|
||||
|
||||
if (executor) {
|
||||
const childClosure = this.closureIndex
|
||||
.find(it=>it.start <= index && (it.end >= index || it.end == null) && it.start > executor.start)
|
||||
.find(it => it.start <= index && (it.end >= index || it.end == null) && it.start > executor.start)
|
||||
?? null
|
||||
;
|
||||
if (childClosure !== null) return null;
|
||||
// Check if cursor is inside a macro
|
||||
const macroEntry = this.macroIndex.findLast(it=>it.start <= index && it.end >= index);
|
||||
const macroEntry = this.macroIndex.findLast(it => it.start <= index && it.end >= index);
|
||||
if (macroEntry) {
|
||||
// Build macro info object for shared function
|
||||
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 {
|
||||
if (executor.name == ':') {
|
||||
const options = this.scopeIndex[this.commandIndex.indexOf(executor)]
|
||||
?.allVariableNames
|
||||
?.map(it=>new SlashCommandVariableAutoCompleteOption(it))
|
||||
?.map(it => new SlashCommandVariableAutoCompleteOption(it))
|
||||
?? []
|
||||
;
|
||||
try {
|
||||
if ('quickReplyApi' in globalThis) {
|
||||
const qrApi = globalThis.quickReplyApi;
|
||||
options.push(...qrApi.listSets()
|
||||
.map(set=>qrApi.listQuickReplies(set).map(qr=>`${set}.${qr}`))
|
||||
.map(set => qrApi.listQuickReplies(set).map(qr => `${set}.${qr}`))
|
||||
.flat()
|
||||
.map(qr=>new SlashCommandQuickReplyAutoCompleteOption(qr)),
|
||||
.map(qr => new SlashCommandQuickReplyAutoCompleteOption(qr)),
|
||||
);
|
||||
}
|
||||
} catch { /* empty */ }
|
||||
@@ -540,8 +540,8 @@ export class SlashCommandParser {
|
||||
executor.start,
|
||||
options,
|
||||
true,
|
||||
()=>`No matching variables in scope and no matching Quick Replies for "${result.name}"`,
|
||||
()=>'No variables in scope and no Quick Replies found.',
|
||||
() => `No matching variables in scope and no matching Quick Replies for "${result.name}"`,
|
||||
() => 'No variables in scope and no Quick Replies found.',
|
||||
);
|
||||
return result;
|
||||
}
|
||||
@@ -741,7 +741,7 @@ export class SlashCommandParser {
|
||||
return this.testSymbol(':}');
|
||||
}
|
||||
parseClosure(isRoot = false) {
|
||||
const closureIndexEntry = { start:this.index + 1, end:null };
|
||||
const closureIndexEntry = { start: this.index + 1, end: null };
|
||||
this.closureIndex.push(closureIndexEntry);
|
||||
let injectPipe = true;
|
||||
if (!isRoot) this.take(2); // discard opening {:
|
||||
@@ -1023,14 +1023,14 @@ export class SlashCommandParser {
|
||||
cmd.unnamedArgumentList = this.parseUnnamedArgument(cmd.command?.unnamedArgumentList?.length && cmd?.command?.splitUnnamedArgument, cmd?.command?.splitUnnamedArgumentCount, rawQuotes);
|
||||
cmd.endUnnamedArgs = this.index;
|
||||
if (cmd.name == 'let') {
|
||||
const keyArg = cmd.namedArgumentList.find(it=>it.name == 'key');
|
||||
const keyArg = cmd.namedArgumentList.find(it => it.name == 'key');
|
||||
if (keyArg) {
|
||||
this.scope.variableNames.push(keyArg.value.toString());
|
||||
} else if (typeof cmd.unnamedArgumentList[0]?.value == 'string') {
|
||||
this.scope.variableNames.push(cmd.unnamedArgumentList[0].value);
|
||||
}
|
||||
} else if (cmd.name == 'import') {
|
||||
const value = /**@type {string[]}*/(cmd.unnamedArgumentList.map(it=>it.value));
|
||||
const value = /**@type {string[]}*/(cmd.unnamedArgumentList.map(it => it.value));
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const srcName = value[i];
|
||||
let dstName = srcName;
|
||||
|
||||
@@ -5,7 +5,7 @@ export class SlashCommandScope {
|
||||
/** @type {string[]} */ variableNames = [];
|
||||
get allVariableNames() {
|
||||
const names = [...this.variableNames, ...(this.parent?.allVariableNames ?? [])];
|
||||
return names.filter((it,idx)=>idx == names.indexOf(it));
|
||||
return names.filter((it, idx) => idx == names.indexOf(it));
|
||||
}
|
||||
// @ts-ignore
|
||||
/** @type {object.<string, string|SlashCommandClosure>} */ variables = {};
|
||||
@@ -13,7 +13,7 @@ export class SlashCommandScope {
|
||||
/** @type {object.<string, string|SlashCommandClosure>} */ macros = {};
|
||||
/** @type {{key:string, value:string|SlashCommandClosure}[]} */
|
||||
get macroList() {
|
||||
return [...Object.keys(this.macros).map(key=>({ key, value:this.macros[key] })), ...(this.parent?.macroList ?? [])];
|
||||
return [...Object.keys(this.macros).map(key => ({ key, value: this.macros[key] })), ...(this.parent?.macroList ?? [])];
|
||||
}
|
||||
/** @type {SlashCommandScope} */ parent;
|
||||
/** @type {string} */ #pipe;
|
||||
@@ -40,7 +40,7 @@ export class SlashCommandScope {
|
||||
|
||||
|
||||
setMacro(key, value, overwrite = true) {
|
||||
if (overwrite || !this.macroList.find(it=>it.key == key)) {
|
||||
if (overwrite || !this.macroList.find(it => it.key == key)) {
|
||||
this.macros[key] = value;
|
||||
}
|
||||
}
|
||||
@@ -109,8 +109,6 @@ export class SlashCommandScope {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export class SlashCommandScopeVariableExistsError extends Error {}
|
||||
|
||||
|
||||
|
||||
@@ -2091,7 +2091,6 @@ function onTagAsFolderClick() {
|
||||
// If folder display has changed, we have to redraw the character list, otherwise this folders state would not change
|
||||
printCharactersDebounced();
|
||||
saveSettingsDebounced();
|
||||
|
||||
}
|
||||
|
||||
function updateDrawTagFolder(element, tag) {
|
||||
|
||||
@@ -802,7 +802,6 @@ async function getStatusTextgen() {
|
||||
console.info('Status check aborted.', err.reason);
|
||||
} else {
|
||||
console.error('Error getting status', err);
|
||||
|
||||
}
|
||||
setOnlineStatus('no_connection');
|
||||
}
|
||||
@@ -1126,7 +1125,7 @@ export function initTextGenSettings() {
|
||||
* @returns void
|
||||
*/
|
||||
function showSamplerControls(apiType = null) {
|
||||
$('#textgenerationwebui_api-settings [data-tg-samplers], #textgenerationwebui_api [data-tg-samplers]').each(function(idx, elem) {
|
||||
$('#textgenerationwebui_api-settings [data-tg-samplers], #textgenerationwebui_api [data-tg-samplers]').each(function (idx, elem) {
|
||||
const typeSpecificControlled = $(elem).data('tg-type') !== undefined;
|
||||
|
||||
if (!typeSpecificControlled) $(this).show();
|
||||
@@ -1139,7 +1138,7 @@ function showSamplerControls(apiType = null) {
|
||||
|
||||
if (!samplersActivatedManually?.length || !prioritizeManualSamplerSelect) return;
|
||||
|
||||
$('#textgenerationwebui_api-settings [data-tg-samplers], #textgenerationwebui_api [data-tg-samplers]').each(function() {
|
||||
$('#textgenerationwebui_api-settings [data-tg-samplers], #textgenerationwebui_api [data-tg-samplers]').each(function () {
|
||||
const tgSamplers = $(this).attr('data-tg-samplers').split(',').map(x => x.trim()).filter(str => str !== '');
|
||||
|
||||
for (const tgSampler of tgSamplers) {
|
||||
|
||||
@@ -455,7 +455,6 @@ async function changeName(handle, name, callback) {
|
||||
|
||||
toastr.success('Name changed successfully', 'Name Changed');
|
||||
callback();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error changing name:', error);
|
||||
}
|
||||
@@ -495,7 +494,6 @@ async function restoreSnapshot(name, callback) {
|
||||
} catch (error) {
|
||||
console.error('Error restoring snapshot:', error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -601,7 +599,6 @@ async function viewSettingsSnapshots() {
|
||||
const content = await loadSnapshotContent(snapshot.name);
|
||||
contentBlock.val(content);
|
||||
}
|
||||
|
||||
});
|
||||
template.find('.snapshotList').append(snapshotBlock);
|
||||
}
|
||||
@@ -667,7 +664,6 @@ async function resetEverything(callback) {
|
||||
} catch (error) {
|
||||
console.error('Error resetting everything:', error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function openUserProfile() {
|
||||
|
||||
@@ -2310,7 +2310,6 @@ export function highlightRegex(regexStr) {
|
||||
flags: new RegExp('(?<=\\/)([gimsuy]*)$', 'g'), // Match trailing flags
|
||||
delimiters: new RegExp('^\\/|(?<![\\\\<])\\/', 'g'), // Match leading or trailing delimiters
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
brackets: new RegExp('(\\\\)?\\[.*?\\]', 'g'), // Non-escaped square brackets
|
||||
|
||||
@@ -675,7 +675,6 @@ class WorldInfoTimedEffects {
|
||||
console.log('[WI] Timed effect "delay" applied to entry', entry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4495,7 +4494,6 @@ function parseDecorators(content) {
|
||||
}
|
||||
|
||||
return [[], content];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,7 +111,6 @@ router.post('/get', async (request, response) => {
|
||||
|
||||
try {
|
||||
if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
|
||||
|
||||
ensureFoldersExist(request.user.directories);
|
||||
|
||||
const folders = fs.readdirSync(folderPath, { withFileTypes: true })
|
||||
@@ -346,7 +345,6 @@ router.post('/character', async (request, response) => {
|
||||
let output = [];
|
||||
try {
|
||||
if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
|
||||
|
||||
// Live2d assets
|
||||
if (category == 'live2d') {
|
||||
const folders = fs.readdirSync(folderPath, { withFileTypes: true });
|
||||
|
||||
@@ -541,7 +541,6 @@ llamacpp.post('/props', async function (request, response) {
|
||||
console.debug('LlamaCpp props response:', data);
|
||||
|
||||
return response.send(data);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response.sendStatus(500);
|
||||
@@ -591,7 +590,6 @@ llamacpp.post('/slots', async function (request, response) {
|
||||
console.debug('LlamaCpp slots response:', data);
|
||||
|
||||
return response.send(data);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response.sendStatus(500);
|
||||
|
||||
@@ -11,7 +11,7 @@ router.post('/chat/get', async (request, response) => {
|
||||
const backupModels = [];
|
||||
const backupFiles = await fsPromises
|
||||
.readdir(request.user.directories.backups, { withFileTypes: true })
|
||||
.then(d => d .filter(d => d.isFile() && path.extname(d.name) === '.jsonl' && d.name.startsWith(CHAT_BACKUPS_PREFIX)).map(d => d.name));
|
||||
.then(d => d.filter(d => d.isFile() && path.extname(d.name) === '.jsonl' && d.name.startsWith(CHAT_BACKUPS_PREFIX)).map(d => d.name));
|
||||
|
||||
for (const name of backupFiles) {
|
||||
const filePath = path.join(request.user.directories.backups, name);
|
||||
|
||||
@@ -639,7 +639,6 @@ function charaFormatData(data, directories) {
|
||||
if (file && file.entries) {
|
||||
_.set(char, 'data.character_book', convertWorldInfoToCharacterBook(data.world, file.entries));
|
||||
}
|
||||
|
||||
} catch {
|
||||
console.warn(`Failed to read world info file: ${data.world}. Character book will not be available.`);
|
||||
}
|
||||
@@ -921,7 +920,8 @@ async function importFromJson(uploadPath, { request }, preservedFileName) {
|
||||
let charJSON = JSON.stringify(char);
|
||||
const result = await writeCharacterData(DEFAULT_AVATAR_PATH, charJSON, pngName, request);
|
||||
return result ? pngName : '';
|
||||
} else if (jsonData.char_name !== undefined) {//json Pygmalion notepad
|
||||
} else if (jsonData.char_name !== undefined) {
|
||||
//json Pygmalion notepad
|
||||
console.info('Importing from gradio json');
|
||||
jsonData.char_name = sanitize(jsonData.char_name);
|
||||
if (jsonData.creator_notes) {
|
||||
|
||||
@@ -367,7 +367,6 @@ router.post('/version', async (request, response) => {
|
||||
const { isUpToDate, remoteUrl } = await checkIfRepoIsUpToDate(extensionPath);
|
||||
|
||||
return response.send({ currentBranchName, currentCommitHash, isUpToDate, remoteUrl });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Getting extension version failed', error);
|
||||
return response.status(500).send(`Server Error: ${error.message}`);
|
||||
@@ -406,7 +405,6 @@ router.post('/delete', async (request, response) => {
|
||||
console.info(`Extension has been deleted at ${extensionPath}`);
|
||||
|
||||
return response.send(`Extension has been deleted at ${extensionPath}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Deleting custom content failed', error);
|
||||
return response.status(500).send(`Server Error: ${error.message}`);
|
||||
|
||||
@@ -51,7 +51,7 @@ export async function migrateGroupChatsMetadataFormat(userDirectories) {
|
||||
if (!needsMigration) {
|
||||
continue;
|
||||
}
|
||||
if (!fs.existsSync(backupPath)){
|
||||
if (!fs.existsSync(backupPath)) {
|
||||
await fsPromises.mkdir(backupPath, { recursive: true });
|
||||
}
|
||||
await fsPromises.copyFile(groupFilePath, path.join(backupPath, groupFile.name));
|
||||
|
||||
@@ -256,7 +256,6 @@ router.post('/caption-image', async (request, response) => {
|
||||
console.info(status);
|
||||
|
||||
if (status.state === HordeAsyncRequestStates.done) {
|
||||
|
||||
if (status.forms === undefined) {
|
||||
console.error('Image interrogation request failed: no forms found.');
|
||||
return response.sendStatus(500);
|
||||
@@ -278,7 +277,6 @@ router.post('/caption-image', async (request, response) => {
|
||||
return response.sendStatus(503);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
response.sendStatus(500);
|
||||
|
||||
@@ -442,7 +442,6 @@ router.post('/', async function (request, response) {
|
||||
}
|
||||
|
||||
return response.status(400).json({ error: 'Invalid request format.' });
|
||||
|
||||
} catch (error) {
|
||||
console.error('[ImageMetadata] API error:', error);
|
||||
return response.status(500).json({ error: 'Internal server error.' });
|
||||
|
||||
@@ -189,7 +189,6 @@ router.post('/generate-voice', async (request, response) => {
|
||||
response.setHeader('Content-Length', audioBytes.length);
|
||||
|
||||
return response.send(Buffer.from(audioBytes));
|
||||
|
||||
} catch (conversionError) {
|
||||
console.error('MiniMax TTS: Audio conversion error:', conversionError);
|
||||
return response.status(500).json({ error: `Audio data conversion failed: ${conversionError.message}` });
|
||||
@@ -222,7 +221,6 @@ router.post('/generate-voice', async (request, response) => {
|
||||
console.error('MiniMax TTS: No valid audio data in response:', responseData);
|
||||
return response.status(500).json({ error: `API Error: ${errorMessage}` });
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('MiniMax TTS generation failed:', error);
|
||||
return response.status(500).json({ error: 'Internal server error' });
|
||||
|
||||
@@ -158,7 +158,6 @@ router.post('/samplers', async (request, response) => {
|
||||
const data = await result.json();
|
||||
const names = data.map(x => x.name);
|
||||
return response.send(names);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response.sendStatus(500);
|
||||
|
||||
@@ -301,7 +301,6 @@ publicRouter.get('/', async function (request, response) {
|
||||
|
||||
// Send a 404 so the frontend can display a placeholder
|
||||
return response.sendStatus(404);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed getting thumbnail', error);
|
||||
return response.sendStatus(500);
|
||||
|
||||
@@ -118,7 +118,6 @@ export function postProcessPrompt(messages, type, names) {
|
||||
* @copyright Prompt Conversion script taken from RisuAI by kwaroran (GPLv3).
|
||||
*/
|
||||
export function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, withSysPromptSupport, useSystemPrompt, addSysHumanMsg, excludePrefixes) {
|
||||
|
||||
//Prepare messages for claude.
|
||||
//When 'Exclude Human/Assistant prefixes' checked, setting messages role to the 'system'(last message is exception).
|
||||
if (messages.length > 0) {
|
||||
@@ -1278,7 +1277,7 @@ export function calculateGoogleBudgetTokens(maxTokens, reasoningEffort, model) {
|
||||
return getGemini3ProBudget();
|
||||
}
|
||||
|
||||
if (/gemini-3-flash/.test(model) ) {
|
||||
if (/gemini-3-flash/.test(model)) {
|
||||
return getGemini3FlashBudget();
|
||||
}
|
||||
|
||||
|
||||
@@ -1012,7 +1012,6 @@ export async function canResolve(name, useIPv6 = true, useIPv4 = true) {
|
||||
}
|
||||
|
||||
return v6Resolved || v4Resolved;
|
||||
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user