From 6d984890381b267829df2199f993c75b5661d1d3 Mon Sep 17 00:00:00 2001 From: WubzyGD Date: Fri, 8 Jan 2021 12:27:48 -0700 Subject: [PATCH] Finish pagination class --- commands/testpage.js | 44 +++++++++++++++++ package-lock.json | 34 ++++++++++--- package.json | 1 + util/pagination.d.ts | 24 +++++++++- util/pagination.js | 82 ++++++++++++++++++++++++++++++-- util/ts/pagination.ts | 108 +++++++++++++++++++++++++++++++++++++++--- 6 files changed, 274 insertions(+), 19 deletions(-) create mode 100644 commands/testpage.js diff --git a/commands/testpage.js b/commands/testpage.js new file mode 100644 index 0000000..b2562dd --- /dev/null +++ b/commands/testpage.js @@ -0,0 +1,44 @@ +const Discord = require('discord.js'); +const {Pagination} = require('../util/pagination'); + +module.exports = { + name: "testpage", + aliases: ['tp'], + meta: { + category: "", + perms: "", + staff: false, + vip: "", + serverPerms: [], + writtenBy: "", + serverOnly: false + }, + tags: [], + help: new Discord.MessageEmbed() + .setTitle("Help -> ") + .setDescription("") + .addField("Syntax", "``"), + async execute(message, msg, args, cmd, prefix, mention, client) { + let p = await new Pagination(message.channel, [ + new Discord.MessageEmbed() + .setTitle("bonk") + .setDescription("bonk horny jail") + .addField("bonk", "you have been bonked") + .setColor('c375f0'), + new Discord.MessageEmbed() + .setTitle("stonks") + .setDescription("yeet") + .setColor('c375f0'), + new Discord.MessageEmbed() + .setTitle("honks") + .setDescription("such wow many honks") + .addField("aye", "lul text") + .setColor('c375f0'), + new Discord.MessageEmbed() + .setTitle("yoink") + .setDescription("give me the vibes") + .addField("vibecheck", "your vibe will now be checked.") + .setColor('c375f0'), + ], message, client).start({endTime: 60000, user: message.author.id}); + } +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 93dd4f3..fa35b8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -806,6 +806,11 @@ "requires": { "has-flag": "^3.0.0" } + }, + "urijs": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", + "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" } } }, @@ -7032,9 +7037,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "inquirer": { "version": "7.3.3", @@ -8777,6 +8782,23 @@ } } }, + "swwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/swwrap/-/swwrap-1.0.0.tgz", + "integrity": "sha512-Hjpa/2giqpQR7Few0RHZ09X7Y/tfvlyuY0dJTVxQ05ifX1SGrbYSo+C28CLJh8owkKxvCgnYmitng6t6UiQSag==", + "requires": { + "@types/node": "^14.14.20", + "node-fetch": "^2.6.1", + "typescript": "^3.9.7" + }, + "dependencies": { + "@types/node": { + "version": "14.14.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz", + "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==" + } + } + }, "tar": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", @@ -9024,9 +9046,9 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "urijs": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", - "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.5.tgz", + "integrity": "sha512-48z9VGWwdCV5KfizHsE05DWS5fhK6gFlx5MjO7xu0Krc5FGPWzjlXEVV0nPMrdVuP7xmMHiPZ2HoYZwKOFTZOg==" }, "url-parse": { "version": "1.4.7", diff --git a/package.json b/package.json index de3ec0a..869f89d 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "node-fetch": "^2.6.1", "sequelize": "^5.22.3", "sqlite3": "^4.2.0", + "swwrap": "^1.0.0", "winston": "^3.3.3", "ytdl-core": "^3.2.2", "ytdl-core-discord": "^1.2.1" diff --git a/util/pagination.d.ts b/util/pagination.d.ts index 6b1c5a9..66739de 100644 --- a/util/pagination.d.ts +++ b/util/pagination.d.ts @@ -1,4 +1,4 @@ -import { TextChannel, Message, MessageEmbed, Client } from 'discord.js'; +import { TextChannel, Message, MessageEmbed, Client, ReactionCollector } from 'discord.js'; export declare class Pagination { channel: TextChannel; message: Message; @@ -6,10 +6,30 @@ export declare class Pagination { originalMessage: Message; currentPage: number; client: Client; - constructor(channel: TextChannel, pages: MessageEmbed[], originalMessage: Message, client: Client, message?: Message); + loopPages: boolean; + controllers: ControllerData; + constructor(channel: TextChannel, pages: MessageEmbed[], originalMessage: Message, client: Client, loopPages?: boolean, message?: Message); setPage(page: number): Promise; nextPage(): Promise; prevPage(): Promise; addPage(page: MessageEmbed): Pagination; replacePage(index: number, page: MessageEmbed): Pagination; + setControllers(endTime: number, user?: 'any' | string, extraControls?: ExtraControls): Promise; + updateControllers(): Promise; + endControllers(): Promise; + start(options?: { + endTime?: number; + startPage?: number; + user?: 'any' | string; + }): Promise; + stop(): Promise; } +interface ExtraControls { +} +interface ControllerData { + endTime: number; + enabled: boolean; + lastInteraction: Date; + collector: ReactionCollector; +} +export {}; diff --git a/util/pagination.js b/util/pagination.js index 08d5209..c05268d 100644 --- a/util/pagination.js +++ b/util/pagination.js @@ -2,7 +2,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Pagination = void 0; class Pagination { - constructor(channel, pages, originalMessage, client, message) { + constructor(channel, pages, originalMessage, client, loopPages, message) { + this.loopPages = true; + this.controllers = { enabled: false, endTime: null, collector: null, lastInteraction: null }; this.channel = channel; this.pages = pages; this.originalMessage = message; @@ -11,6 +13,9 @@ class Pagination { if (message) { this.message = message; } + if (loopPages) { + this.loopPages = loopPages; + } } ; async setPage(page) { @@ -25,7 +30,7 @@ class Pagination { this.message = tempm; } } - await this.message.edit(this.pages[page] + await this.message.edit('', this.pages[page] .setFooter(`Natsuki | Page ${page + 1} of ${this.pages.length}`, this.client.user.avatarURL()) .setTimestamp()); this.currentPage = page; @@ -33,12 +38,24 @@ class Pagination { } ; async nextPage() { - await this.setPage(typeof this.currentPage === "number" ? this.currentPage + 1 == this.pages.length ? this.currentPage : this.currentPage + 1 : 0); + await this.setPage(typeof this.currentPage === "number" + ? this.currentPage + 1 == this.pages.length + ? this.loopPages + ? 0 + : this.currentPage + : this.currentPage + 1 + : 0); return this; } ; async prevPage() { - await this.setPage(typeof this.currentPage === "number" ? this.currentPage === 0 ? 0 : this.currentPage - 1 : this.pages.length - 1); + await this.setPage(typeof this.currentPage === "number" + ? this.currentPage === 0 + ? this.loopPages + ? this.pages.length - 1 + : 0 + : this.currentPage - 1 + : this.pages.length - 1); return this; } ; @@ -46,6 +63,7 @@ class Pagination { this.pages.push(page); return this; } + ; replacePage(index, page) { if (index < 0) { throw new RangeError("replacePage() param 'index' must be a value greater than 0"); @@ -56,5 +74,61 @@ class Pagination { this.pages[index] = page; return this; } + ; + async setControllers(endTime, user, extraControls) { + if (this.controllers.enabled) { + return; + } + await this.message.react('⬅'); + await this.message.react('➡'); + await this.message.react('⏹'); + let emoji = ['⬅', '➡', '⏹']; + let filter = user && user.toLowerCase().trim() !== 'any' + ? (r, u) => { return u.id === user.trim() && emoji.includes(r.emoji.name); } + : (r) => { return emoji.includes(r.emoji.name); }; + this.controllers.collector = this.message.createReactionCollector(filter, { time: 450000 }); + this.controllers.collector.on('collect', async (r) => { + console.log(r); + let functions = { + '⬅': () => { return this.prevPage(); }, + '➡': () => { return this.nextPage(); }, + '⏹': () => { return this.endControllers(); } + }; + this.controllers.lastInteraction = new Date(); + return functions[r.emoji.name](); + }); + this.controllers.enabled = true; + this.controllers.endTime = endTime; + this.controllers.lastInteraction = new Date(); + setInterval(() => { + if (new Date().getTime() - this.controllers.lastInteraction.getTime() > this.controllers.endTime) { + return this.endControllers(); + } + }, this.controllers.endTime); + return this; + } + ; + async updateControllers() { return this; } + ; + async endControllers() { + await this.message.reactions.removeAll(); + this.controllers.collector.stop(); + let fe = this.message.embeds[0]; + fe.setDescription(`${fe.description}\n\n*This menu has ended, start a new one to interact with it!*`); + fe.setFooter(`${fe.footer.text} | Menu ended`, this.client.user.avatarURL()); + await this.message.edit(fe); + return this; + } + ; + async start(options) { + await this.setPage(options && options.startPage ? options.startPage : 0); + await this.setControllers(options && options.endTime ? options.endTime : 60, options && options.user ? options.user : 'any'); + return this; + } + ; + async stop() { + return await this.endControllers(); + } + ; } exports.Pagination = Pagination; diff --git a/util/ts/pagination.ts b/util/ts/pagination.ts index 7062b1c..e4d8f24 100644 --- a/util/ts/pagination.ts +++ b/util/ts/pagination.ts @@ -1,4 +1,4 @@ -import {TextChannel, Message, MessageEmbed, Client} from 'discord.js'; +import {TextChannel, Message, MessageEmbed, Client, MessageReaction, ReactionCollector} from 'discord.js'; export class Pagination { channel: TextChannel; @@ -7,10 +7,12 @@ export class Pagination { originalMessage: Message; currentPage: number; client: Client; + loopPages: boolean = true; + controllers: ControllerData = {enabled: false, endTime: null, collector: null, lastInteraction: null}; - constructor (channel: TextChannel, pages: MessageEmbed[], originalMessage: Message, client: Client, message?: Message) { + constructor (channel: TextChannel, pages: MessageEmbed[], originalMessage: Message, client: Client, loopPages?: boolean, message?: Message) { this.channel = channel; this.pages = pages; this.originalMessage = message; @@ -18,6 +20,7 @@ export class Pagination { this.currentPage = 0; if (message) {this.message = message;} + if (loopPages) {this.loopPages = loopPages;} }; @@ -32,7 +35,7 @@ export class Pagination { else {this.message = tempm;} } - await this.message.edit(this.pages[page] + await this.message.edit('', this.pages[page] .setFooter(`Natsuki | Page ${page + 1} of ${this.pages.length}`, this.client.user.avatarURL()) .setTimestamp() ); @@ -42,19 +45,33 @@ export class Pagination { }; public async nextPage(): Promise { - await this.setPage(typeof this.currentPage === "number" ? this.currentPage + 1 == this.pages.length ? this.currentPage : this.currentPage + 1 : 0); + await this.setPage(typeof this.currentPage === "number" + ? this.currentPage + 1 == this.pages.length + ? this.loopPages + ? 0 + : this.currentPage + : this.currentPage + 1 + : 0 + ); return this; }; public async prevPage(): Promise { - await this.setPage(typeof this.currentPage === "number" ? this.currentPage === 0 ? 0 : this.currentPage - 1 : this.pages.length - 1); + await this.setPage(typeof this.currentPage === "number" + ? this.currentPage === 0 + ? this.loopPages + ? this.pages.length - 1 + : 0 + : this.currentPage - 1 + : this.pages.length - 1 + ); return this; }; public addPage(page: MessageEmbed): Pagination { this.pages.push(page); return this; - } + }; public replacePage(index: number, page: MessageEmbed): Pagination { if (index < 0) {throw new RangeError("replacePage() param 'index' must be a value greater than 0");} @@ -62,5 +79,82 @@ export class Pagination { this.pages[index] = page; return this; - } + }; + + + public async setControllers(endTime: number, user?: 'any' | string, extraControls?: ExtraControls): Promise { + if (this.controllers.enabled) {return;} + + await this.message.react('⬅'); + await this.message.react('➡'); + await this.message.react('⏹'); + + let emoji = ['⬅', '➡', '⏹']; + let filter = user && user.toLowerCase().trim() !== 'any' + ? (r: MessageReaction, u) => {return u.id === user.trim() && emoji.includes(r.emoji.name);} + : (r: MessageReaction) => {return emoji.includes(r.emoji.name);}; + + this.controllers.collector = this.message.createReactionCollector(filter, {time: 450000}); + + this.controllers.collector.on('collect', async (r: MessageReaction) => { + console.log(r); + let functions = { + '⬅': () => {return this.prevPage();}, + '➡': () => {return this.nextPage();}, + '⏹': () => {return this.endControllers();} + } + this.controllers.lastInteraction = new Date(); + return functions[r.emoji.name](); + }); + + this.controllers.enabled = true; + this.controllers.endTime = endTime; + this.controllers.lastInteraction = new Date(); + + setInterval(() => { + if (new Date().getTime() - this.controllers.lastInteraction.getTime() > this.controllers.endTime && this.controllers.enabled) {return this.endControllers();} + }, this.controllers.endTime); + + return this; + }; + + public async updateControllers(): Promise {return this;}; + + public async endControllers(): Promise { + await this.message.reactions.removeAll(); + this.controllers.collector.stop(); + + let fe = this.message.embeds[0]; + fe.setDescription(`${fe.description}\n\n*This menu has ended, start a new one to interact with it!*`); + fe.setFooter(`${fe.footer.text} | Menu ended`, this.client.user.avatarURL()); + await this.message.edit(fe); + + return this; + }; + + + public async start(options?: {endTime?: number, startPage?: number, user?: 'any' | string}): Promise { + await this.setPage(options && options.startPage ? options.startPage : 0); + await this.setControllers(options && options.endTime ? options.endTime : 60, options && options.user ? options.user : 'any'); + + return this; + }; + + public async stop(): Promise { + return await this.endControllers(); + }; + +} + + + +interface ExtraControls { + +} + +interface ControllerData { + endTime: number, + enabled: boolean, + lastInteraction: Date, + collector: ReactionCollector } \ No newline at end of file