From 6df3498cb5c5c2a20681623526c3b1e00460ac80 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Tue, 24 Jun 2025 08:43:57 +0200 Subject: [PATCH] Finished autocomplete & context menu interactions Autocomplete & context menu interactions have been fully implemented in the Open Discord framework. They have not yet been implemented in the Open Ticket bot code though. --- src/core/api/defaults/client.ts | 2 +- src/core/api/defaults/event.ts | 6 +- src/core/api/defaults/responder.ts | 98 ++++++++- src/core/api/modules/defaults.ts | 6 + src/core/api/modules/responder.ts | 305 ++++++++++++++++++++++++++++- src/data/framework/eventLoader.ts | 4 + src/index.ts | 18 +- 7 files changed, 432 insertions(+), 7 deletions(-) diff --git a/src/core/api/defaults/client.ts b/src/core/api/defaults/client.ts index 620e4ef..0859c14 100644 --- a/src/core/api/defaults/client.ts +++ b/src/core/api/defaults/client.ts @@ -160,7 +160,7 @@ export class ODTextCommandManager_Default extends ODTextCommandManager { * It's used to generate typescript declarations for this class. */ export interface ODContextMenuManagerIds_Default { - "opendiscord:test-menu":ODContextMenu + //"opendiscord:test-menu":ODContextMenu } /**## ODContextMenuManager_Default `default_class` diff --git a/src/core/api/defaults/event.ts b/src/core/api/defaults/event.ts index 1ea6607..f4f6d05 100644 --- a/src/core/api/defaults/event.ts +++ b/src/core/api/defaults/event.ts @@ -21,7 +21,7 @@ import { ODLanguageManager_Default } from "./language" import { ODCheckerFunctionManager_Default, ODCheckerManager_Default, ODCheckerRenderer_Default, ODCheckerTranslationRegister_Default } from "./checker" import { ODClientManager_Default, ODContextMenuManager_Default, ODSlashCommandManager_Default, ODTextCommandManager_Default } from "./client" import { ODBuilderManager_Default, ODButtonManager_Default, ODDropdownManager_Default, ODEmbedManager_Default, ODFileManager_Default, ODMessageManager_Default, ODModalManager_Default } from "./builder" -import { ODButtonResponderManager_Default, ODCommandResponderManager_Default, ODDropdownResponderManager_Default, ODModalResponderManager_Default, ODResponderManager_Default } from "./responder" +import { ODAutocompleteResponderManager_Default, ODButtonResponderManager_Default, ODCommandResponderManager_Default, ODContextMenuResponderManager_Default, ODDropdownResponderManager_Default, ODModalResponderManager_Default, ODResponderManager_Default } from "./responder" import { ODActionManager_Default } from "./action" import { ODPermissionManager_Default } from "./permission" import { ODHelpMenuManager_Default } from "./helpmenu" @@ -255,6 +255,10 @@ export interface ODEventIds_Default { "afterDropdownRespondersLoaded": ODEvent_Default<(dropdowns:ODDropdownResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> "onModalResponderLoad": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> "afterModalRespondersLoaded": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> + "onContextMenuResponderLoad": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> + "afterContextMenuRespondersLoaded": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> + "onAutocompleteResponderLoad": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> + "afterAutocompleteRespondersLoaded": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> //plugin loading before finalizations "onPluginBeforeFinalizationLoad": ODEvent_Default<() => ODPromiseVoid>, diff --git a/src/core/api/defaults/responder.ts b/src/core/api/defaults/responder.ts index 1d80ea9..95534bb 100644 --- a/src/core/api/defaults/responder.ts +++ b/src/core/api/defaults/responder.ts @@ -2,7 +2,7 @@ //DEFAULT RESPONDER MODULE /////////////////////////////////////// import { ODValidId } from "../modules/base" -import { ODButtonResponder, ODButtonResponderInstance, ODButtonResponderManager, ODCommandResponder, ODCommandResponderInstance, ODCommandResponderManager, ODDropdownResponder, ODDropdownResponderInstance, ODDropdownResponderManager, ODModalResponder, ODModalResponderInstance, ODModalResponderManager, ODResponderManager } from "../modules/responder" +import { ODAutocompleteResponder, ODAutocompleteResponderInstance, ODAutocompleteResponderManager, ODButtonResponder, ODButtonResponderInstance, ODButtonResponderManager, ODCommandResponder, ODCommandResponderInstance, ODCommandResponderManager, ODContextMenuResponder, ODContextMenuResponderInstance, ODContextMenuResponderManager, ODDropdownResponder, ODDropdownResponderInstance, ODDropdownResponderManager, ODModalResponder, ODModalResponderInstance, ODModalResponderManager, ODResponderManager } from "../modules/responder" import { ODWorkerManager_Default } from "./worker" /**## ODResponderManager_Default `default_class` @@ -16,6 +16,8 @@ export class ODResponderManager_Default extends ODResponderManager { declare buttons: ODButtonResponderManager_Default declare dropdowns: ODDropdownResponderManager_Default declare modals: ODModalResponderManager_Default + declare contextMenus: ODContextMenuResponderManager_Default + declare autocomplete: ODAutocompleteResponderManager_Default } /**## ODCommandResponderManagerIds_Default `interface` @@ -252,4 +254,98 @@ export class ODModalResponderManager_Default extends ODModalResponderManager { */ export class ODModalResponder_Default extends ODModalResponder { declare workers: ODWorkerManager_Default +} + +/**## ODContextMenuResponderManagerIds_Default `interface` + * This interface is a list of ids available in the `ODContextMenuResponderManager_Default` class. + * It's used to generate typescript declarations for this class. + */ +export interface ODContextMenuResponderManagerIds_Default { + //"opendiscord:example":{source:"context-menu",params:{},workers:"opendiscord:example"}, +} + +/**## ODContextMenuResponderManager_Default `default_class` + * This is a special class that adds type definitions & typescript to the ODContextMenuResponderManager class. + * It doesn't add any extra features! + * + * This default class is made for the global variable `opendiscord.responders.contextMenus`! + */ +export class ODContextMenuResponderManager_Default extends ODContextMenuResponderManager { + get(id:ModalResponderId): ODContextMenuResponder_Default + get(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null + + get(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null { + return super.get(id) + } + + remove(id:ModalResponderId): ODContextMenuResponder_Default + remove(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null + + remove(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null { + return super.remove(id) + } + + exists(id:keyof ODContextMenuResponderManagerIds_Default): boolean + exists(id:ODValidId): boolean + + exists(id:ODValidId): boolean { + return super.exists(id) + } +} + +/**## ODContextMenuResponder_Default `default_class` + * This is a special class that adds type definitions & typescript to the ODContextMenuResponder class. + * It doesn't add any extra features! + * + * This default class is made for the default `ODContextMenuResponder`'s! + */ +export class ODContextMenuResponder_Default extends ODContextMenuResponder { + declare workers: ODWorkerManager_Default +} + +/**## ODAutocompleteResponderManagerIds_Default `interface` + * This interface is a list of ids available in the `ODAutocompleteResponderManager_Default` class. + * It's used to generate typescript declarations for this class. + */ +export interface ODAutocompleteResponderManagerIds_Default { + //"opendiscord:example":{source:"autocomplete",params:{},workers:"opendiscord:example"}, +} + +/**## ODAutocompleteResponderManager_Default `default_class` + * This is a special class that adds type definitions & typescript to the ODAutocompleteResponderManager class. + * It doesn't add any extra features! + * + * This default class is made for the global variable `opendiscord.responders.autocomplete`! + */ +export class ODAutocompleteResponderManager_Default extends ODAutocompleteResponderManager { + get(id:ModalResponderId): ODAutocompleteResponder_Default + get(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null + + get(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null { + return super.get(id) + } + + remove(id:ModalResponderId): ODAutocompleteResponder_Default + remove(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null + + remove(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null { + return super.remove(id) + } + + exists(id:keyof ODAutocompleteResponderManagerIds_Default): boolean + exists(id:ODValidId): boolean + + exists(id:ODValidId): boolean { + return super.exists(id) + } +} + +/**## ODAutocompleteResponder_Default `default_class` + * This is a special class that adds type definitions & typescript to the ODAutocompleteResponder class. + * It doesn't add any extra features! + * + * This default class is made for the default `ODAutocompleteResponder`'s! + */ +export class ODAutocompleteResponder_Default extends ODAutocompleteResponder { + declare workers: ODWorkerManager_Default } \ No newline at end of file diff --git a/src/core/api/modules/defaults.ts b/src/core/api/modules/defaults.ts index 02029fa..4b366ff 100644 --- a/src/core/api/modules/defaults.ts +++ b/src/core/api/modules/defaults.ts @@ -140,6 +140,10 @@ export interface ODDefaults { dropdownRespondersLoading:boolean, /**Load the default Open Ticket modal responders. */ modalRespondersLoading:boolean, + /**Load the default Open Ticket context menu responders. */ + contextMenuRespondersLoading:boolean, + /**Load the default Open Ticket autocomplete responders. */ + autocompleteRespondersLoading:boolean, /**Set the time (in ms) before Open Ticket sends an error message when no reply is sent in a responder. */ responderTimeoutMs:number, @@ -311,6 +315,8 @@ export class ODDefaultsManager { buttonRespondersLoading:true, dropdownRespondersLoading:true, modalRespondersLoading:true, + contextMenuRespondersLoading:true, + autocompleteRespondersLoading:true, responderTimeoutMs:2500, actionsLoading:true, diff --git a/src/core/api/modules/responder.ts b/src/core/api/modules/responder.ts index a732d2a..ab995dd 100644 --- a/src/core/api/modules/responder.ts +++ b/src/core/api/modules/responder.ts @@ -5,7 +5,7 @@ import { ODId, ODManager, ODValidId, ODSystemError, ODManagerData } from "./base import * as discord from "discord.js" import { ODWorkerManager, ODWorkerCallback, ODWorker } from "./worker" import { ODDebugger } from "./console" -import { ODClientManager, ODSlashCommand, ODTextCommand, ODTextCommandInteractionOption } from "./client" +import { ODClientManager, ODContextMenu, ODSlashCommand, ODTextCommand, ODTextCommandInteractionOption } from "./client" import { ODDropdownData, ODMessageBuildResult, ODMessageBuildSentResult, ODModalBuildResult } from "./builder" /**## ODResponderImplementation `class` @@ -36,7 +36,7 @@ export class ODResponderImplementation ex /**## ODResponderTimeoutErrorCallback `type` * This is the callback for the responder timeout function. It will be executed when something went wrong or the action takes too much time. */ -export type ODResponderTimeoutErrorCallback = (instance:Instance, source:Source) => void|Promise +export type ODResponderTimeoutErrorCallback = (instance:Instance, source:Source) => void|Promise /**## ODResponderManager `class` * This is an Open Ticket responder manager. @@ -61,12 +61,18 @@ export class ODResponderManager { dropdowns: ODDropdownResponderManager /**A manager for all modal responders. */ modals: ODModalResponderManager + /**A manager for all context menu responders. */ + contextMenus: ODContextMenuResponderManager + /**A manager for all autocomplete responders. */ + autocomplete: ODAutocompleteResponderManager constructor(debug:ODDebugger, client:ODClientManager){ this.commands = new ODCommandResponderManager(debug,"command responder",client) this.buttons = new ODButtonResponderManager(debug,"button responder",client) this.dropdowns = new ODDropdownResponderManager(debug,"dropdown responder",client) this.modals = new ODModalResponderManager(debug,"modal responder",client) + this.contextMenus = new ODContextMenuResponderManager(debug,"context menu responder",client) + this.autocomplete = new ODAutocompleteResponderManager(debug,"autocomplete responder",client) } } @@ -1083,7 +1089,7 @@ export class ODModalResponderInstance { const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) this.didReply = true return {success:true,message:await sent.fetch()} - }else throw new ODSystemError() + }else throw new ODSystemError("Unable to update modal interaction!") }catch{ return {success:false,message:null} } @@ -1113,4 +1119,297 @@ export class ODModalResponder extends ODResponderI //wait for workers to finish await this.workers.executeWorkers(instance,source,params) } +} + +/**## ODContextMenuResponderManager `class` + * This is an Open Ticket context menu responder manager. + * + * It contains all Open Ticket context menu responders. These can respond to user/message context menu interactions. + * + * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: + * - plugins can extend/edit replies + * - automatically reply on error + * - independent workers (with priority) + * - fail-safe design using try-catch + * - know where the request came from! + * - And so much more! + */ +export class ODContextMenuResponderManager extends ODManager> { + /**An alias to the Open Ticket client manager. */ + #client: ODClientManager + /**The callback executed when the default workers take too much time to reply. */ + #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null + /**The amount of milliseconds before the timeout error callback is executed. */ + #timeoutMs: number|null = null + + constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ + super(debug,debugname) + this.#client = client + } + + /**Set the message to send when the response times out! */ + setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ + this.#timeoutErrorCallback = callback + this.#timeoutMs = ms + } + + add(data:ODContextMenuResponder<"context-menu",any>, overwrite?:boolean){ + const res = super.add(data,overwrite) + + this.#client.contextMenus.onInteraction(data.match,(interaction,cmd) => { + const newData = this.get(data.id) + if (!newData) return + newData.respond(new ODContextMenuResponderInstance(interaction,cmd,this.#timeoutErrorCallback,this.#timeoutMs),"context-menu",{}) + }) + + return res + } +} + +/**## ODContextMenuResponderInstance `class` + * This is an Open Ticket context menu responder instance. + * + * An instance is an active context menu interaction. You can reply to the context menu using `reply()`. + */ +export class ODContextMenuResponderInstance { + /**The interaction which is the source of this instance. */ + interaction: discord.ContextMenuCommandInteraction + /**Did a worker already reply to this instance/interaction? */ + didReply: boolean = false + /**The context menu wich is the source of this instance. */ + menu:ODContextMenu + /**The user who triggered this context menu. */ + user: discord.User + /**The guild member who triggered this context menu. */ + member: discord.GuildMember|null + /**The guild where this context menu was triggered. */ + guild: discord.Guild|null + /**The channel where this context menu was triggered. */ + channel: discord.TextBasedChannel + /**The target of this context menu (user or message). */ + target: discord.Message|discord.User + + constructor(interaction:discord.ContextMenuCommandInteraction, menu:ODContextMenu, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null){ + if (!interaction.channel) throw new ODSystemError("ODContextMenuResponderInstance: Unable to find interaction channel!") + this.interaction = interaction + this.menu = menu + this.user = interaction.user + this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null + this.guild = interaction.guild + this.channel = interaction.channel + if (interaction.isMessageContextMenuCommand()) this.target = interaction.targetMessage + else if (interaction.isUserContextMenuCommand()) this.target = interaction.targetUser + else throw new ODSystemError("ODContextMenuResponderInstance: Invalid context menu type. Should be of the type User/Message!") + + setTimeout(async () => { + if (!this.didReply){ + try { + if (!errorCallback){ + this.reply({id:new ODId("looks-like-we-got-an-error-here"), ephemeral:true, message:{ + content:":x: **Something went wrong while replying to this context menu!**" + }}) + }else{ + await errorCallback(this,"context-menu") + } + + }catch(err){ + process.emit("uncaughtException",err) + } + } + },timeoutMs ?? 2500) + } + + /**Reply to this context menu. */ + async reply(msg:ODMessageBuildResult): Promise> { + try{ + const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] + if (this.interaction.replied || this.interaction.deferred){ + const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) + this.didReply = true + return {success:true,message:sent} + }else{ + const sent = await this.interaction.reply(Object.assign(msg.message,{flags:msgFlags})) + this.didReply = true + return {success:true,message:await sent.fetch()} + } + }catch{ + return {success:false,message:null} + } + } + /**Update the message of this context menu. */ + async update(msg:ODMessageBuildResult): Promise> { + try{ + const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] + if (this.interaction.replied || this.interaction.deferred){ + const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) + this.didReply = true + return {success:true,message:await sent.fetch()} + }else throw new ODSystemError("Unable to update context menu interaction!") + }catch{ + return {success:false,message:null} + } + } + /**Defer this context menu. */ + async defer(type:"reply", ephemeral:boolean){ + if (this.interaction.deferred) return false + if (type == "reply"){ + const msgFlags: number[] = ephemeral ? [discord.MessageFlags.Ephemeral] : [] + await this.interaction.deferReply({flags:msgFlags}) + } + this.didReply = true + return true + } + /**Show a modal as reply to this context menu. */ + async modal(modal:ODModalBuildResult){ + this.interaction.showModal(modal.modal) + this.didReply = true + return true + } +} + +/**## ODContextMenuResponder `class` + * This is an Open Ticket context menu responder. + * + * This class manages all workers which are executed when the related context menu is triggered. + */ +export class ODContextMenuResponder extends ODResponderImplementation { + /**Respond to this button */ + async respond(instance:ODContextMenuResponderInstance, source:Source, params:Params){ + //wait for workers to finish + await this.workers.executeWorkers(instance,source,params) + } +} + +/**## ODAutocompleteResponderManager `class` + * This is an Open Ticket autocomplete responder manager. + * + * It contains all Open Ticket autocomplete responders. These can respond to autocomplete interactions. + * + * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: + * - plugins can extend/edit replies + * - automatically reply on error + * - independent workers (with priority) + * - fail-safe design using try-catch + * - know where the request came from! + * - And so much more! + */ +export class ODAutocompleteResponderManager extends ODManager> { + /**An alias to the Open Ticket client manager. */ + #client: ODClientManager + /**The callback executed when the default workers take too much time to reply. */ + #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null + /**The amount of milliseconds before the timeout error callback is executed. */ + #timeoutMs: number|null = null + + constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ + super(debug,debugname) + this.#client = client + } + + /**Set the message to send when the response times out! */ + setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ + this.#timeoutErrorCallback = callback + this.#timeoutMs = ms + } + + add(data:ODAutocompleteResponder<"autocomplete",any>, overwrite?:boolean){ + const res = super.add(data,overwrite) + + this.#client.autocompletes.onInteraction(data.cmdMatch,data.match,(interaction) => { + const newData = this.get(data.id) + if (!newData) return + newData.respond(new ODAutocompleteResponderInstance(interaction,this.#timeoutErrorCallback,this.#timeoutMs),"autocomplete",{}) + }) + + return res + } +} + +/**## ODAutocompleteResponderInstance `class` + * This is an Open Ticket autocomplete responder instance. + * + * An instance is an active autocomplete interaction. You can reply to the autocomplete using `reply()`. + */ +export class ODAutocompleteResponderInstance { + /**The interaction which is the source of this instance. */ + interaction: discord.AutocompleteInteraction + /**Did a worker already reply to this instance/interaction? */ + didReply: boolean = false + /**The user who triggered this autocomplete. */ + user: discord.User + /**The guild member who triggered this autocomplete. */ + member: discord.GuildMember|null + /**The guild where this autocomplete was triggered. */ + guild: discord.Guild|null + /**The channel where this autocomplete was triggered. */ + channel: discord.TextBasedChannel + /**The target slash command option of this autocomplete. */ + target: discord.AutocompleteFocusedOption + + constructor(interaction:discord.AutocompleteInteraction, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null){ + if (!interaction.channel) throw new ODSystemError("ODAutocompleteResponderInstance: Unable to find interaction channel!") + this.interaction = interaction + this.user = interaction.user + this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null + this.guild = interaction.guild + this.channel = interaction.channel + this.target = interaction.options.getFocused(true) + + setTimeout(async () => { + if (!this.didReply){ + process.emit("uncaughtException",new ODSystemError("Autocomplete responder instance failed to respond widthin 2.5sec!")) + } + },timeoutMs ?? 2500) + } + + /**Reply to this autocomplete. */ + async autocomplete(choices:(string|discord.ApplicationCommandOptionChoiceData)[]): Promise<{success:boolean}> { + const newChoices: (discord.ApplicationCommandOptionChoiceData)[] = choices.map((raw) => { + if (typeof raw == "string") return {name:raw,value:raw} + else return raw + }) + + try{ + if (this.interaction.responded){ + return {success:false} + }else{ + await this.interaction.respond(newChoices) + return {success:true} + } + }catch(err){ + process.emit("uncaughtException",err) + return {success:false} + } + } + /**Reply to this autocomplete, but filter choices based on the input of the user. */ + async filteredAutocomplete(choices:(string|discord.ApplicationCommandOptionChoiceData)[]): Promise<{success:boolean}> { + const newChoices: (discord.ApplicationCommandOptionChoiceData)[] = choices.map((raw) => { + if (typeof raw == "string") return {name:raw,value:raw} + else return raw + }) + + const filteredChoices = newChoices.filter((choice) => choice.name.startsWith(this.target.value) || choice.value.toString().startsWith(this.target.value)) + return await this.autocomplete(filteredChoices) + } +} + +/**## ODAutocompleteResponder `class` + * This is an Open Ticket autocomplete responder. + * + * This class manages all workers which are executed when the related autocomplete is triggered. + */ +export class ODAutocompleteResponder extends ODResponderImplementation { + /**The slash command of the autocomplete should match the following regex. */ + cmdMatch: string|RegExp + + constructor(id:ODValidId,cmdMatch:string|RegExp,match:string|RegExp,callback?:ODWorkerCallback,priority?:number,callbackId?:ODValidId){ + super(id,match,callback,priority,callbackId) + this.cmdMatch = cmdMatch + } + + /**Respond to this autocomplete interaction. */ + async respond(instance:ODAutocompleteResponderInstance, source:Source, params:Params){ + //wait for workers to finish + await this.workers.executeWorkers(instance,source,params) + } } \ No newline at end of file diff --git a/src/data/framework/eventLoader.ts b/src/data/framework/eventLoader.ts index 6aa4111..aeda57d 100644 --- a/src/data/framework/eventLoader.ts +++ b/src/data/framework/eventLoader.ts @@ -209,6 +209,10 @@ export const loadAllEvents = () => { "afterDropdownRespondersLoaded", "onModalResponderLoad", "afterModalRespondersLoaded", + "onContextMenuResponderLoad", + "afterContextMenuRespondersLoaded", + "onAutocompleteResponderLoad", + "afterAutocompleteRespondersLoaded", //plugin loading before finalizations "onPluginBeforeFinalizationLoad", diff --git a/src/index.ts b/src/index.ts index be21530..c6e0c8c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -710,6 +710,22 @@ const main = async () => { await opendiscord.events.get("onModalResponderLoad").emit([opendiscord.responders.modals,opendiscord.responders,opendiscord.actions]) await opendiscord.events.get("afterModalRespondersLoaded").emit([opendiscord.responders.modals,opendiscord.responders,opendiscord.actions]) + //load context menu responders + opendiscord.log("Loading context menu responders...","system") + if (opendiscord.defaults.getDefault("contextMenuRespondersLoading")){ + //TODO!! + } + await opendiscord.events.get("onContextMenuResponderLoad").emit([opendiscord.responders.contextMenus,opendiscord.responders,opendiscord.actions]) + await opendiscord.events.get("afterContextMenuRespondersLoaded").emit([opendiscord.responders.contextMenus,opendiscord.responders,opendiscord.actions]) + + //load autocomplete responders + opendiscord.log("Loading autocomplete responders...","system") + if (opendiscord.defaults.getDefault("autocompleteRespondersLoading")){ + //TODO!! + } + await opendiscord.events.get("onAutocompleteResponderLoad").emit([opendiscord.responders.autocomplete,opendiscord.responders,opendiscord.actions]) + await opendiscord.events.get("afterAutocompleteRespondersLoaded").emit([opendiscord.responders.autocomplete,opendiscord.responders,opendiscord.actions]) + //plugin loading before finalizations await opendiscord.events.get("onPluginBeforeFinalizationLoad").emit([]) await opendiscord.events.get("afterPluginBeforeFinalizationLoaded").emit([]) @@ -871,7 +887,7 @@ const main = async () => { await opendiscord.startscreen.renderAllComponents() if (opendiscord.languages.getLanguageMetadata(false)?.automated){ console.log("===================") - opendiscord.log("You are currently using a language which has been translated by Google Translate!","warning") + opendiscord.log("You are using a language which has been translated using Google Translate or AI!","warning") opendiscord.log("Please help us improve the translation by contributing to our project!","warning") console.log("===================") }