UNPKG

@joshbrucker/discordjs-utils

Version:

A set of utility classes and functions to aid with discord.js bot development. Paged embeds, emoji utilities, and more!

178 lines (177 loc) 6.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PagedEmbed = exports.PagedEmbedSendError = void 0; const discord_js_1 = require("discord.js"); const v10_1 = require("discord-api-types/v10"); const PagedEmbedOptions_1 = require("./PagedEmbedOptions"); const errorHandlers_js_1 = require("../utils/errorHandlers.js"); class PagedEmbedSendError extends Error { constructor(message) { super(message); this.name = "PagedEmbedSendError"; } } exports.PagedEmbedSendError = PagedEmbedSendError; /* Allows for creation and customization of "paged" embeds, where Discord users can click buttons to page through a list of embeds. */ class PagedEmbed { static BACK_ID = "back"; static FORWARD_ID = "forward"; timeout; leftEmoji; rightEmoji; leftStyle; rightStyle; showPageNumbers; wrapAround; resetTimerOnPress; collector; backButton; forwardButton; constructor(options) { options = { ...PagedEmbedOptions_1.DEFAULT_OPTIONS, ...options }; this.timeout = options.timeout; this.leftEmoji = options.leftEmoji; this.rightEmoji = options.rightEmoji; this.leftStyle = options.leftStyle; this.rightStyle = options.rightStyle; this.showPageNumbers = options.showPageNumbers; this.wrapAround = options.wrapAround; this.resetTimerOnPress = options.resetTimerOnPress; this.backButton = new discord_js_1.ButtonBuilder(); this.forwardButton = new discord_js_1.ButtonBuilder(); } setTimeout(timeout) { this.timeout = timeout; return this; } setLeftEmoji(leftEmoji) { this.leftEmoji = leftEmoji; return this; } setRightEmoji(rightEmoji) { this.rightEmoji = rightEmoji; return this; } setLeftStyle(leftStyle) { this.leftStyle = leftStyle; return this; } setRightStyle(rightStyle) { this.rightStyle = rightStyle; return this; } withShowPageNumbers(showPageNumbers) { this.showPageNumbers = showPageNumbers; return this; } withWrapAround(wrapAround) { this.wrapAround = wrapAround; return this; } withResetTimerOnPress(resetTimerOnPress) { this.resetTimerOnPress = resetTimerOnPress; return this; } /* Expires the paged embed, making the buttons no longer clickable */ expire() { this.collector?.stop(); } /* Resets the timer that runs to expire the paged embed. */ resetTimer(newTimeout) { this.collector?.resetTimer({ time: newTimeout || this.timeout }); } /* Sends a the paged embed with the given embed list and attachments. */ async send(interaction, embeds, attachments = [], startIndex = 0) { if (embeds.length === 0) { throw new PagedEmbedSendError("Embed list size must be at least 1."); } if (startIndex < 0 || startIndex >= embeds.length) { throw new PagedEmbedSendError("startIndex must be within bounds of embed list size."); } // Hydrate embeds with current page number over total page numbers, if requested if (this.showPageNumbers) { for (let i = 0; i < embeds.length; i++) { const embed = embeds[i]; embed.setFooter({ text: "\u200b\n" + `Page ${i + 1} / ${embeds.length}` + (embed.data.footer ? embed.data.footer.text : ""), iconURL: embed.data.footer?.icon_url, }); } } // Don't set any buttons if there is only one embed if (embeds.length === 1) { await interaction.reply({ embeds: [embeds[0]], files: attachments, }); return; } this.backButton .setStyle(this.leftStyle) .setEmoji(this.leftEmoji) .setCustomId(PagedEmbed.BACK_ID); this.forwardButton .setStyle(this.rightStyle) .setEmoji(this.rightEmoji) .setCustomId(PagedEmbed.FORWARD_ID); const getButtonRow = (currentIndex, embedCount) => { const showBackButton = currentIndex > 0 || this.wrapAround; const showForwardButton = currentIndex < embedCount - 1 || this.wrapAround; return new discord_js_1.ActionRowBuilder().addComponents(...(showBackButton ? [this.backButton] : []), ...(showForwardButton ? [this.forwardButton] : [])); }; let currentIndex = startIndex; const interactionResponse = await interaction.reply({ embeds: [embeds[currentIndex]], files: attachments, components: [getButtonRow(currentIndex, embeds.length)], withResponse: true, }); const message = interactionResponse.resource?.message; if (message) { this.collector = message.createMessageComponentCollector({ time: this.timeout, }); this.collector.on("collect", async (buttonInteraction) => { if (this.resetTimerOnPress) { this.resetTimer(); } if (buttonInteraction.customId === PagedEmbed.BACK_ID) { currentIndex -= 1; } else if (buttonInteraction.customId === PagedEmbed.FORWARD_ID) { currentIndex += 1; } // Handles wrap around cases from both directions. currentIndex = ((currentIndex % embeds.length) + embeds.length) % embeds.length; await buttonInteraction .update({ embeds: [embeds[currentIndex]], components: [getButtonRow(currentIndex, embeds.length)], }) .catch((0, errorHandlers_js_1.ignore)([v10_1.RESTJSONErrorCodes.UnknownInteraction])); }); this.collector.on("end", async () => { this.backButton.setDisabled(true); this.forwardButton.setDisabled(true); await interaction .editReply({ components: [getButtonRow(currentIndex, embeds.length)], }) .catch((0, errorHandlers_js_1.ignore)([v10_1.RESTJSONErrorCodes.UnknownMessage])); }); } } } exports.PagedEmbed = PagedEmbed;