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 | import { initInputMarkdown } from './scripts/input-md-formatting.js'; | 244 | import { initInputMarkdown } from './scripts/input-md-formatting.js'; |
| 245 | import { AbortReason } from './scripts/util/AbortReason.js'; | 245 | import { AbortReason } from './scripts/util/AbortReason.js'; |
| 246 | import { initSystemPrompts } from './scripts/sysprompt.js'; | 246 | import { initSystemPrompts } from './scripts/sysprompt.js'; |
| 247 | import { registerExtensionSlashCommands } from './scripts/extensions-slashcommands.js'; | ||
| 247 | 248 | ||
| 248 | //exporting functions and vars for mods | 249 | //exporting functions and vars for mods |
| 249 | export { | 250 | export { |
| @@ -957,6 +958,7 @@ async function firstLoadInit() { | |||
| 957 | initLogprobs(); | 958 | initLogprobs(); |
| 958 | initInputMarkdown(); | 959 | initInputMarkdown(); |
| 959 | initExtensions(); | 960 | initExtensions(); |
| 961 | registerExtensionSlashCommands(); | ||
| 960 | doDailyExtensionUpdatesCheck(); | 962 | doDailyExtensionUpdatesCheck(); |
| 961 | await hideLoader(); | 963 | await hideLoader(); |
| 962 | await fixViewport(); | 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 | import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js'; | 1 | import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js'; |
| 2 | import { showLoader } from './loader.js'; | 2 | import { showLoader } from './loader.js'; |
| 3 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; | 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 | import { renderTemplate, renderTemplateAsync } from './templates.js'; | 4 | import { renderTemplate, renderTemplateAsync } from './templates.js'; |
| 11 | import { equalsIgnoreCaseAndAccents, isFalseBoolean, isSubsetOf, isTrueBoolean, setValueByPath } from './utils.js'; | 5 | import { isSubsetOf, setValueByPath } from './utils.js'; |
| 12 | export { | 6 | export { |
| 13 | getContext, | 7 | getContext, |
| 14 | getApiUrl, | 8 | getApiUrl, |
| @@ -249,7 +243,7 @@ function onEnableExtensionClick() { | |||
| 249 | enableExtension(name, false); | 243 | enableExtension(name, false); |
| 250 | } | 244 | } |
| 251 | 245 | ||
| 252 | async function enableExtension(name, reload = true) { | 246 | export async function enableExtension(name, reload = true) { |
| 253 | extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name); | 247 | extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name); |
| 254 | stateChanged = true; | 248 | stateChanged = true; |
| 255 | await saveSettings(); | 249 | await saveSettings(); |
| @@ -260,7 +254,7 @@ async function enableExtension(name, reload = true) { | |||
| 260 | } | 254 | } |
| 261 | } | 255 | } |
| 262 | 256 | ||
| 263 | async function disableExtension(name, reload = true) { | 257 | export async function disableExtension(name, reload = true) { |
| 264 | extension_settings.disabledExtensions.push(name); | 258 | extension_settings.disabledExtensions.push(name); |
| 265 | stateChanged = true; | 259 | stateChanged = true; |
| 266 | await saveSettings(); | 260 | await saveSettings(); |
| @@ -1049,277 +1043,9 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { | |||
| 1049 | await installExtension(url); | 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 | 1046 | ||
| 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 | |||
| 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 | export async function initExtensions() { | 1048 | export async function initExtensions() { |
| 1321 | registerExtensionSlashCommands(); | ||
| 1322 | |||
| 1323 | await addExtensionsButtonAndMenu(); | 1049 | await addExtensionsButtonAndMenu(); |
| 1324 | $('#extensionsMenuButton').css('display', 'flex'); | 1050 | $('#extensionsMenuButton').css('display', 'flex'); |
| 1325 | 1051 | ||