| 1041 | 1049 | await installExtension(url); |
| 1042 | 1050 | } |
| 1043 | 1051 | |
| 1052 | +/** |
| 1053 | + * @param {boolean} enable - Whether to enable or disable the extension |
| 1054 | + * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise<string>} |
| 1055 | + */ |
| 1056 | +function getExtensionToggleCallback(enable) { |
| 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 does only support string. Closures or arrays are not allowed.'); |
| 1060 | + if (!extensionName) { |
| 1061 | + toastr.warning(`Extension name must be provided as an argument to ${enable ? 'enable' : 'disable'} this extension.`); |
| 1062 | + return ''; |
| 1063 | + } |
| 1064 | + |
| 1065 | + const reload = isTrueBoolean(args?.reload); |
| 1066 | + |
| 1067 | + const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); |
| 1068 | + if (!internalExtensionName) { |
| 1069 | + toastr.warning(`Extension ${extensionName} does not exist.`); |
| 1070 | + return ''; |
| 1071 | + } |
| 1072 | + if (enable === !extension_settings.disabledExtensions.includes(internalExtensionName)) { |
| 1073 | + toastr.info(`Extension ${extensionName} is already ${enable ? 'enabled' : 'disabled'}.`); |
| 1074 | + return internalExtensionName; |
| 1075 | + } |
| 1076 | + |
| 1077 | + reload && toastr.info(`${enable ? 'Enabling' : 'Disabling'} extension ${extensionName} and reloading...`); |
| 1078 | + await enableExtension(internalExtensionName, reload); |
| 1079 | + toastr.success(`Extension ${extensionName} ${enable ? 'enabled' : 'disabled'}.`); |
| 1080 | + |
| 1081 | + return internalExtensionName; |
| 1082 | + }; |
| 1083 | +} |
| 1084 | + |
| 1085 | +function registerExtensionSlashCommands() { |
| 1086 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1087 | + name: 'extension-enable', |
| 1088 | + callback: getExtensionToggleCallback(true), |
| 1089 | + namedArgumentList: [ |
| 1090 | + SlashCommandNamedArgument.fromProps({ |
| 1091 | + name: 'reload', |
| 1092 | + description: 'Whether to reload the page after enabling the extension', |
| 1093 | + typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1094 | + defaultValue: 'true', |
| 1095 | + enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1096 | + }), |
| 1097 | + ], |
| 1098 | + unnamedArgumentList: [ |
| 1099 | + SlashCommandArgument.fromProps({ |
| 1100 | + description: 'Extension name', |
| 1101 | + typeList: [ARGUMENT_TYPE.STRING], |
| 1102 | + isRequired: true, |
| 1103 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), |
| 1104 | + forceEnum: true, |
| 1105 | + }), |
| 1106 | + ], |
| 1107 | + helpString: ` |
| 1108 | + <div> |
| 1109 | + Enables a specified extension. |
| 1110 | + </div> |
| 1111 | + <div> |
| 1112 | + By default, the page will be reloaded automatically, stopping any further commands.<br /> |
| 1113 | + If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay disabled until refreshed. |
| 1114 | + The page either needs to be refreshed, or <code>/reload-page</code> has to be called. |
| 1115 | + </div> |
| 1116 | + <div> |
| 1117 | + <strong>Example:</strong> |
| 1118 | + <ul> |
| 1119 | + <li> |
| 1120 | + <pre><code class="language-stscript">/extension-enable Summarize</code></pre> |
| 1121 | + </li> |
| 1122 | + </ul> |
| 1123 | + </div> |
| 1124 | + `, |
| 1125 | + })); |
| 1126 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1127 | + name: 'extension-disable', |
| 1128 | + callback: getExtensionToggleCallback(false), |
| 1129 | + namedArgumentList: [ |
| 1130 | + SlashCommandNamedArgument.fromProps({ |
| 1131 | + name: 'reload', |
| 1132 | + description: 'Whether to reload the page after disabling the extension', |
| 1133 | + typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1134 | + defaultValue: 'true', |
| 1135 | + enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1136 | + }), |
| 1137 | + ], |
| 1138 | + unnamedArgumentList: [ |
| 1139 | + SlashCommandArgument.fromProps({ |
| 1140 | + description: 'Extension name', |
| 1141 | + typeList: [ARGUMENT_TYPE.STRING], |
| 1142 | + isRequired: true, |
| 1143 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), |
| 1144 | + forceEnum: true, |
| 1145 | + }), |
| 1146 | + ], |
| 1147 | + helpString: ` |
| 1148 | + <div> |
| 1149 | + Disables a specified extension. |
| 1150 | + </div> |
| 1151 | + <div> |
| 1152 | + By default, the page will be reloaded automatically, stopping any further commands.<br /> |
| 1153 | + If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay enabled until refreshed. |
| 1154 | + The page either needs to be refreshed, or <code>/reload-page</code> has to be called. |
| 1155 | + </div> |
| 1156 | + <div> |
| 1157 | + <strong>Example:</strong> |
| 1158 | + <ul> |
| 1159 | + <li> |
| 1160 | + <pre><code class="language-stscript">/extension-disable Summarize</code></pre> |
| 1161 | + </li> |
| 1162 | + </ul> |
| 1163 | + </div> |
| 1164 | + `, |
| 1165 | + })); |
| 1166 | + |
| 1167 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1168 | + name: 'reload-page', |
| 1169 | + callback: async () => { |
| 1170 | + toastr.info('Reloading the page...'); |
| 1171 | + location.reload(); |
| 1172 | + return ''; |
| 1173 | + }, |
| 1174 | + helpString: 'Reloads the current page. All further commands will not be processed.', |
| 1175 | + })); |
| 1176 | +} |
| 1177 | + |
| 1044 | 1178 | export async function initExtensions() { |
| 1179 | + registerExtensionSlashCommands(); |
| 1180 | + |
| 1045 | 1181 | await addExtensionsButtonAndMenu(); |
| 1046 | 1182 | $('#extensionsMenuButton').css('display', 'flex'); |
| 1047 | 1183 | |