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.",
async run({guild, channel, author}) {
if (isAuthorized(guild, channel)) {
function getShopEmbed(selection: ShopItem[], title = "Shop") {
function getShopEmbed(selection: ShopItem[], title: string) {
const fields: EmbedField[] = [];
for (const item of selection)
@ -32,17 +32,15 @@ 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 pageAmount = shopPages.length;
const msg = await channel.send(getShopEmbed(shopPages[0], `Shop (Page 1 of ${pageAmount})`));
const shopPages = split(ShopItems, 5);
const pageAmount = shopPages.length;
paginate(msg, author.id, pageAmount, (page) => {
msg.edit(getShopEmbed(shopPages[page], `Shop (Page ${page + 1} of ${pageAmount})`));
});
}
paginate(channel, author.id, pageAmount, (page, hasMultiplePages) => {
return getShopEmbed(
shopPages[page],
hasMultiplePages ? `Shop (Page ${page + 1} of ${pageAmount})` : "Shop"
);
});
}
}
});

View file

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

View file

@ -1,5 +1,14 @@
// 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 FileManager from "./storage";
import {eventListeners} from "../events/messageReactionRemove";
@ -36,57 +45,69 @@ export function updateGlobalEmoteRegistry(): void {
// 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.
export async function paginate(
message: Message,
channel: TextChannel | DMChannel | NewsChannel,
senderID: string,
total: number,
callback: (page: number) => void,
callback: (page: number, hasMultiplePages: boolean) => MessageOptions & {split?: false},
duration = 60000
) {
let page = 0;
const turn = (amount: number) => {
page += amount;
const hasMultiplePages = total > 1;
const message = await channel.send(callback(0, hasMultiplePages));
if (page < 0) page += total;
else if (page >= total) page -= total;
if (hasMultiplePages) {
let page = 0;
const turn = (amount: number) => {
page += amount;
callback(page);
};
const BACKWARDS_EMOJI = "⬅️";
const FORWARDS_EMOJI = "➡️";
const handle = (emote: string, reacterID: string) => {
switch (emote) {
case BACKWARDS_EMOJI:
turn(-1);
break;
case FORWARDS_EMOJI:
turn(1);
break;
}
};
if (page < 0) page += total;
else if (page >= total) page -= total;
// Listen for reactions and call the handler.
let backwardsReaction = await message.react(BACKWARDS_EMOJI);
let forwardsReaction = await message.react(FORWARDS_EMOJI);
eventListeners.set(message.id, handle);
await message.awaitReactions(
(reaction, user) => {
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.
// 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);
handle(reaction.emoji.name, user.id);
if (canDeleteEmotes) reaction.users.remove(user);
message.edit(callback(page, true));
};
const BACKWARDS_EMOJI = "⬅️";
const FORWARDS_EMOJI = "➡️";
const handle = (emote: string, reacterID: string) => {
if (senderID === reacterID) {
switch (emote) {
case BACKWARDS_EMOJI:
turn(-1);
break;
case FORWARDS_EMOJI:
turn(1);
break;
}
}
};
return false;
},
{time: duration}
);
// When time's up, remove the bot's own reactions.
eventListeners.delete(message.id);
backwardsReaction.users.remove(message.author);
forwardsReaction.users.remove(message.author);
// Listen for reactions and call the handler.
let backwardsReaction = await message.react(BACKWARDS_EMOJI);
let forwardsReaction = await message.react(FORWARDS_EMOJI);
eventListeners.set(message.id, handle);
const collector = message.createReactionCollector(
(reaction, user) => {
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.
// 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);
handle(reaction.emoji.name, user.id);
if (canDeleteEmotes) reaction.users.remove(user);
collector.resetTimer();
}
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}
);
// When time's up, remove the bot's own reactions.
collector.on("end", () => {
eventListeners.delete(message.id);
backwardsReaction.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).