UNPKG

@novelbrasil/discord.js-embed-menu

Version:

Easily create Discord.js embed menus with reactions and unlimited customisable pages.

321 lines (320 loc) 15.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DiscordEmbedMenu = void 0; const events_1 = require("events"); const discord_js_1 = require("discord.js"); const discord_embed_menu_page_1 = require("./discord_embed_menu_page"); class DiscordEmbedMenu extends events_1.EventEmitter { constructor(interaction, pages, timeout = 300000, deleteOnTimeout = true, mention = false, keepUserReactionOnStop = true, loadingMessage) { super(); this.menu = null; this.reactionCollector = null; this.componentCollector = null; this.data = {}; this.interaction = interaction; this.channel = interaction.channel; this.user = interaction.user; this.timeout = timeout; this.deleteOnTimeout = deleteOnTimeout; this.mention = mention; this.keepUserReactionOnStop = keepUserReactionOnStop; this.loadingMessage = loadingMessage || DiscordEmbedMenu.LOADING_MESSAGE; this.isDM = !this.channel || this.channel.isDMBased(); this.userTag = '<@' + this.user.id + '>'; this.pages = []; for (let i = 0, l = pages.length; i < l; i++) { let page = pages[i]; this.pages.push(page instanceof discord_embed_menu_page_1.DiscordEmbedMenuPage ? page : new discord_embed_menu_page_1.DiscordEmbedMenuPage(page.name, page.content, page.reactions, i, page.buttons)); } this.currentPage = this.pages[0]; this.pageIndex = 0; } start(options) { return __awaiter(this, void 0, void 0, function* () { return yield this.setPage(0, options); }); } stop() { return __awaiter(this, void 0, void 0, function* () { this.stopReactions(false); if (this.menu && this.keepUserReactionOnStop) { if (this.menu instanceof discord_js_1.Message) this.menu.reactions.cache.forEach((reaction) => __awaiter(this, void 0, void 0, function* () { if (this.menu && this.menu.client && this.menu.client.user) { yield reaction.users.remove(this.menu.client.user.id); } })); } else if (!this.isDM) { return yield this.clearReactions(); } }); } delete() { return __awaiter(this, void 0, void 0, function* () { this.stopReactions(false); if (this.menu) { return yield this.menu.delete(); } }); } clearReactions() { return __awaiter(this, void 0, void 0, function* () { if (this.menu && !this.isDM && this.menu instanceof discord_js_1.Message) { return this.menu.reactions.removeAll(); } }); } setPage() { return __awaiter(this, arguments, void 0, function* (page = 0, options) { if (typeof (page) === 'string') { let pageIndex = this.pages.findIndex(p => p.name === page); if (pageIndex != -1) { page = pageIndex; } else { throw new Error(`Page "${page}" not found!`); } } this.emit('page-changing', this.pageIndex, this.currentPage, page, this.pages[page]); this.pageIndex = page; this.currentPage = this.pages[this.pageIndex]; let content = (!this.isDM && this.mention ? this.userTag : ''); let loadingEmbed = new discord_js_1.EmbedBuilder({ title: this.currentPage.content.data.title, description: this.loadingMessage }); if (this.isDM) { if (this.menu) { yield this.menu.delete(); this.menu = null; } if (this.channel && this.channel instanceof discord_js_1.BaseGuildTextChannel) { this.menu = yield this.channel.send({ content, embeds: [loadingEmbed] }); } else { this.menu = yield this.user.send({ content, embeds: [loadingEmbed] }); this.channel = this.menu.channel; } } else { if (this.menu) { yield this.menu.edit({ content, embeds: [loadingEmbed], components: [] }); } else { if (options === null || options === void 0 ? void 0 : options.reply) this.menu = yield this.interaction.reply({ content, embeds: [loadingEmbed], components: [] }); else if (options === null || options === void 0 ? void 0 : options.followUp) this.menu = yield this.interaction.followUp({ content, embeds: [loadingEmbed], components: [] }); else if (this.channel instanceof discord_js_1.BaseGuildTextChannel) this.menu = yield this.channel.send({ content, embeds: [loadingEmbed], components: [] }); } } if (this.currentPage.reactions) { this.stopReactions(true); yield this.addReactions(); this.awaitReactions(); } const components = []; if (this.currentPage.buttons) { const buttons = this.currentPage.buttons; for (let i = 0; i < Object.keys(buttons).length; i++) if (i % 5 == 0) components.push(new discord_js_1.ActionRowBuilder()); for (const row of components) { for (const button of Object.values(buttons)) { row.addComponents(button.button); } } } if (!this.menu) throw new Error('Menu is not defined, cannot edit it.'); this.menu = yield this.menu.edit({ content, embeds: [this.currentPage.content], components }); if (this.currentPage.buttons) { yield this.awaitButtons(); } this.emit('page-changed', this.pageIndex, this.currentPage); }); } addReactions() { return __awaiter(this, void 0, void 0, function* () { let reactions = []; if (this.menu && this.menu instanceof discord_js_1.Message) { for (let reaction in this.currentPage.reactions) { reactions.push(yield this.menu.react(reaction)); } } return reactions; }); } stopReactions(triggerEnd = true) { if (this.reactionCollector) { if (!triggerEnd) { this.reactionCollector.removeAllListeners(); } this.reactionCollector.stop(); this.reactionCollector = null; } } awaitButtons() { return __awaiter(this, void 0, void 0, function* () { var _a; if (this.menu && this.menu instanceof discord_js_1.Message) { const filter = (_interaction) => { return _interaction.user.id === this.user.id; }; try { const component = yield this.menu.awaitMessageComponent({ filter, time: this.timeout, componentType: discord_js_1.ComponentType.Button }); if (!component) return; yield component.deferUpdate(); const key = Object.prototype.hasOwnProperty.call(this.currentPage.buttons, component.customId) ? component.customId : Object.prototype.hasOwnProperty.call(this.currentPage.buttons, component.id) ? component.id : null; if (key && this.menu && this.menu instanceof discord_js_1.Message) { if (component.user.id !== this.user.id) return; if (!this.currentPage.buttons) return; if (typeof this.currentPage.buttons[key].action !== 'string') { this.currentPage.buttons[key].action(this); } switch (this.currentPage.buttons[key].action) { case "first": this.setPage(0); break; case "last": this.setPage(this.pages.length - 1); break; case 'previous': { if (this.pageIndex > 0) { this.setPage(this.pageIndex - 1); } break; } case 'next': { if (this.pageIndex < this.pages.length - 1) { this.setPage(this.pageIndex + 1); } break; } case 'delete': { this.delete(); break; } default: { this.setPage(this.pages.findIndex(p => this.currentPage.buttons && p.name === this.currentPage.buttons[key].action)); break; } } } } catch (error) { if (!this.isDM) { if (this.deleteOnTimeout) { yield this.delete(); } else { yield ((_a = this.menu) === null || _a === void 0 ? void 0 : _a.edit({ components: [] })); } } } } }); } awaitReactions() { if (this.menu && this.menu instanceof discord_js_1.Message) { const filter = (_reaction, user) => { return this.menu != null && this.menu.client != null && this.menu.client.user != null && user.id != this.menu.client.user.id; }; this.reactionCollector = this.menu.createReactionCollector({ filter, time: this.timeout }); let reactionsChanged; this.reactionCollector.on('end', (reactions) => __awaiter(this, void 0, void 0, function* () { var _a; if (!this.isDM) { if (reactions) { if (reactionsChanged) { return yield this.clearReactions(); } else if (this.menu) { yield ((_a = reactions.at(0)) === null || _a === void 0 ? void 0 : _a.users.remove(this.menu.client.users.cache.get(this.user.id))); } } else if (this.deleteOnTimeout) { return yield this.delete(); } else { return yield this.clearReactions(); } } })); this.reactionCollector.on('collect', (reaction, user) => { const reactionName = Object.prototype.hasOwnProperty.call(this.currentPage.reactions, reaction.emoji.name) ? reaction.emoji.name : Object.prototype.hasOwnProperty.call(this.currentPage.reactions, reaction.emoji.id) ? reaction.emoji.id : null; if (user.id !== this.user.id || !Object.keys(this.currentPage.reactions).includes(reactionName)) { return reaction.users.remove(user); } if (reactionName && this.menu && this.menu instanceof discord_js_1.Message) { if (typeof this.currentPage.reactions[reactionName] === 'function') { // this this flag is not true then the clearReaction() at ligne 188 will be never call when try to change page // also test when no page change it works too reactionsChanged = true; return this.currentPage.reactions[reactionName](this); } switch (this.currentPage.reactions[reactionName]) { case 'first': { reactionsChanged = JSON.stringify(this.menu.reactions.cache.keys()) != JSON.stringify(Object.keys(this.pages[0].reactions)); this.setPage(0); break; } case 'last': { reactionsChanged = JSON.stringify(this.menu.reactions.cache.keys()) != JSON.stringify(Object.keys(this.pages[this.pages.length - 1].reactions)); this.setPage(this.pages.length - 1); break; } case 'previous': { if (this.pageIndex > 0) { reactionsChanged = JSON.stringify(this.menu.reactions.cache.keys()) != JSON.stringify(Object.keys(this.pages[this.pageIndex - 1].reactions)); this.setPage(this.pageIndex - 1); } break; } case 'next': { if (this.pageIndex < this.pages.length - 1) { reactionsChanged = JSON.stringify(this.menu.reactions.cache.keys()) != JSON.stringify(Object.keys(this.pages[this.pageIndex + 1].reactions)); this.setPage(this.pageIndex + 1); } break; } case 'stop': { this.stop(); break; } case 'delete': { this.delete(); break; } default: { reactionsChanged = JSON.stringify(this.menu.reactions.cache.keys()) != JSON.stringify(Object.keys(this.pages.find(p => p.name === this.currentPage.reactions[reactionName]).reactions)); this.setPage(this.pages.findIndex(p => p.name === this.currentPage.reactions[reactionName])); break; } } } }); } } } exports.DiscordEmbedMenu = DiscordEmbedMenu; DiscordEmbedMenu.REQUIRED_PERMS = ['SendMessages', 'EmbedLinks', 'AddReactions', 'ManageMessages']; DiscordEmbedMenu.LOADING_MESSAGE = 'Carregando, por favor seja paciente...';