MessageReaction.js (3767B)
1 'use strict'; 2 3 const GuildEmoji = require('./GuildEmoji'); 4 const ReactionEmoji = require('./ReactionEmoji'); 5 const ReactionUserManager = require('../managers/ReactionUserManager'); 6 const Util = require('../util/Util'); 7 8 /** 9 * Represents a reaction to a message. 10 */ 11 class MessageReaction { 12 /** 13 * @param {Client} client The instantiating client 14 * @param {Object} data The data for the message reaction 15 * @param {Message} message The message the reaction refers to 16 */ 17 constructor(client, data, message) { 18 /** 19 * The client that instantiated this message reaction 20 * @name MessageReaction#client 21 * @type {Client} 22 * @readonly 23 */ 24 Object.defineProperty(this, 'client', { value: client }); 25 /** 26 * The message that this reaction refers to 27 * @type {Message} 28 */ 29 this.message = message; 30 31 /** 32 * Whether the client has given this reaction 33 * @type {boolean} 34 */ 35 this.me = data.me; 36 37 /** 38 * A manager of the users that have given this reaction 39 * @type {ReactionUserManager} 40 */ 41 this.users = new ReactionUserManager(client, undefined, this); 42 43 this._emoji = new ReactionEmoji(this, data.emoji); 44 45 this._patch(data); 46 } 47 48 _patch(data) { 49 /** 50 * The number of people that have given the same reaction 51 * @type {?number} 52 * @name MessageReaction#count 53 */ 54 // eslint-disable-next-line eqeqeq 55 if (this.count == undefined) this.count = data.count; 56 } 57 58 /** 59 * Removes all users from this reaction. 60 * @returns {Promise<MessageReaction>} 61 */ 62 async remove() { 63 await this.client.api 64 .channels(this.message.channel.id) 65 .messages(this.message.id) 66 .reactions(this._emoji.identifier) 67 .delete(); 68 return this; 69 } 70 71 /** 72 * The emoji of this reaction, either an GuildEmoji object for known custom emojis, or a ReactionEmoji 73 * object which has fewer properties. Whatever the prototype of the emoji, it will still have 74 * `name`, `id`, `identifier` and `toString()` 75 * @type {GuildEmoji|ReactionEmoji} 76 * @readonly 77 */ 78 get emoji() { 79 if (this._emoji instanceof GuildEmoji) return this._emoji; 80 // Check to see if the emoji has become known to the client 81 if (this._emoji.id) { 82 const emojis = this.message.client.emojis.cache; 83 if (emojis.has(this._emoji.id)) { 84 const emoji = emojis.get(this._emoji.id); 85 this._emoji = emoji; 86 return emoji; 87 } 88 } 89 return this._emoji; 90 } 91 92 /** 93 * Whether or not this reaction is a partial 94 * @type {boolean} 95 * @readonly 96 */ 97 get partial() { 98 return this.count === null; 99 } 100 101 /** 102 * Fetch this reaction. 103 * @returns {Promise<MessageReaction>} 104 */ 105 async fetch() { 106 const message = await this.message.fetch(); 107 const existing = message.reactions.cache.get(this.emoji.id || this.emoji.name); 108 // The reaction won't get set when it has been completely removed 109 this._patch(existing || { count: 0 }); 110 return this; 111 } 112 113 toJSON() { 114 return Util.flatten(this, { emoji: 'emojiID', message: 'messageID' }); 115 } 116 117 _add(user) { 118 if (this.partial) return; 119 this.users.cache.set(user.id, user); 120 if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++; 121 if (!this.me) this.me = user.id === this.message.client.user.id; 122 } 123 124 _remove(user) { 125 if (this.partial) return; 126 this.users.cache.delete(user.id); 127 if (!this.me || user.id !== this.message.client.user.id) this.count--; 128 if (user.id === this.message.client.user.id) this.me = false; 129 if (this.count <= 0 && this.users.cache.size === 0) { 130 this.message.reactions.cache.delete(this.emoji.id || this.emoji.name); 131 } 132 } 133 } 134 135 module.exports = MessageReaction;