UNPKG

@notoiro/djs-button-pages

Version:

A simple yet powerful module for implementing customizable embed pages with buttons in Discord chat. Works only with Discord.js.

323 lines (322 loc) 12.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const discord_js_1 = require("discord.js"); const Constants_1 = __importDefault(require("../Enums/Constants")); const Utils_1 = require("../Utils/Utils"); const PaginationSent_1 = __importDefault(require("./PaginationSent")); /** * Class that wraps pagination. */ class PaginationWrapper { _buttons = []; _embeds = []; _time; _filterOptions = {}; _afterSendingAction; _beforeStopAction; _afterStopAction; /** * Class that wraps pagination. * @param {PaginationData} data Data from which to build pagination. */ constructor(data) { if (data) this.overrideData(data); } ; /** * @returns {Array<ButtonWrapper>} Buttons for pagination. */ get buttons() { return this._buttons; } ; /** * @returns {Array<APIEmbed>} Embeds for pagination. */ get embeds() { return this._embeds.map((embed) => embed.data); } ; /** * @returns {FilterOptions} Options for filtering out interactions. */ get filterOptions() { return this._filterOptions; } ; /** * @returns {number} Time that the pagination will be alive for. */ get time() { return this._time; } ; /** * @returns {AfterSendingAction} Action that is called after sending. */ get afterSendingAction() { return this._afterSendingAction; } ; /** * @returns {StopAction} Action that is called before the pagination will be stopped. */ get beforeStopAction() { return this._beforeStopAction; } ; /** * @returns {StopAction} Action that is called after the pagination is stopped. */ get afterStopAction() { return this._afterStopAction; } ; /** * Gets button by it's customId. * @param {string} custom_id Custom id. * @returns {ButtonWrapper | undefined} Button. */ getButtonByCustomId(custom_id) { return this._buttons.find((button) => button.data.custom_id === custom_id); } ; /** * Sets action that will be called after sending. * @param {AfterSendingAction} action Action. * @returns {this} */ setAfterSendingAction(action) { this._afterSendingAction = action; return this; } ; /** * Sets action that will be called before the pagination is stopped. * @param {StopAction} action Action. * @returns {this} */ setBeforeStopAction(action) { this._beforeStopAction = action; return this; } ; /** * Sets action that will be called after the pagination is stopped. * @param {StopAction} action Action. * @returns {this} */ setAfterStopAction(action) { this._afterStopAction = action; return this; } ; /** * Sets time that the pagination will be alive for. * @param {number} time Time. * @param {boolean} bypassLimits Should the time bypass limits or not. * @returns {this} */ setTime(time, bypassLimits = false) { if (time < 0 || !Number.isInteger(time)) throw new Error("[DJS-Button-Pages]: Time should be integer!"); if (!bypassLimits && time < Constants_1.default.LibraryMinPageLifeTime) throw new Error("[DJS-Button-Pages]: Pagination should exist at least one second!"); if (!bypassLimits && time > Constants_1.default.LibraryMaxPageLifeTime) throw new RangeError("[DJS-Button-Pages]: Pagination total life time should be no more than an hour due to optimization. If you want to bypass the limit, pass true as the second argument to this method."); this._time = time; return this; } ; /** * Sets embeds for the pagination. * @param {Array<Embed | EmbedBuilder | APIEmbed>} embeds Embeds. * @returns {this} */ setEmbeds(embeds) { const embedBuilders = embeds.map((embed) => discord_js_1.EmbedBuilder.from(embed)); if (embedBuilders.some((embed) => (0, Utils_1.getEmbedLength)(embed.data) <= 0)) throw new Error("[DJS-Button-Pages]: No embeds from the array can be empty!"); if (embedBuilders.some((embed) => (0, Utils_1.getEmbedLength)(embed.data) > Constants_1.default.DiscordMaxEmbedLength)) throw new RangeError(`[DJS-Button-Pages]: No embeds from the array can be longer than ${Constants_1.default.DiscordMaxEmbedLength}.`); this._embeds = embedBuilders; return this; } ; /** * Sets buttons for the pagination. * @param {ButtonWrapper | Array<ButtonWrapper>} buttons Buttons. * @returns {this} */ setButtons(buttons) { if (!Array.isArray(buttons)) buttons = [buttons]; if (buttons.length > Constants_1.default.DiscordMaxButtonsPerRow * Constants_1.default.DiscordMaxRowsPerMessage) throw new RangeError(`[DJS-Button-Pages]: There can not be more than ${Constants_1.default.DiscordMaxButtonsPerRow * Constants_1.default.DiscordMaxRowsPerMessage}.`); if (buttons.some((val) => !val.action || !val.data || !val.switch)) throw new Error("[DJS-Button-Pages]: Buttons can not have empty values."); if (new Set(buttons.map((button) => button.data.custom_id)).size < buttons.length) throw new Error("[DJS-Button-Pages]: Buttons can not have similar customIds."); this._buttons = buttons; return this; } ; /** * Sets options for filtering out interactions. * @param {FilterOptions} options Options for filtering out interactions. * @returns {this} */ setFilterOptions(options) { if (options.maxIdleTime && (!Number.isInteger(options.maxIdleTime) || options.maxIdleTime < 0)) throw new RangeError("[DJS-Button-Pages]: Max collector's idle time should be a natural number!"); if (options.maxInteractions && (!Number.isInteger(options.maxInteractions) || options.maxInteractions < 0)) throw new RangeError("[DJS-Button-Pages]: Max number of interactions should be a natural number!"); if (options.maxUsers && (!Number.isInteger(options.maxUsers) || options.maxUsers < 0)) throw new RangeError("[DJS-Button-Pages]: Max number of users should be a natural number!"); if (typeof options.noAccessReplyContent === "string" && options.noAccessReplyContent.length < 1) throw new Error("[DJS-Button-Pages]: Reply should be longer than zero symbols."); this._filterOptions = options; return this; } ; /** * Sets allowed users for pagination. * @param {Array<Snowflake>} users User's snowflake. * @returns {this} */ setAllowedUsers(users) { this._filterOptions.allowedUsers = users; return this; } ; /** * Adds user(-s) to allowed list. * @param {Snowflake | Array<Snowflake>} users User(-s). * @returns {this} */ addAllowedUsers(users) { if (!Array.isArray(users)) users = [users]; if (!this._filterOptions.allowedUsers) this._filterOptions.allowedUsers = []; this._filterOptions.allowedUsers.push(...users); return this; } ; /** * Sends pagination to the channel. * @param {TextBasedChannel} channel Channel. * @param {MessageCreateOptions} options Message options. * @param {number} page Page number which will be the starting point. * @returns {Promise<PaginationSent>} Class that represents pagination that is already sent. */ async send(channel, options = {}, page = 0) { if (page < 0 || !Number.isInteger(page)) throw new RangeError("[DJS-Button-Pages]: Page number should be integer!"); if (page > this.embeds.length - 1) { console.warn("[DJS-Button-Pages]: You're passing in page number that is greater than pagination has."); page = this.embeds.length - 1; } ; options.embeds = [this.embeds[page]]; options.components = []; // @ts-ignore const message = await channel.send(options); if (this._afterSendingAction) await this._afterSendingAction(message); const paginationSent = new PaginationSent_1.default(this, message, page, this._beforeStopAction, this._afterStopAction); return paginationSent.init(); } ; /** * Sends pagination as a reply to message. * @param {Message} replyTo Message. * @param {MessageReplyOptions} options Message options. * @param {number} page Page number which will be the starting point. * @returns {Promise<PaginationSent>} Class that represents pagination that is already sent. */ async reply(replyTo, options = {}, page = 0) { if (page < 0 || !Number.isInteger(page)) throw new RangeError("[DJS-Button-Pages]: Page number should be integer!"); if (page > this.embeds.length - 1) { console.warn("[DJS-Button-Pages]: You're passing in page number that is greater than pagination has."); page = this.embeds.length - 1; } ; options.embeds = [this.embeds[page]]; options.components = []; const message = await replyTo.reply(options); if (this._afterSendingAction) await this._afterSendingAction(message); const paginationSent = new PaginationSent_1.default(this, message, page, this._beforeStopAction, this._afterStopAction); return paginationSent.init(); } ; /** * Sends pagination as a reply to interaction. * @param {RepliableInteraction} interaction Interaction. * @param {InteractionReplyOptions} options Reply options. * @param {number} page Page number which will be the starting point. * @returns {Promise<PaginationSent>} Class that represents pagination that is already sent. */ async interactionReply(interaction, options = {}, page = 0) { if (!interaction.deferred) if (options.flags === discord_js_1.MessageFlags.Ephemeral) await interaction.deferReply({ flags: discord_js_1.MessageFlags.Ephemeral }); else await interaction.deferReply(); if (page < 0 || !Number.isInteger(page)) throw new RangeError("[DJS-Button-Pages]: Page number should be integer!"); if (page > this.embeds.length - 1) { console.warn("[DJS-Button-Pages]: You're passing in page number that is greater than pagination has."); page = this.embeds.length - 1; } ; options.embeds = [this.embeds[page]]; options.components = []; // @ts-ignore const reply = await interaction.editReply(options); if (this._afterSendingAction) await this._afterSendingAction(reply); const paginationSent = new PaginationSent_1.default(this, interaction, page, this._beforeStopAction, this._afterStopAction); return paginationSent.init(); } ; /** * Transforms class to JSON-like object. * @returns {PaginationData} JSON-like object. */ toJSON() { return { embeds: this.embeds, buttons: this.buttons, time: this.time, filterOptions: this.filterOptions, }; } ; /** * Overrides pagination data. * @param {Partial<PaginationData>} data Pagination data. * @returns {void} */ overrideData(data) { const { embeds, buttons, filterOptions, time } = data; if (embeds) this.setEmbeds(embeds); if (buttons) this.setButtons(buttons); if (filterOptions) this.setFilterOptions(filterOptions); if (time) this.setTime(time); return; } ; } exports.default = PaginationWrapper; ;