From 3a9c10d68053cf86989224554a67627affa23197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leandro=20Jofr=C3=A9?= Date: Thu, 30 Apr 2026 17:41:04 -0300 Subject: [PATCH] Feat - Add expression-set-fallback slash command (#5551) * Feat - Add expression-set-fallback slash command * Fix ESLint * Fix - Use proper name convention for slash command method * Fix - Change misleading expression-set-fallback help string label * Fix - Use normal description for expression label argument * Update - Make expression-set-fallback case unsensitive Also fixed array creation by removing the spread syntax and added warning. --- .../scripts/extensions/expressions/index.js | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index 042d41dfa..70bf300f3 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -4,7 +4,7 @@ import { characters, eventSource, event_types, generateQuietPrompt, generateRaw, import { dragElement, isMobile } from '../../RossAscends-mods.js'; import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js'; -import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar, isFalseBoolean } from '../../utils.js'; +import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar, isFalseBoolean, includesIgnoreCaseAndAccents } from '../../utils.js'; import { hideMutedSprites, selected_group } from '../../group-chats.js'; import { isJsonSchemaSupported } from '../../textgen-settings.js'; import { debounce_timeout } from '../../constants.js'; @@ -786,6 +786,30 @@ async function setSpriteSlashCommand({ type }, searchTerm) { return label; } +/** + * @param {string} expressionName - Label of the expression to set as fallback + */ +function setFallBackExpressionSlashCommand(args, expressionName) { + expressionName = expressionName.trim().toLowerCase(); + + const select = /** @type {HTMLSelectElement} */(document.getElementById('expression_fallback')); + const fallbackExpressions = Array + .from(select?.options || []) + .map(option => option.value) + .filter(expression => expression?.length > 0); + + const expressionMatch = fallbackExpressions.find(expression => includesIgnoreCaseAndAccents(expression, expressionName)); + + if (!expressionMatch) { + toastr.warning(t`No expression found for search term ${expressionName}`, t`Set Fallback Expression`); + return ''; + } + + $(select).val(expressionMatch).trigger('change'); + + return expressionMatch; +} + /** * Returns the sprite folder name (including override) for a character. * @param {object} char Character object @@ -2316,6 +2340,24 @@ export async function init() { helpString: 'Force sets the expression for the current character.', returns: 'The currently set expression label after setting it.', })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'expression-set-fallback', + callback: setFallBackExpressionSlashCommand, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'expression label to set', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => [ + new SlashCommandEnumValue('#none', 'Sets the fallback expression to no image'), + new SlashCommandEnumValue('#emoji', 'Sets the fallback expression to emojis'), + ...localEnumProviders.expressions(), + ], + }), + ], + helpString: 'Force sets the expression fallback for all characters.', + returns: 'The currently set expression label after setting it.', + })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'expression-folder-override', aliases: ['spriteoverride', 'costume'],