let djs try { djs = require('discord.js') } catch { throw new Error('Paginator: ' + 'Please install discord.js package manually') } const defaultOpts = { pages: [], remove: '🗑️', reset: '🔁', reaction: ['⬅️', '➡️'], removeReaction: true, removeAtEnd: true, timeout: 60000, filter: (reaction, user) => true } function none() {} class Paginator { constructor(opts = defaultOpts) { Object.assign(this, defaultOpts) Object.assign(this, opts) } async spawn(channel) { const opts = { remove: this.remove, reset: this.reset, reaction: this.reaction, removeReaction: this.removeReaction, removeAtEnd: this.removeAtEnd, timeout: this.timeout, filter: this.filter } const pages = [...this.pages] let page = 0 if (!pages.length) throw new Error('Paginator: ' + 'Empty pages') let message = await channel.send(pages[page]) if (!Array.isArray(opts.reaction) || opts.reaction.length < 2) throw new Error('Paginator: ' + 'Must be two reactions given in \'reaction\' options') if (typeof opts.filter != 'function') throw new Error('Paginator: ' + 'Expecting a function in \'filter\' options') if (opts.timeout < 1000 || opts.timeout > 259200000) throw new Error('Paginator: ' + 'Spawner timeout must be between 1 second and 3 days') const reactions = {} if (typeof opts.reset == 'string' && pages.length > 1) { reactions.reset = await message.react(opts.reset).catch(none) if (!reactions.reset) return } if (pages.length > 1) { reactions.left = await message.react(opts.reaction[0]).catch(none) if (!reactions.left) return reactions.right = await message.react(opts.reaction[1]).catch(none) } if (typeof opts.remove == 'string') { reactions.remove = await message.react(opts.remove).catch(none) if (!reactions.remove) return } async function filter(reaction, user) { const bool = [false, await opts.filter(reaction, user)] if (reactions.reset) bool[0] = reaction.emoji.toString() == reactions.reset.emoji.toString() if (!bool[0] && reactions.remove) bool[0] = reaction.emoji.toString() == reactions.remove.emoji.toString() if (!bool[0]) bool[0] = reaction.emoji.toString() == reactions.left.emoji.toString() || reaction.emoji.toString() == reactions.right.emoji.toString() return bool.every(condition => condition) } const collector = message.createReactionCollector(filter, { time: opts.timeout }) collector.on('collect', async (reaction, user) => { if (reactions.reset && reaction.emoji.toString() == reactions.reset.emoji.toString()) { page = 0 await message.edit(pages[page]) } else if (reactions.remove && reaction.emoji.toString() == reactions.remove.emoji.toString()) { collector.stop('123M0V3') return } else if (reaction.emoji.toString() == reactions.left.emoji.toString()) { if (pages[page - 1]) { page-- await message.edit(pages[page]) } } else if (reaction.emoji.toString() == reactions.right.emoji.toString()) { if (pages[page + 1]) { page++ await message.edit(pages[page]) } } reaction.users.remove(user.id).catch(none) }) collector.on('end', async (collected, reason) => { if (opts.removeAtEnd && reason != '123M0V3') { for (const reaction of Object.values(reactions)) { await reaction.remove().catch(none) } } if (reason == '123M0V3') await message.delete() }) } } module.exports = Paginator