| 1 | import { DOMPurify, showdown } from '../../lib.js'; |
| 2 | import { sendSystemMessage, system_message_types } from '../../script.js'; |
| 3 | import { callGenericPopup, POPUP_TYPE } from '../popup.js'; |
| 4 | import { escapeHtml } from '../utils.js'; |
| 5 | import { enumIcons } from './SlashCommandCommonEnumsProvider.js'; |
| 6 | import { enumTypes, SlashCommandEnumValue } from './SlashCommandEnumValue.js'; |
| 7 | |
| 8 | /** @typedef {'pipe'|'object'|'chat-html'|'chat-text'|'popup-html'|'popup-text'|'toast-html'|'toast-text'|'console'|'none'} SlashCommandReturnType */ |
| 9 | |
| 10 | export const slashCommandReturnHelper = { |
| 11 | // Without this, VSCode formatter fucks up JS docs. Don't ask me why. |
| 12 | _: false, |
| 13 | |
| 14 | /** |
| 15 | * Gets/creates the enum list of types of return relevant for a slash command |
| 16 | * |
| 17 | * @param {object} [options={}] Options |
| 18 | * @param {boolean} [options.allowPipe=true] Allow option to pipe the return value |
| 19 | * @param {boolean} [options.allowObject=false] Allow option to return the value as an object |
| 20 | * @param {boolean} [options.allowChat=false] Allow option to return the value as a chat message |
| 21 | * @param {boolean} [options.allowPopup=false] Allow option to return the value as a popup |
| 22 | * @param {boolean}[options.allowTextVersion=true] Used in combination with chat/popup/toast, some of them do not make sense for text versions, e.g.if you are building a HTML string anyway |
| 23 | * @returns {SlashCommandEnumValue[]} The enum list |
| 24 | */ |
| 25 | enumList: ({ allowPipe = true, allowObject = false, allowChat = false, allowPopup = false, allowTextVersion = true } = {}) => [ |
| 26 | allowPipe && new SlashCommandEnumValue('pipe', 'Return to the pipe for the next command', enumTypes.name, '|'), |
| 27 | allowObject && new SlashCommandEnumValue('object', 'Return as an object (or array) to the pipe for the next command', enumTypes.variable, enumIcons.dictionary), |
| 28 | allowChat && new SlashCommandEnumValue('chat-html', 'Sending a chat message with the return value - Can display HTML', enumTypes.command, enumIcons.message), |
| 29 | allowChat && allowTextVersion && new SlashCommandEnumValue('chat-text', 'Sending a chat message with the return value - Will only display as text', enumTypes.qr, enumIcons.message), |
| 30 | allowPopup && new SlashCommandEnumValue('popup-html', 'Showing as a popup with the return value - Can display HTML', enumTypes.command, enumIcons.popup), |
| 31 | allowPopup && allowTextVersion && new SlashCommandEnumValue('popup-text', 'Showing as a popup with the return value - Will only display as text', enumTypes.qr, enumIcons.popup), |
| 32 | new SlashCommandEnumValue('toast-html', 'Show the return value as a toast notification - Can display HTML', enumTypes.command, 'ℹ️'), |
| 33 | allowTextVersion && new SlashCommandEnumValue('toast-text', 'Show the return value as a toast notification - Will only display as text', enumTypes.qr, 'ℹ️'), |
| 34 | new SlashCommandEnumValue('console', 'Log the return value (object, if it can be one) to the console', enumTypes.enum, '>'), |
| 35 | new SlashCommandEnumValue('none', 'No return value'), |
| 36 | ].filter(x => !!x), |
| 37 | |
| 38 | /** |
| 39 | * Handles the return value based on the specified type |
| 40 | * |
| 41 | * @param {SlashCommandReturnType} type The type of return |
| 42 | * @param {object|number|string} value The value to return |
| 43 | * @param {object} [options={}] Options |
| 44 | * @param {(o: object) => string} [options.objectToStringFunc=null] Function to convert the object to a string, if object was provided and 'object' was not the chosen return type |
| 45 | * @param {(o: object) => string} [options.objectToHtmlFunc=null] Analog to 'objectToStringFunc', which will be used here if not provided - but can do a different string layout if HTML is requested |
| 46 | * @returns {Promise<*>} The processed return value |
| 47 | */ |
| 48 | async doReturn(type, value, { objectToStringFunc = o => o?.toString(), objectToHtmlFunc = null } = {}) { |
| 49 | const shouldHtml = type.endsWith('html'); |
| 50 | const actualConverterFunc = shouldHtml && objectToHtmlFunc ? objectToHtmlFunc : objectToStringFunc; |
| 51 | const stringValue = typeof value !== 'string' ? actualConverterFunc(value) : value; |
| 52 | |
| 53 | switch (type) { |
| 54 | case 'popup-html': |
| 55 | case 'popup-text': |
| 56 | case 'chat-text': |
| 57 | case 'chat-html': |
| 58 | case 'toast-text': |
| 59 | case 'toast-html': { |
| 60 | const htmlOrNotHtml = shouldHtml ? DOMPurify.sanitize((new showdown.Converter()).makeHtml(stringValue)) : escapeHtml(stringValue); |
| 61 | |
| 62 | if (type.startsWith('popup')) await callGenericPopup(htmlOrNotHtml, POPUP_TYPE.TEXT, '', { allowVerticalScrolling: true, wide: true }); |
| 63 | if (type.startsWith('chat')) sendSystemMessage(system_message_types.GENERIC, htmlOrNotHtml); |
| 64 | if (type.startsWith('toast')) toastr.info(htmlOrNotHtml, null, { escapeHtml: !shouldHtml }); |
| 65 | |
| 66 | return ''; |
| 67 | } |
| 68 | case 'pipe': |
| 69 | return stringValue ?? ''; |
| 70 | case 'object': |
| 71 | return JSON.stringify(value); |
| 72 | case 'console': |
| 73 | console.info(value); |
| 74 | return ''; |
| 75 | case 'none': |
| 76 | return ''; |
| 77 | default: |
| 78 | throw new Error(`Unknown return type: ${type}`); |
| 79 | } |
| 80 | }, |
| 81 | }; |