Merge pull request #3651 from SillyTavern/input-handling-args Add `/input` arguments to execute closures on success and on cancel

64206d6f47a13c79b6f82e3bb796b742ed83a98c

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

Signed
1 files changed, +66 -19Ignore whitespace
public/scripts/slash-commands.js+66 -19
@@ -69,7 +69,7 @@ import { SlashCommand } from './slash-commands/SlashCommand.js';
6969import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js';
7070import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashCommandNamedArgumentAssignment.js';
7171import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
7272import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
7373import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
7474import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js';
7575import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js';
@@ -1287,26 +1287,52 @@ export function initDefaultSlashCommands() {
12871287 callback: inputCallback,
12881288 returns: 'user input',
12891289 namedArgumentList: [
12901290 new SlashCommandNamedArgument.fromProps({
1291- 'default', 'default value of the input field', [ARGUMENT_TYPE.STRING], false, false, '"string"',
1291+ name: 'default',
1292- ),
1292+ description: 'default value of the input field',
1293- new SlashCommandNamedArgument(
1293+ typeList: [ARGUMENT_TYPE.STRING],
1294- 'large', 'show large input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
1294+ }),
1295- ),
1295+ SlashCommandNamedArgument.fromProps({
1296- new SlashCommandNamedArgument(
1296+ name: 'large',
1297- 'wide', 'show wide input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
1297+ description: 'show large input field',
1298- ),
1298+ typeList: [ARGUMENT_TYPE.BOOLEAN],
1299- new SlashCommandNamedArgument(
1299+ defaultValue: 'off',
1300- 'okButton', 'text for the ok button', [ARGUMENT_TYPE.STRING], false,
1300+ enumList: commonEnumProviders.boolean('onOff')(),
13011301 }),
13021302 new SlashCommandNamedArgument.fromProps({
1303- 'rows', 'number of rows for the input field', [ARGUMENT_TYPE.NUMBER], false,
1303+ name: 'wide',
1304- ),
1304+ description: 'show wide input field',
1305+ typeList: [ARGUMENT_TYPE.BOOLEAN],
1306+ defaultValue: 'off',
1307+ enumList: commonEnumProviders.boolean('onOff')(),
1308+ }),
1309+ SlashCommandNamedArgument.fromProps({
1310+ name: 'okButton',
1311+ description: 'text for the ok button',
1312+ typeList: [ARGUMENT_TYPE.STRING],
1313+ defaultValue: 'Ok',
1314+ }),
1315+ SlashCommandNamedArgument.fromProps({
1316+ name: 'rows',
1317+ description: 'number of rows for the input field',
1318+ typeList: [ARGUMENT_TYPE.NUMBER],
1319+ }),
1320+ SlashCommandNamedArgument.fromProps({
1321+ name: 'onSuccess',
1322+ description: 'closure to execute when the ok button is clicked or the input is closed as successful (via Enter, etc)',
1323+ typeList: [ARGUMENT_TYPE.CLOSURE],
1324+ }),
1325+ SlashCommandNamedArgument.fromProps({
1326+ name: 'onCancel',
1327+ description: 'closure to execute when the cancel button is clicked or the input is closed as cancelled (via Escape, etc)',
1328+ typeList: [ARGUMENT_TYPE.CLOSURE],
1329+ }),
13051330 ],
13061331 unnamedArgumentList: [
13071332 new SlashCommandArgument.fromProps({
13081333 description: 'text to display', [ARGUMENT_TYPE.STRING], false,
1309- ),
1334+ typeList: [ARGUMENT_TYPE.STRING],
1335+ }),
13101336 ],
13111337 helpString: `
13121338 <div>
@@ -2546,6 +2572,7 @@ async function delayCallback(_, amount) {
25462572 return '';
25472573}
25482574
2575+
25492576async function inputCallback(args, prompt) {
25502577 const safeValue = DOMPurify.sanitize(prompt || '');
25512578 const defaultInput = args?.default !== undefined && typeof args?.default === 'string' ? args.default : '';
@@ -2559,6 +2586,26 @@ async function inputCallback(args, prompt) {
25592586 await delay(1);
25602587 const result = await callGenericPopup(safeValue, POPUP_TYPE.INPUT, defaultInput, popupOptions);
25612588 await delay(1);
2589+
2590+ // Input will return null on nothing entered, and false on cancel clicked
2591+ if (result === null || result === false) {
2592+ // Veryify if a cancel handler exists and it is valid
2593+ if (args?.onCancel) {
2594+ if (!(args.onCancel instanceof SlashCommandClosure)) {
2595+ throw new Error('argument \'onCancel\' must be a closure for command /input');
2596+ }
2597+ await args.onCancel.execute();
2598+ }
2599+ } else {
2600+ // Verify if an ok handler exists and it is valid
2601+ if (args?.onSuccess) {
2602+ if (!(args.onSuccess instanceof SlashCommandClosure)) {
2603+ throw new Error('argument \'onSuccess\' must be a closure for command /input');
2604+ }
2605+ await args.onSuccess.execute();
2606+ }
2607+ }
2608+
25622609 return String(result || '');
25632610}
25642611