Refactor extension slash commands into own file - Weird circle imports again with the slash command classes
| @@ -244,6 +244,7 @@ import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCo | ||
| 244 | 244 | import { initInputMarkdown } from './scripts/input-md-formatting.js'; |
| 245 | 245 | import { AbortReason } from './scripts/util/AbortReason.js'; |
| 246 | 246 | import { initSystemPrompts } from './scripts/sysprompt.js'; |
| 247 | +import { registerExtensionSlashCommands } from './scripts/extensions-slashcommands.js'; | |
| 247 | 248 | |
| 248 | 249 | //exporting functions and vars for mods |
| 249 | 250 | export { |
| @@ -957,6 +958,7 @@ async function firstLoadInit() { | ||
| 957 | 958 | initLogprobs(); |
| 958 | 959 | initInputMarkdown(); |
| 959 | 960 | initExtensions(); |
| 961 | + registerExtensionSlashCommands(); | |
| 960 | 962 | doDailyExtensionUpdatesCheck(); |
| 961 | 963 | await hideLoader(); |
| 962 | 964 | await fixViewport(); |
| @@ -0,0 +1,276 @@ | ||
| 1 | +import { disableExtension, enableExtension, extension_settings, extensionNames } from './extensions.js'; | |
| 2 | +import { SlashCommand } from './slash-commands/SlashCommand.js'; | |
| 3 | +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; | |
| 4 | +import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; | |
| 5 | +import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | |
| 6 | +import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; | |
| 7 | +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | |
| 8 | +import { equalsIgnoreCaseAndAccents, isFalseBoolean, isTrueBoolean } from './utils.js'; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * @param {'enable' | 'disable' | 'toggle'} action - The action to perform on the extension | |
| 12 | + * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise<string>} | |
| 13 | + */ | |
| 14 | +function getExtensionActionCallback(action) { | |
| 15 | + return async (args, extensionName) => { | |
| 16 | + if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); | |
| 17 | + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 18 | + if (!extensionName) { | |
| 19 | + toastr.warning(`Extension name must be provided as an argument to ${action} this extension.`); | |
| 20 | + return ''; | |
| 21 | + } | |
| 22 | + | |
| 23 | + const reload = isTrueBoolean(args?.reload); | |
| 24 | + const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); | |
| 25 | + if (!internalExtensionName) { | |
| 26 | + toastr.warning(`Extension ${extensionName} does not exist.`); | |
| 27 | + return ''; | |
| 28 | + } | |
| 29 | + | |
| 30 | + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); | |
| 31 | + | |
| 32 | + if (action === 'enable' && isEnabled) { | |
| 33 | + toastr.info(`Extension ${extensionName} is already enabled.`); | |
| 34 | + return internalExtensionName; | |
| 35 | + } | |
| 36 | + | |
| 37 | + if (action === 'disable' && !isEnabled) { | |
| 38 | + toastr.info(`Extension ${extensionName} is already disabled.`); | |
| 39 | + return internalExtensionName; | |
| 40 | + } | |
| 41 | + | |
| 42 | + if (action === 'toggle') { | |
| 43 | + action = isEnabled ? 'disable' : 'enable'; | |
| 44 | + } | |
| 45 | + | |
| 46 | + reload && toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); | |
| 47 | + | |
| 48 | + if (action === 'enable') { | |
| 49 | + await enableExtension(internalExtensionName, reload); | |
| 50 | + } else { | |
| 51 | + await disableExtension(internalExtensionName, reload); | |
| 52 | + } | |
| 53 | + | |
| 54 | + toastr.success(`Extension ${extensionName} ${action}d.`); | |
| 55 | + | |
| 56 | + return internalExtensionName; | |
| 57 | + }; | |
| 58 | +} | |
| 59 | + | |
| 60 | +export function registerExtensionSlashCommands() { | |
| 61 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 62 | + name: 'extension-enable', | |
| 63 | + callback: getExtensionActionCallback('enable'), | |
| 64 | + namedArgumentList: [ | |
| 65 | + SlashCommandNamedArgument.fromProps({ | |
| 66 | + name: 'reload', | |
| 67 | + description: 'Whether to reload the page after enabling the extension', | |
| 68 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 69 | + defaultValue: 'true', | |
| 70 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 71 | + }), | |
| 72 | + ], | |
| 73 | + unnamedArgumentList: [ | |
| 74 | + SlashCommandArgument.fromProps({ | |
| 75 | + description: 'Extension name', | |
| 76 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 77 | + isRequired: true, | |
| 78 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 79 | + forceEnum: true, | |
| 80 | + }), | |
| 81 | + ], | |
| 82 | + helpString: ` | |
| 83 | + <div> | |
| 84 | + Enables a specified extension. | |
| 85 | + </div> | |
| 86 | + <div> | |
| 87 | + By default, the page will be reloaded automatically, stopping any further commands.<br /> | |
| 88 | + If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay disabled until refreshed. | |
| 89 | + The page either needs to be refreshed, or <code>/reload-page</code> has to be called. | |
| 90 | + </div> | |
| 91 | + <div> | |
| 92 | + <strong>Example:</strong> | |
| 93 | + <ul> | |
| 94 | + <li> | |
| 95 | + <pre><code class="language-stscript">/extension-enable Summarize</code></pre> | |
| 96 | + </li> | |
| 97 | + </ul> | |
| 98 | + </div> | |
| 99 | + `, | |
| 100 | + })); | |
| 101 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 102 | + name: 'extension-disable', | |
| 103 | + callback: getExtensionActionCallback('enable'), | |
| 104 | + namedArgumentList: [ | |
| 105 | + SlashCommandNamedArgument.fromProps({ | |
| 106 | + name: 'reload', | |
| 107 | + description: 'Whether to reload the page after disabling the extension', | |
| 108 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 109 | + defaultValue: 'true', | |
| 110 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 111 | + }), | |
| 112 | + ], | |
| 113 | + unnamedArgumentList: [ | |
| 114 | + SlashCommandArgument.fromProps({ | |
| 115 | + description: 'Extension name', | |
| 116 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 117 | + isRequired: true, | |
| 118 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 119 | + forceEnum: true, | |
| 120 | + }), | |
| 121 | + ], | |
| 122 | + helpString: ` | |
| 123 | + <div> | |
| 124 | + Disables a specified extension. | |
| 125 | + </div> | |
| 126 | + <div> | |
| 127 | + By default, the page will be reloaded automatically, stopping any further commands.<br /> | |
| 128 | + If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay enabled until refreshed. | |
| 129 | + The page either needs to be refreshed, or <code>/reload-page</code> has to be called. | |
| 130 | + </div> | |
| 131 | + <div> | |
| 132 | + <strong>Example:</strong> | |
| 133 | + <ul> | |
| 134 | + <li> | |
| 135 | + <pre><code class="language-stscript">/extension-disable Summarize</code></pre> | |
| 136 | + </li> | |
| 137 | + </ul> | |
| 138 | + </div> | |
| 139 | + `, | |
| 140 | + })); | |
| 141 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 142 | + name: 'extension-toggle', | |
| 143 | + callback: async (args, extensionName) => { | |
| 144 | + if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); | |
| 145 | + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 146 | + | |
| 147 | + const action = isTrueBoolean(args?.state) ? 'enable' : | |
| 148 | + isFalseBoolean(args?.state) ? 'disable' : | |
| 149 | + 'toggle'; | |
| 150 | + | |
| 151 | + return await getExtensionActionCallback(action)(args, extensionName); | |
| 152 | + }, | |
| 153 | + namedArgumentList: [ | |
| 154 | + SlashCommandNamedArgument.fromProps({ | |
| 155 | + name: 'reload', | |
| 156 | + description: 'Whether to reload the page after toggling the extension', | |
| 157 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 158 | + defaultValue: 'true', | |
| 159 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 160 | + }), | |
| 161 | + SlashCommandNamedArgument.fromProps({ | |
| 162 | + name: 'state', | |
| 163 | + description: 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.', | |
| 164 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 165 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 166 | + }), | |
| 167 | + ], | |
| 168 | + unnamedArgumentList: [ | |
| 169 | + SlashCommandArgument.fromProps({ | |
| 170 | + description: 'Extension name', | |
| 171 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 172 | + isRequired: true, | |
| 173 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 174 | + forceEnum: true, | |
| 175 | + }), | |
| 176 | + ], | |
| 177 | + helpString: ` | |
| 178 | + <div> | |
| 179 | + Toggles the state of a specified extension. | |
| 180 | + </div> | |
| 181 | + <div> | |
| 182 | + By default, the page will be reloaded automatically, stopping any further commands.<br /> | |
| 183 | + If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay in its current state until refreshed. | |
| 184 | + The page either needs to be refreshed, or <code>/reload-page</code> has to be called. | |
| 185 | + </div> | |
| 186 | + <div> | |
| 187 | + <strong>Example:</strong> | |
| 188 | + <ul> | |
| 189 | + <li> | |
| 190 | + <pre><code class="language-stscript">/extension-toggle Summarize</code></pre> | |
| 191 | + </li> | |
| 192 | + <li> | |
| 193 | + <pre><code class="language-stscript">/extension-toggle Summarize state=true</code></pre> | |
| 194 | + </li> | |
| 195 | + </ul> | |
| 196 | + </div> | |
| 197 | + `, | |
| 198 | + })); | |
| 199 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 200 | + name: 'extension-state', | |
| 201 | + callback: async (_, extensionName) => { | |
| 202 | + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 203 | + const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); | |
| 204 | + if (!internalExtensionName) { | |
| 205 | + toastr.warning(`Extension ${extensionName} does not exist.`); | |
| 206 | + return ''; | |
| 207 | + } | |
| 208 | + | |
| 209 | + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); | |
| 210 | + return String(isEnabled); | |
| 211 | + }, | |
| 212 | + unnamedArgumentList: [ | |
| 213 | + SlashCommandArgument.fromProps({ | |
| 214 | + description: 'Extension name', | |
| 215 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 216 | + isRequired: true, | |
| 217 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 218 | + forceEnum: true, | |
| 219 | + }), | |
| 220 | + ], | |
| 221 | + helpString: ` | |
| 222 | + <div> | |
| 223 | + Returns the state of a specified extension (true if enabled, false if disabled). | |
| 224 | + </div> | |
| 225 | + <div> | |
| 226 | + <strong>Example:</strong> | |
| 227 | + <ul> | |
| 228 | + <li> | |
| 229 | + <pre><code class="language-stscript">/extension-state Summarize</code></pre> | |
| 230 | + </li> | |
| 231 | + </ul> | |
| 232 | + </div> | |
| 233 | + `, | |
| 234 | + })); | |
| 235 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 236 | + name: 'extension-exists', | |
| 237 | + aliases: ['extension-installed'], | |
| 238 | + callback: async (_, extensionName) => { | |
| 239 | + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 240 | + const exists = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)) !== undefined; | |
| 241 | + return exists ? 'true' : 'false'; | |
| 242 | + }, | |
| 243 | + unnamedArgumentList: [ | |
| 244 | + SlashCommandArgument.fromProps({ | |
| 245 | + description: 'Extension name', | |
| 246 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 247 | + isRequired: true, | |
| 248 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 249 | + forceEnum: true, | |
| 250 | + }), | |
| 251 | + ], | |
| 252 | + helpString: ` | |
| 253 | + <div> | |
| 254 | + Checks if a specified extension exists. | |
| 255 | + </div> | |
| 256 | + <div> | |
| 257 | + <strong>Example:</strong> | |
| 258 | + <ul> | |
| 259 | + <li> | |
| 260 | + <pre><code class="language-stscript">/extension-exists LALib</code></pre> | |
| 261 | + </li> | |
| 262 | + </ul> | |
| 263 | + </div> | |
| 264 | + `, | |
| 265 | + })); | |
| 266 | + | |
| 267 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 268 | + name: 'reload-page', | |
| 269 | + callback: async () => { | |
| 270 | + toastr.info('Reloading the page...'); | |
| 271 | + location.reload(); | |
| 272 | + return ''; | |
| 273 | + }, | |
| 274 | + helpString: 'Reloads the current page. All further commands will not be processed.', | |
| 275 | + })); | |
| 276 | +} | |
| @@ -1,14 +1,8 @@ | ||
| 1 | 1 | import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js'; |
| 2 | 2 | import { showLoader } from './loader.js'; |
| 3 | 3 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; |
| 4 | -import { SlashCommand } from './slash-commands/SlashCommand.js'; | |
| 5 | -import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; | |
| 6 | -import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; | |
| 7 | -import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | |
| 8 | -import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; | |
| 9 | -import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | |
| 10 | 4 | import { renderTemplate, renderTemplateAsync } from './templates.js'; |
| 11 | 5 | import { equalsIgnoreCaseAndAccents, isFalseBoolean, isSubsetOf, isTrueBoolean, setValueByPath } from './utils.js'; |
| 12 | 6 | export { |
| 13 | 7 | getContext, |
| 14 | 8 | getApiUrl, |
| @@ -249,7 +243,7 @@ function onEnableExtensionClick() { | ||
| 249 | 243 | enableExtension(name, false); |
| 250 | 244 | } |
| 251 | 245 | |
| 252 | 246 | export async function enableExtension(name, reload = true) { |
| 253 | 247 | extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name); |
| 254 | 248 | stateChanged = true; |
| 255 | 249 | await saveSettings(); |
| @@ -260,7 +254,7 @@ async function enableExtension(name, reload = true) { | ||
| 260 | 254 | } |
| 261 | 255 | } |
| 262 | 256 | |
| 263 | 257 | export async function disableExtension(name, reload = true) { |
| 264 | 258 | extension_settings.disabledExtensions.push(name); |
| 265 | 259 | stateChanged = true; |
| 266 | 260 | await saveSettings(); |
| @@ -1049,277 +1043,9 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { | ||
| 1049 | 1043 | await installExtension(url); |
| 1050 | 1044 | } |
| 1051 | 1045 | |
| 1052 | -/** | |
| 1053 | - * @param {'enable' | 'disable' | 'toggle'} action - The action to perform on the extension | |
| 1054 | - * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise<string>} | |
| 1055 | - */ | |
| 1056 | -function getExtensionActionCallback(action) { | |
| 1057 | - return async (args, extensionName) => { | |
| 1058 | - if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); | |
| 1059 | - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 1060 | - if (!extensionName) { | |
| 1061 | - toastr.warning(`Extension name must be provided as an argument to ${action} this extension.`); | |
| 1062 | - return ''; | |
| 1063 | - } | |
| 1064 | - | |
| 1065 | - const reload = isTrueBoolean(args?.reload); | |
| 1066 | - const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); | |
| 1067 | - if (!internalExtensionName) { | |
| 1068 | - toastr.warning(`Extension ${extensionName} does not exist.`); | |
| 1069 | - return ''; | |
| 1070 | - } | |
| 1071 | - | |
| 1072 | - const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); | |
| 1073 | - | |
| 1074 | - if (action === 'enable' && isEnabled) { | |
| 1075 | - toastr.info(`Extension ${extensionName} is already enabled.`); | |
| 1076 | - return internalExtensionName; | |
| 1077 | - } | |
| 1078 | - | |
| 1079 | - if (action === 'disable' && !isEnabled) { | |
| 1080 | - toastr.info(`Extension ${extensionName} is already disabled.`); | |
| 1081 | - return internalExtensionName; | |
| 1082 | - } | |
| 1083 | - | |
| 1084 | - if (action === 'toggle') { | |
| 1085 | - action = isEnabled ? 'disable' : 'enable'; | |
| 1086 | - } | |
| 1087 | - | |
| 1088 | - reload && toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); | |
| 1089 | - | |
| 1090 | - if (action === 'enable') { | |
| 1091 | - await enableExtension(internalExtensionName, reload); | |
| 1092 | - } else { | |
| 1093 | - await disableExtension(internalExtensionName, reload); | |
| 1094 | - } | |
| 1095 | - | |
| 1096 | - toastr.success(`Extension ${extensionName} ${action}d.`); | |
| 1097 | - | |
| 1098 | - return internalExtensionName; | |
| 1099 | - }; | |
| 1100 | -} | |
| 1101 | - | |
| 1102 | -function registerExtensionSlashCommands() { | |
| 1103 | - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1104 | - name: 'extension-enable', | |
| 1105 | - callback: getExtensionActionCallback('enable'), | |
| 1106 | - namedArgumentList: [ | |
| 1107 | - SlashCommandNamedArgument.fromProps({ | |
| 1108 | - name: 'reload', | |
| 1109 | - description: 'Whether to reload the page after enabling the extension', | |
| 1110 | - typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 1111 | - defaultValue: 'true', | |
| 1112 | - enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 1113 | - }), | |
| 1114 | - ], | |
| 1115 | - unnamedArgumentList: [ | |
| 1116 | - SlashCommandArgument.fromProps({ | |
| 1117 | - description: 'Extension name', | |
| 1118 | - typeList: [ARGUMENT_TYPE.STRING], | |
| 1119 | - isRequired: true, | |
| 1120 | - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 1121 | - forceEnum: true, | |
| 1122 | - }), | |
| 1123 | - ], | |
| 1124 | - helpString: ` | |
| 1125 | - <div> | |
| 1126 | - Enables a specified extension. | |
| 1127 | - </div> | |
| 1128 | - <div> | |
| 1129 | - By default, the page will be reloaded automatically, stopping any further commands.<br /> | |
| 1130 | - If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay disabled until refreshed. | |
| 1131 | - The page either needs to be refreshed, or <code>/reload-page</code> has to be called. | |
| 1132 | - </div> | |
| 1133 | - <div> | |
| 1134 | - <strong>Example:</strong> | |
| 1135 | - <ul> | |
| 1136 | - <li> | |
| 1137 | - <pre><code class="language-stscript">/extension-enable Summarize</code></pre> | |
| 1138 | - </li> | |
| 1139 | - </ul> | |
| 1140 | - </div> | |
| 1141 | - `, | |
| 1142 | - })); | |
| 1143 | - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1144 | - name: 'extension-disable', | |
| 1145 | - callback: getExtensionActionCallback('enable'), | |
| 1146 | - namedArgumentList: [ | |
| 1147 | - SlashCommandNamedArgument.fromProps({ | |
| 1148 | - name: 'reload', | |
| 1149 | - description: 'Whether to reload the page after disabling the extension', | |
| 1150 | - typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 1151 | - defaultValue: 'true', | |
| 1152 | - enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 1153 | - }), | |
| 1154 | - ], | |
| 1155 | - unnamedArgumentList: [ | |
| 1156 | - SlashCommandArgument.fromProps({ | |
| 1157 | - description: 'Extension name', | |
| 1158 | - typeList: [ARGUMENT_TYPE.STRING], | |
| 1159 | - isRequired: true, | |
| 1160 | - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 1161 | - forceEnum: true, | |
| 1162 | - }), | |
| 1163 | - ], | |
| 1164 | - helpString: ` | |
| 1165 | - <div> | |
| 1166 | - Disables a specified extension. | |
| 1167 | - </div> | |
| 1168 | - <div> | |
| 1169 | - By default, the page will be reloaded automatically, stopping any further commands.<br /> | |
| 1170 | - If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay enabled until refreshed. | |
| 1171 | - The page either needs to be refreshed, or <code>/reload-page</code> has to be called. | |
| 1172 | - </div> | |
| 1173 | - <div> | |
| 1174 | - <strong>Example:</strong> | |
| 1175 | - <ul> | |
| 1176 | - <li> | |
| 1177 | - <pre><code class="language-stscript">/extension-disable Summarize</code></pre> | |
| 1178 | - </li> | |
| 1179 | - </ul> | |
| 1180 | - </div> | |
| 1181 | - `, | |
| 1182 | - })); | |
| 1183 | - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1184 | - name: 'extension-toggle', | |
| 1185 | - callback: async (args, extensionName) => { | |
| 1186 | - if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); | |
| 1187 | - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 1188 | - | |
| 1189 | - const action = isTrueBoolean(args?.state) ? 'enable' : | |
| 1190 | - isFalseBoolean(args?.state) ? 'disable' : | |
| 1191 | - 'toggle'; | |
| 1192 | - | |
| 1193 | - return await getExtensionActionCallback(action)(args, extensionName); | |
| 1194 | - }, | |
| 1195 | - namedArgumentList: [ | |
| 1196 | - SlashCommandNamedArgument.fromProps({ | |
| 1197 | - name: 'reload', | |
| 1198 | - description: 'Whether to reload the page after toggling the extension', | |
| 1199 | - typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 1200 | - defaultValue: 'true', | |
| 1201 | - enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 1202 | - }), | |
| 1203 | - SlashCommandNamedArgument.fromProps({ | |
| 1204 | - name: 'state', | |
| 1205 | - description: 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.', | |
| 1206 | - typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 1207 | - enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 1208 | - }), | |
| 1209 | - ], | |
| 1210 | - unnamedArgumentList: [ | |
| 1211 | - SlashCommandArgument.fromProps({ | |
| 1212 | - description: 'Extension name', | |
| 1213 | - typeList: [ARGUMENT_TYPE.STRING], | |
| 1214 | - isRequired: true, | |
| 1215 | - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 1216 | - forceEnum: true, | |
| 1217 | - }), | |
| 1218 | - ], | |
| 1219 | - helpString: ` | |
| 1220 | - <div> | |
| 1221 | - Toggles the state of a specified extension. | |
| 1222 | - </div> | |
| 1223 | - <div> | |
| 1224 | - By default, the page will be reloaded automatically, stopping any further commands.<br /> | |
| 1225 | - If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay in its current state until refreshed. | |
| 1226 | - The page either needs to be refreshed, or <code>/reload-page</code> has to be called. | |
| 1227 | - </div> | |
| 1228 | - <div> | |
| 1229 | - <strong>Example:</strong> | |
| 1230 | - <ul> | |
| 1231 | - <li> | |
| 1232 | - <pre><code class="language-stscript">/extension-toggle Summarize</code></pre> | |
| 1233 | - </li> | |
| 1234 | - <li> | |
| 1235 | - <pre><code class="language-stscript">/extension-toggle Summarize state=true</code></pre> | |
| 1236 | - </li> | |
| 1237 | - </ul> | |
| 1238 | - </div> | |
| 1239 | - `, | |
| 1240 | - })); | |
| 1241 | - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1242 | - name: 'extension-state', | |
| 1243 | - callback: async (_, extensionName) => { | |
| 1244 | - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 1245 | - const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); | |
| 1246 | - if (!internalExtensionName) { | |
| 1247 | - toastr.warning(`Extension ${extensionName} does not exist.`); | |
| 1248 | - return ''; | |
| 1249 | - } | |
| 1250 | 1046 | |
| 1251 | - const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); | |
| 1252 | - return String(isEnabled); | |
| 1253 | - }, | |
| 1254 | - unnamedArgumentList: [ | |
| 1255 | - SlashCommandArgument.fromProps({ | |
| 1256 | - description: 'Extension name', | |
| 1257 | - typeList: [ARGUMENT_TYPE.STRING], | |
| 1258 | - isRequired: true, | |
| 1259 | - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 1260 | - forceEnum: true, | |
| 1261 | - }), | |
| 1262 | - ], | |
| 1263 | - helpString: ` | |
| 1264 | - <div> | |
| 1265 | - Returns the state of a specified extension (true if enabled, false if disabled). | |
| 1266 | - </div> | |
| 1267 | - <div> | |
| 1268 | - <strong>Example:</strong> | |
| 1269 | - <ul> | |
| 1270 | - <li> | |
| 1271 | - <pre><code class="language-stscript">/extension-state Summarize</code></pre> | |
| 1272 | - </li> | |
| 1273 | - </ul> | |
| 1274 | - </div> | |
| 1275 | - `, | |
| 1276 | - })); | |
| 1277 | - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1278 | - name: 'extension-exists', | |
| 1279 | - aliases: ['extension-installed'], | |
| 1280 | - callback: async (_, extensionName) => { | |
| 1281 | - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); | |
| 1282 | - const exists = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)) !== undefined; | |
| 1283 | - return exists ? 'true' : 'false'; | |
| 1284 | - }, | |
| 1285 | - unnamedArgumentList: [ | |
| 1286 | - SlashCommandArgument.fromProps({ | |
| 1287 | - description: 'Extension name', | |
| 1288 | - typeList: [ARGUMENT_TYPE.STRING], | |
| 1289 | - isRequired: true, | |
| 1290 | - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 1291 | - forceEnum: true, | |
| 1292 | - }), | |
| 1293 | - ], | |
| 1294 | - helpString: ` | |
| 1295 | - <div> | |
| 1296 | - Checks if a specified extension exists. | |
| 1297 | - </div> | |
| 1298 | - <div> | |
| 1299 | - <strong>Example:</strong> | |
| 1300 | - <ul> | |
| 1301 | - <li> | |
| 1302 | - <pre><code class="language-stscript">/extension-exists LALib</code></pre> | |
| 1303 | - </li> | |
| 1304 | - </ul> | |
| 1305 | - </div> | |
| 1306 | - `, | |
| 1307 | - })); | |
| 1308 | - | |
| 1309 | - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1310 | - name: 'reload-page', | |
| 1311 | - callback: async () => { | |
| 1312 | - toastr.info('Reloading the page...'); | |
| 1313 | - location.reload(); | |
| 1314 | - return ''; | |
| 1315 | - }, | |
| 1316 | - helpString: 'Reloads the current page. All further commands will not be processed.', | |
| 1317 | - })); | |
| 1318 | -} | |
| 1319 | 1047 | |
| 1320 | 1048 | export async function initExtensions() { |
| 1321 | - registerExtensionSlashCommands(); | |
| 1322 | - | |
| 1323 | 1049 | await addExtensionsButtonAndMenu(); |
| 1324 | 1050 | $('#extensionsMenuButton').css('display', 'flex'); |
| 1325 | 1051 | |