@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
JavaScript
"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;
;