Reworked paginate function

This commit is contained in:
WatDuhHekBro 2021-03-30 07:16:31 -05:00
parent 475ecb3d5d
commit 02c18f57c7
3 changed files with 83 additions and 76 deletions

View file

@ -10,7 +10,7 @@ export const ShopCommand = new Command({
description: "Displays the list of items you can buy in the shop.", description: "Displays the list of items you can buy in the shop.",
async run({guild, channel, author}) { async run({guild, channel, author}) {
if (isAuthorized(guild, channel)) { if (isAuthorized(guild, channel)) {
function getShopEmbed(selection: ShopItem[], title = "Shop") { function getShopEmbed(selection: ShopItem[], title: string) {
const fields: EmbedField[] = []; const fields: EmbedField[] = [];
for (const item of selection) for (const item of selection)
@ -32,19 +32,17 @@ export const ShopCommand = new Command({
}; };
} }
// In case there's just one page, omit unnecessary details.
if (ShopItems.length <= 5) channel.send(getShopEmbed(ShopItems));
else {
const shopPages = split(ShopItems, 5); const shopPages = split(ShopItems, 5);
const pageAmount = shopPages.length; const pageAmount = shopPages.length;
const msg = await channel.send(getShopEmbed(shopPages[0], `Shop (Page 1 of ${pageAmount})`));
paginate(msg, author.id, pageAmount, (page) => { paginate(channel, author.id, pageAmount, (page, hasMultiplePages) => {
msg.edit(getShopEmbed(shopPages[page], `Shop (Page ${page + 1} of ${pageAmount})`)); return getShopEmbed(
shopPages[page],
hasMultiplePages ? `Shop (Page ${page + 1} of ${pageAmount})` : "Shop"
);
}); });
} }
} }
}
}); });
export const BuyCommand = new Command({ export const BuyCommand = new Command({

View file

@ -93,33 +93,21 @@ async function displayEmoteList(emotes: GuildEmoji[], channel: TextChannel | DMC
}); });
const sections = split(emotes, 20); const sections = split(emotes, 20);
const pages = sections.length; const pages = sections.length;
const embed = new MessageEmbed().setTitle("**Emotes**").setColor("AQUA"); const embed = new MessageEmbed().setColor("AQUA");
let desc = "";
// Gather the first page (if it even exists, which it might not if there no valid emotes appear) // Gather the first page (if it even exists, which it might not if there no valid emotes appear)
if (pages > 0) { if (pages > 0) {
for (const emote of sections[0]) { paginate(channel, author.id, pages, (page, hasMultiplePages) => {
desc += `${emote} ${emote.name} (**${emote.guild.name}**)\n`; embed.setTitle(hasMultiplePages ? `**Emotes** (Page ${page + 1} of ${pages})` : "**Emotes**");
}
embed.setDescription(desc);
if (pages > 1) {
embed.setTitle(`**Emotes** (Page 1 of ${pages})`);
const msg = await channel.send({embed});
paginate(msg, author.id, pages, (page) => {
let desc = ""; let desc = "";
for (const emote of sections[page]) { for (const emote of sections[page]) {
desc += `${emote} ${emote.name} (**${emote.guild.name}**)\n`; desc += `${emote} ${emote.name} (**${emote.guild.name}**)\n`;
} }
embed.setTitle(`**Emotes** (Page ${page + 1} of ${pages})`);
embed.setDescription(desc); embed.setDescription(desc);
msg.edit(embed);
return embed;
}); });
} else {
channel.send({embed});
}
} else { } else {
channel.send("No valid emotes found by that query."); channel.send("No valid emotes found by that query.");
} }

View file

@ -1,5 +1,14 @@
// Library for Discord-specific functions // Library for Discord-specific functions
import {Message, Guild, GuildMember, Permissions} from "discord.js"; import {
Message,
Guild,
GuildMember,
Permissions,
TextChannel,
DMChannel,
NewsChannel,
MessageOptions
} from "discord.js";
import {get} from "https"; import {get} from "https";
import FileManager from "./storage"; import FileManager from "./storage";
import {eventListeners} from "../events/messageReactionRemove"; import {eventListeners} from "../events/messageReactionRemove";
@ -36,12 +45,16 @@ export function updateGlobalEmoteRegistry(): void {
// Pagination function that allows for customization via a callback. // Pagination function that allows for customization via a callback.
// Define your own pages outside the function because this only manages the actual turning of pages. // Define your own pages outside the function because this only manages the actual turning of pages.
export async function paginate( export async function paginate(
message: Message, channel: TextChannel | DMChannel | NewsChannel,
senderID: string, senderID: string,
total: number, total: number,
callback: (page: number) => void, callback: (page: number, hasMultiplePages: boolean) => MessageOptions & {split?: false},
duration = 60000 duration = 60000
) { ) {
const hasMultiplePages = total > 1;
const message = await channel.send(callback(0, hasMultiplePages));
if (hasMultiplePages) {
let page = 0; let page = 0;
const turn = (amount: number) => { const turn = (amount: number) => {
page += amount; page += amount;
@ -49,11 +62,12 @@ export async function paginate(
if (page < 0) page += total; if (page < 0) page += total;
else if (page >= total) page -= total; else if (page >= total) page -= total;
callback(page); message.edit(callback(page, true));
}; };
const BACKWARDS_EMOJI = "⬅️"; const BACKWARDS_EMOJI = "⬅️";
const FORWARDS_EMOJI = "➡️"; const FORWARDS_EMOJI = "➡️";
const handle = (emote: string, reacterID: string) => { const handle = (emote: string, reacterID: string) => {
if (senderID === reacterID) {
switch (emote) { switch (emote) {
case BACKWARDS_EMOJI: case BACKWARDS_EMOJI:
turn(-1); turn(-1);
@ -62,31 +76,38 @@ export async function paginate(
turn(1); turn(1);
break; break;
} }
}
}; };
// Listen for reactions and call the handler. // Listen for reactions and call the handler.
let backwardsReaction = await message.react(BACKWARDS_EMOJI); let backwardsReaction = await message.react(BACKWARDS_EMOJI);
let forwardsReaction = await message.react(FORWARDS_EMOJI); let forwardsReaction = await message.react(FORWARDS_EMOJI);
eventListeners.set(message.id, handle); eventListeners.set(message.id, handle);
await message.awaitReactions( const collector = message.createReactionCollector(
(reaction, user) => { (reaction, user) => {
if (user.id === senderID) { if (user.id === senderID) {
// The reason this is inside the call is because it's possible to switch a user's permissions halfway and suddenly throw an error. // The reason this is inside the call is because it's possible to switch a user's permissions halfway and suddenly throw an error.
// This will dynamically adjust for that, switching modes depending on whether it currently has the "Manage Messages" permission. // This will dynamically adjust for that, switching modes depending on whether it currently has the "Manage Messages" permission.
const canDeleteEmotes = botHasPermission(message.guild, Permissions.FLAGS.MANAGE_MESSAGES); const canDeleteEmotes = botHasPermission(message.guild, Permissions.FLAGS.MANAGE_MESSAGES);
handle(reaction.emoji.name, user.id); handle(reaction.emoji.name, user.id);
if (canDeleteEmotes) reaction.users.remove(user); if (canDeleteEmotes) reaction.users.remove(user);
collector.resetTimer();
} }
return false; return false;
}, },
// Apparently, regardless of whether you put "time" or "idle", it won't matter to the collector.
// In order to actually reset the timer, you have to do it manually via collector.resetTimer().
{time: duration} {time: duration}
); );
// When time's up, remove the bot's own reactions. // When time's up, remove the bot's own reactions.
collector.on("end", () => {
eventListeners.delete(message.id); eventListeners.delete(message.id);
backwardsReaction.users.remove(message.author); backwardsReaction.users.remove(message.author);
forwardsReaction.users.remove(message.author); forwardsReaction.users.remove(message.author);
});
}
} }
// Waits for the sender to either confirm an action or let it pass (and delete the message). // Waits for the sender to either confirm an action or let it pass (and delete the message).