Merge pull request #2798 from SillyTavern/popup-command-styles Expand `/popup` command and refactor a bit
Signed| @@ -92,7 +92,7 @@ const showPopupHelper = { | |||
| 92 | * @param {string?} header - The header text for the popup. | 92 | * @param {string?} header - The header text for the popup. |
| 93 | * @param {string?} text - The main text for the popup. | 93 | * @param {string?} text - The main text for the popup. |
| 94 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. | 94 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. |
| 95 | * @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction. | 95 | * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction. |
| 96 | */ | 96 | */ |
| 97 | confirm: async (header, text, popupOptions = {}) => { | 97 | confirm: async (header, text, popupOptions = {}) => { |
| 98 | const content = PopupUtils.BuildTextWithHeader(header, text); | 98 | const content = PopupUtils.BuildTextWithHeader(header, text); |
| @@ -107,7 +107,7 @@ const showPopupHelper = { | |||
| 107 | * @param {string?} header - The header text for the popup. | 107 | * @param {string?} header - The header text for the popup. |
| 108 | * @param {string?} text - The main text for the popup. | 108 | * @param {string?} text - The main text for the popup. |
| 109 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. | 109 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. |
| 110 | * @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction. | 110 | * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction. |
| 111 | */ | 111 | */ |
| 112 | text: async (header, text, popupOptions = {}) => { | 112 | text: async (header, text, popupOptions = {}) => { |
| 113 | const content = PopupUtils.BuildTextWithHeader(header, text); | 113 | const content = PopupUtils.BuildTextWithHeader(header, text); |
| @@ -1267,20 +1267,59 @@ export function initDefaultSlashCommands() { | |||
| 1267 | callback: popupCallback, | 1267 | callback: popupCallback, |
| 1268 | returns: 'popup text', | 1268 | returns: 'popup text', |
| 1269 | namedArgumentList: [ | 1269 | namedArgumentList: [ |
| 1270 | new SlashCommandNamedArgument( | 1270 | SlashCommandNamedArgument.fromProps({ |
| 1271 | 'large', 'show large popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(), | 1271 | name: 'large', |
| 1272 | ), | 1272 | description: 'show large popup', |
| 1273 | new SlashCommandNamedArgument( | 1273 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1274 | 'wide', 'show wide popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(), | 1274 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1275 | ), | 1275 | defaultValue: 'false', |
| 1276 | new SlashCommandNamedArgument( | 1276 | }), |
| 1277 | 'okButton', 'text for the OK button', [ARGUMENT_TYPE.STRING], false, | 1277 | SlashCommandNamedArgument.fromProps({ |
| 1278 | ), | 1278 | name: 'wide', |
| 1279 | description: 'show wide popup', | ||
| 1280 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1281 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1282 | defaultValue: 'false', | ||
| 1283 | }), | ||
| 1284 | SlashCommandNamedArgument.fromProps({ | ||
| 1285 | name: 'wider', | ||
| 1286 | description: 'show wider popup', | ||
| 1287 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1288 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1289 | defaultValue: 'false', | ||
| 1290 | }), | ||
| 1291 | SlashCommandNamedArgument.fromProps({ | ||
| 1292 | name: 'transparent', | ||
| 1293 | description: 'show transparent popup', | ||
| 1294 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1295 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1296 | defaultValue: 'false', | ||
| 1297 | }), | ||
| 1298 | SlashCommandNamedArgument.fromProps({ | ||
| 1299 | name: 'okButton', | ||
| 1300 | description: 'text for the OK button', | ||
| 1301 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 1302 | defaultValue: 'OK', | ||
| 1303 | }), | ||
| 1304 | SlashCommandNamedArgument.fromProps({ | ||
| 1305 | name: 'cancelButton', | ||
| 1306 | description: 'text for the Cancel button', | ||
| 1307 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 1308 | }), | ||
| 1309 | SlashCommandNamedArgument.fromProps({ | ||
| 1310 | name: 'result', | ||
| 1311 | description: 'if enabled, returns the popup result (as an integer) instead of the popup text. Resolves to 1 for OK and 0 cancel button, empty string for exiting out.', | ||
| 1312 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1313 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1314 | defaultValue: 'false', | ||
| 1315 | }), | ||
| 1279 | ], | 1316 | ], |
| 1280 | unnamedArgumentList: [ | 1317 | unnamedArgumentList: [ |
| 1281 | new SlashCommandArgument( | 1318 | SlashCommandArgument.fromProps({ |
| 1282 | 'text', [ARGUMENT_TYPE.STRING], true, | 1319 | description: 'popup text', |
| 1283 | ), | 1320 | typeList: [ARGUMENT_TYPE.STRING], |
| 1321 | isRequired: true, | ||
| 1322 | }), | ||
| 1284 | ], | 1323 | ], |
| 1285 | helpString: ` | 1324 | helpString: ` |
| 1286 | <div> | 1325 | <div> |
| @@ -1291,7 +1330,10 @@ export function initDefaultSlashCommands() { | |||
| 1291 | <strong>Example:</strong> | 1330 | <strong>Example:</strong> |
| 1292 | <ul> | 1331 | <ul> |
| 1293 | <li> | 1332 | <li> |
| 1294 | <pre><code>/popup large=on wide=on okButton="Submit" Enter some text:</code></pre> | 1333 | <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre> |
| 1334 | </li> | ||
| 1335 | <li> | ||
| 1336 | <pre><code>/popup okButton="Left" cancelButton="Right" result=true Do you want to go left or right? | /echo 0 means right, 1 means left. Choice: {{pipe}}</code></pre> | ||
| 1295 | </li> | 1337 | </li> |
| 1296 | </ul> | 1338 | </ul> |
| 1297 | </div> | 1339 | </div> |
| @@ -1882,16 +1924,21 @@ async function buttonsCallback(args, text) { | |||
| 1882 | } | 1924 | } |
| 1883 | 1925 | ||
| 1884 | async function popupCallback(args, value) { | 1926 | async function popupCallback(args, value) { |
| 1885 | const safeValue = DOMPurify.sanitize(value || ''); | 1927 | const safeBody = DOMPurify.sanitize(value || ''); |
| 1928 | const safeHeader = args?.header && typeof args?.header === 'string' ? DOMPurify.sanitize(args.header) : null; | ||
| 1929 | const requestedResult = isTrueBoolean(args?.result); | ||
| 1930 | |||
| 1931 | /** @type {import('./popup.js').PopupOptions} */ | ||
| 1886 | const popupOptions = { | 1932 | const popupOptions = { |
| 1887 | large: isTrueBoolean(args?.large), | 1933 | large: isTrueBoolean(args?.large), |
| 1888 | wide: isTrueBoolean(args?.wide), | 1934 | wide: isTrueBoolean(args?.wide), |
| 1935 | wider: isTrueBoolean(args?.wider), | ||
| 1936 | transparent: isTrueBoolean(args?.transparent), | ||
| 1889 | okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok', | 1937 | okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok', |
| 1938 | cancelButton: args?.cancelButton !== undefined && typeof args?.cancelButton === 'string' ? args.cancelButton : null, | ||
| 1890 | }; | 1939 | }; |
| 1891 | await delay(1); | 1940 | const result = await Popup.show.text(safeHeader, safeBody, popupOptions); |
| 1892 | await callGenericPopup(safeValue, POPUP_TYPE.TEXT, '', popupOptions); | 1941 | return String(requestedResult ? result ?? '' : value); |
| 1893 | await delay(1); | ||
| 1894 | return String(value); | ||
| 1895 | } | 1942 | } |
| 1896 | 1943 | ||
| 1897 | async function getMessagesCallback(args, value) { | 1944 | async function getMessagesCallback(args, value) { |