diff --git a/src/structures/MessageCollector.js b/src/structures/MessageCollector.js new file mode 100644 index 00000000..81956faa --- /dev/null +++ b/src/structures/MessageCollector.js @@ -0,0 +1,116 @@ +const EventEmitter = require('events').EventEmitter; +const Collection = require('../util/Collection'); + +/** + * Collects messages based on a specified filter, then emits them. + * @extends {EventEmitter} + */ +class MessageCollector extends EventEmitter { + /** + * A function that takes a Message object and a MessageCollector and returns a boolean. + * ```js + * function(message, collector) { + * if (message.content.includes('discord')) { + * return true; // passed the filter test + * } + * return false; // failed the filter test + * } + * ``` + * @typedef {function} CollectorFilterFunction + */ + + /** + * An object containing options used to configure a MessageCollector. All properties are optional. + * @typedef {Object} CollectorOptions + * @property {number} [time] Duration for the collector in milliseconds + * @property {number} [max] Maximum number of messages to handle + */ + + /** + * @param {Channel} channel The channel to collect messages in + * @param {CollectorFilterFunction} filter The filter function + * @param {CollectorOptions} [options] Options for the collector + */ + constructor(channel, filter, options = {}) { + super(); + + /** + * The channel this collector is operating on + * @type {Channel} + */ + this.channel = channel; + + /** + * A function used to filter messages that the collector collects. + * @type {CollectorFilterFunction} + */ + this.filter = filter; + + /** + * Options for the collecor. + * @type {CollectorOptions} + */ + this.options = options; + + /** + * Whether this collector has stopped collecting Messages. + * @type {boolean} + */ + this.ended = false; + + /** + * A collection of collected messages, mapped by message ID. + * @type {Collection} + */ + this.collected = new Collection(); + + this.listener = message => this.verify(message); + this.channel.client.on('message', this.listener); + if (options.time) this.channel.client.setTimeout(() => this.stop('time'), options.time); + } + + /** + * Verifies a message against the filter and options + * @private + * @param {Message} message The message + * @returns {boolean} + */ + verify(message) { + if (this.channel ? this.channel.id !== message.channel.id : false) return false; + if (this.filter(message, this)) { + this.collected.set(message.id, message); + /** + * Emitted whenever the Collector receives a Message that passes the filter test. + * @param {Message} message The received message + * @param {MessageCollector} collector The collector the message passed through + * @event MessageCollector#message + */ + this.emit('message', message, this); + if (this.options.max && this.collected.size === this.options.max) this.stop('limit'); + return true; + } + return false; + } + + /** + * Stops the collector and emits `end`. + * @param {string} [reason='user'] An optional reason for stopping the collector + */ + stop(reason = 'user') { + if (this.ended) return; + this.ended = true; + this.channel.client.removeListener('message', this.listener); + /** + * Emitted when the Collector stops collecting. + * @param {Collection} collection A collection of messages collected + * during the lifetime of the Collector, mapped by the ID of the Messages. + * @param {string} reason The reason for the end of the collector. If it ended because it reached the specified time + * limit, this would be `time`. If you invoke `.stop()` without specifying a reason, this would be `user`. If it + * ended because it reached its message limit, it will be `limit`. + * @event MessageCollector#end + */ + this.emit('end', this.collected, reason); + } +} + +module.exports = MessageCollector; diff --git a/src/structures/interface/TextBasedChannel.js b/src/structures/interface/TextBasedChannel.js index fee8ec85..38e2feb5 100644 --- a/src/structures/interface/TextBasedChannel.js +++ b/src/structures/interface/TextBasedChannel.js @@ -1,6 +1,6 @@ const path = require('path'); -const EventEmitter = require('events').EventEmitter; const Message = require('../Message'); +const MessageCollector = require('../MessageCollector'); const Collection = require('../../util/Collection'); /** @@ -328,118 +328,6 @@ class TextBasedChannel { } } -/** - * Collects messages based on a specified filter, then emits them. - * @extends {EventEmitter} - */ -class MessageCollector extends EventEmitter { - /** - * A function that takes a Message object and a MessageCollector and returns a boolean. - * ```js - * function(message, collector) { - * if (message.content.includes('discord')) { - * return true; // passed the filter test - * } - * return false; // failed the filter test - * } - * ``` - * @typedef {function} CollectorFilterFunction - */ - - /** - * An object containing options used to configure a MessageCollector. All properties are optional. - * @typedef {Object} CollectorOptions - * @property {number} [time] Duration for the collector in milliseconds - * @property {number} [max] Maximum number of messages to handle - */ - - /** - * @param {Channel} channel The channel to collect messages in - * @param {CollectorFilterFunction} filter The filter function - * @param {CollectorOptions} [options] Options for the collector - */ - constructor(channel, filter, options = {}) { - super(); - - /** - * The channel this collector is operating on - * @type {Channel} - */ - this.channel = channel; - - /** - * A function used to filter messages that the collector collects. - * @type {CollectorFilterFunction} - */ - this.filter = filter; - - /** - * Options for the collecor. - * @type {CollectorOptions} - */ - this.options = options; - - /** - * Whether this collector has stopped collecting Messages. - * @type {boolean} - */ - this.ended = false; - - /** - * A collection of collected messages, mapped by message ID. - * @type {Collection} - */ - this.collected = new Collection(); - - this.listener = message => this.verify(message); - this.channel.client.on('message', this.listener); - if (options.time) this.channel.client.setTimeout(() => this.stop('time'), options.time); - } - - /** - * Verifies a message against the filter and options - * @private - * @param {Message} message The message - * @returns {boolean} - */ - verify(message) { - if (this.channel ? this.channel.id !== message.channel.id : false) return false; - if (this.filter(message, this)) { - this.collected.set(message.id, message); - /** - * Emitted whenever the Collector receives a Message that passes the filter test. - * @param {Message} message The received message - * @param {MessageCollector} collector The collector the message passed through - * @event MessageCollector#message - */ - this.emit('message', message, this); - if (this.options.max && this.collected.size === this.options.max) this.stop('limit'); - return true; - } - return false; - } - - /** - * Stops the collector and emits `end`. - * @param {string} [reason='user'] An optional reason for stopping the collector - */ - stop(reason = 'user') { - if (this.ended) return; - this.ended = true; - this.channel.client.removeListener('message', this.listener); - /** - * Emitted when the Collector stops collecting. - * @param {Collection} collection A collection of messages collected - * during the lifetime of the Collector, mapped by the ID of the Messages. - * @param {string} reason The reason for the end of the collector. If it ended because it reached the specified time - * limit, this would be `time`. If you invoke `.stop()` without specifying a reason, this would be `user`. If it - * ended because it reached its message limit, it will be `limit`. - * @event MessageCollector#end - */ - this.emit('end', this.collected, reason); - } -} - exports.applyToClass = (structure, full = false) => { const props = ['sendMessage', 'sendTTSMessage', 'sendFile', 'sendCode']; if (full) {