From b1d90843457bc8715c51830671a9c6a3b5e5d85a Mon Sep 17 00:00:00 2001 From: Drahcirius Date: Mon, 3 Jul 2017 18:53:22 -0400 Subject: [PATCH] Remove RichEmbed in favour of MessageEmbed (#1584) * remove RichEmbed in favour of MessageEmbed * fix provider typo --- src/index.js | 1 - src/structures/Message.js | 4 +- src/structures/MessageEmbed.js | 81 ++++--- src/structures/RichEmbed.js | 216 ------------------ src/structures/Webhook.js | 3 + src/structures/interfaces/TextBasedChannel.js | 2 +- src/structures/shared/SendMessage.js | 5 +- 7 files changed, 63 insertions(+), 249 deletions(-) delete mode 100644 src/structures/RichEmbed.js diff --git a/src/index.js b/src/index.js index 37c06d96e..e7915c7b2 100644 --- a/src/index.js +++ b/src/index.js @@ -53,7 +53,6 @@ module.exports = { Presence: require('./structures/Presence').Presence, ReactionEmoji: require('./structures/ReactionEmoji'), ReactionCollector: require('./structures/ReactionCollector'), - RichEmbed: require('./structures/RichEmbed'), Role: require('./structures/Role'), TextChannel: require('./structures/TextChannel'), User: require('./structures/User'), diff --git a/src/structures/Message.js b/src/structures/Message.js index f355d70dc..51ad902ab 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -384,7 +384,9 @@ class Message { if (typeof content !== 'undefined') content = Util.resolveString(content); - const { embed, code, reply } = options; + let { embed, code, reply } = options; + + if (embed) embed = new Embed(embed)._apiTransform(); // Wrap everything in a code block if (typeof code !== 'undefined' && (typeof code !== 'boolean' || code === true)) { diff --git a/src/structures/MessageEmbed.js b/src/structures/MessageEmbed.js index 21ef03c68..fd7a738c6 100644 --- a/src/structures/MessageEmbed.js +++ b/src/structures/MessageEmbed.js @@ -5,7 +5,7 @@ const { RangeError } = require('../errors'); * Represents an embed in a message (image/video preview, rich embed, etc.) */ class MessageEmbed { - constructor(data) { + constructor(data = {}) { this.setup(data); } @@ -20,31 +20,31 @@ class MessageEmbed { * The title of this embed * @type {?string} */ - this.title = data.title || null; + this.title = data.title; /** * The description of this embed * @type {?string} */ - this.description = data.description || null; + this.description = data.description; /** * The URL of this embed * @type {?string} */ - this.url = data.url || null; + this.url = data.url; /** * The color of the embed * @type {?number} */ - this.color = data.color || null; + this.color = data.color; /** * The timestamp of this embed * @type {?number} */ - this.timestamp = new Date(data.timestamp) || null; + this.timestamp = new Date(data.timestamp); /** * The fields of this embed @@ -53,7 +53,7 @@ class MessageEmbed { * @property {string} value The value of this field * @property {boolean} inline If this field will be displayed inline */ - this.fields = data.fields || null; + this.fields = data.fields || []; /** * The thumbnail of this embed, if there is one @@ -64,7 +64,7 @@ class MessageEmbed { * @property {number} width Width of this thumbnail */ this.thumbnail = data.thumbnail ? { - url: data.thumbnail.url || null, + url: data.thumbnail.url, proxyURL: data.thumbnail.proxy_url, height: data.height, width: data.width, @@ -79,7 +79,7 @@ class MessageEmbed { * @property {number} width Width of this image */ this.image = data.image ? { - url: data.image.url || null, + url: data.image.url, proxyURL: data.image.proxy_url, height: data.height, width: data.width, @@ -92,11 +92,7 @@ class MessageEmbed { * @property {number} height Height of this video * @property {number} width Width of this video */ - this.video = data.video ? { - url: data.video.url || null, - height: data.video.height, - width: data.video.width, - } : null; + this.video = data.video; /** * The author of this embed, if there is one @@ -107,10 +103,10 @@ class MessageEmbed { * @property {string} proxyIconURL Proxied URL of the icon for this author */ this.author = data.author ? { - name: data.author.name || null, - url: data.author.url || null, - iconURL: data.author.iconURL || data.author.icon_url || null, - proxyIconURL: data.author.proxyIconUrl || data.author.proxy_icon_url || null, + name: data.author.name, + url: data.author.url, + iconURL: data.author.iconURL || data.author.icon_url, + proxyIconURL: data.author.proxyIconUrl || data.author.proxy_icon_url, } : null; /** @@ -119,10 +115,7 @@ class MessageEmbed { * @property {string} name The name of this provider * @property {string} url URL of this provider */ - this.provider = data.provider ? { - name: data.provider.name, - url: data.provider.url, - } : null; + this.provider = data.provider; /** * The footer of this embed @@ -132,9 +125,9 @@ class MessageEmbed { * @property {string} proxyIconURL Proxied URL of the icon for this footer */ this.footer = data.footer ? { - text: data.footer.text || null, - iconURL: data.footer.iconURL || data.footer.icon_url || null, - proxyIconURL: data.footer.proxyIconURL || data.footer.proxy_icon_url || null, + text: data.footer.text, + iconURL: data.footer.iconURL || data.footer.icon_url, + proxyIconURL: data.footer.proxyIconURL || data.footer.proxy_icon_url, } : null; } @@ -144,7 +137,7 @@ class MessageEmbed { * @readonly */ get createdAt() { - return new Date(this.timestamp); + return !isNaN(this.timestamp) ? this.timestamp : null; } /** @@ -153,9 +146,7 @@ class MessageEmbed { * @readonly */ get hexColor() { - let col = this.color.toString(16); - while (col.length < 6) col = `0${col}`; - return `#${col}`; + return this.color ? `#${this.color.toString(16).padStart(6, '0')}` : null; } /** @@ -175,6 +166,15 @@ class MessageEmbed { return this; } + /** + * Convenience function for `.addField('\u200B', '\u200B', inline)`. + * @param {boolean} [inline=false] Set the field to display inline + * @returns {MessageEmbed} This embed + */ + addBlankField(inline = false) { + return this.addField('\u200B', '\u200B', inline); + } + /** * Sets the file to upload alongside the embed. This file can be accessed via `attachment://fileName.extension` when * setting an embed image or author/footer icons. Only one file may be attached. @@ -286,6 +286,29 @@ class MessageEmbed { return this; } + _apiTransform() { + return { + title: this.title, + type: 'rich', + description: this.description, + url: this.url, + timestamp: this.timestamp, + color: this.color, + fields: this.fields, + file: this.file, + thumbnail: this.thumbnail, + image: this.image, + author: this.author ? { + name: this.author.name, + url: this.author.url, + icon_url: this.author.iconURL, + } : null, + footer: this.footer ? { + text: this.footer.text, + icon_url: this.footer.iconURL, + } : null, + }; + } } module.exports = MessageEmbed; diff --git a/src/structures/RichEmbed.js b/src/structures/RichEmbed.js deleted file mode 100644 index 014943130..000000000 --- a/src/structures/RichEmbed.js +++ /dev/null @@ -1,216 +0,0 @@ -const Util = require('../util/Util'); - -/** - * A rich embed to be sent with a message with a fluent interface for creation. - * @param {Object} [data] Data to set in the rich embed - */ -class RichEmbed { - constructor(data = {}) { - /** - * Title for this Embed - * @type {string} - */ - this.title = data.title; - - /** - * Description for this Embed - * @type {string} - */ - this.description = data.description; - - /** - * URL for this Embed - * @type {string} - */ - this.url = data.url; - - /** - * Color for this Embed - * @type {number} - */ - this.color = data.color; - - /** - * Author for this Embed - * @type {Object} - */ - this.author = data.author; - - /** - * Timestamp for this Embed - * @type {Date} - */ - this.timestamp = data.timestamp; - - /** - * Fields for this Embed - * @type {Object[]} - */ - this.fields = data.fields || []; - - /** - * Thumbnail for this Embed - * @type {Object} - */ - this.thumbnail = data.thumbnail; - - /** - * Image for this Embed - * @type {Object} - */ - this.image = data.image; - - /** - * Footer for this Embed - * @type {Object} - */ - this.footer = data.footer; - - /** - * File to upload alongside this Embed - * @type {string} - */ - this.file = data.file; - } - - /** - * Sets the title of this embed. - * @param {StringResolvable} title The title - * @returns {RichEmbed} This embed - */ - setTitle(title) { - title = Util.resolveString(title); - if (title.length > 256) throw new RangeError('RichEmbed titles may not exceed 256 characters.'); - this.title = title; - return this; - } - - /** - * Sets the description of this embed. - * @param {StringResolvable} description The description - * @returns {RichEmbed} This embed - */ - setDescription(description) { - description = Util.resolveString(description); - if (description.length > 2048) throw new RangeError('RichEmbed descriptions may not exceed 2048 characters.'); - this.description = description; - return this; - } - - /** - * Sets the URL of this embed. - * @param {string} url The URL - * @returns {RichEmbed} This embed - */ - setURL(url) { - this.url = url; - return this; - } - - /** - * Sets the color of this embed. - * @param {ColorResolvable} color The color of the embed - * @returns {RichEmbed} This embed - */ - setColor(color) { - this.color = Util.resolveColor(color); - return this; - } - - /** - * Sets the author of this embed. - * @param {StringResolvable} name The name of the author - * @param {string} [icon] The icon URL of the author - * @param {string} [url] The URL of the author - * @returns {RichEmbed} This embed - */ - setAuthor(name, icon, url) { - this.author = { name: Util.resolveString(name), icon_url: icon, url }; - return this; - } - - /** - * Sets the timestamp of this embed. - * @param {Date} [timestamp=current date] The timestamp - * @returns {RichEmbed} This embed - */ - setTimestamp(timestamp = new Date()) { - this.timestamp = timestamp; - return this; - } - - /** - * Adds a field to the embed (max 25). - * @param {StringResolvable} name The name of the field - * @param {StringResolvable} value The value of the field - * @param {boolean} [inline=false] Set the field to display inline - * @returns {RichEmbed} This embed - */ - addField(name, value, inline = false) { - if (this.fields.length >= 25) throw new RangeError('RichEmbeds may not exceed 25 fields.'); - name = Util.resolveString(name); - if (name.length > 256) throw new RangeError('RichEmbed field names may not exceed 256 characters.'); - if (!/\S/.test(name)) throw new RangeError('RichEmbed field names may not be empty.'); - value = Util.resolveString(value); - if (value.length > 1024) throw new RangeError('RichEmbed field values may not exceed 1024 characters.'); - if (!/\S/.test(value)) throw new RangeError('RichEmbed field values may not be empty.'); - this.fields.push({ name, value, inline }); - return this; - } - - /** - * Convenience function for `.addField('\u200B', '\u200B', inline)`. - * @param {boolean} [inline=false] Set the field to display inline - * @returns {RichEmbed} This embed - */ - addBlankField(inline = false) { - return this.addField('\u200B', '\u200B', inline); - } - - /** - * Set the thumbnail of this embed. - * @param {string} url The URL of the thumbnail - * @returns {RichEmbed} This embed - */ - setThumbnail(url) { - this.thumbnail = { url }; - return this; - } - - /** - * Set the image of this embed. - * @param {string} url The URL of the image - * @returns {RichEmbed} This embed - */ - setImage(url) { - this.image = { url }; - return this; - } - - /** - * Sets the footer of this embed. - * @param {StringResolvable} text The text of the footer - * @param {string} [icon] The icon URL of the footer - * @returns {RichEmbed} This embed - */ - setFooter(text, icon) { - text = Util.resolveString(text); - if (text.length > 2048) throw new RangeError('RichEmbed footer text may not exceed 2048 characters.'); - this.footer = { text, icon_url: icon }; - return this; - } - - /** - * Sets the file to upload alongside the embed. This file can be accessed via `attachment://fileName.extension` when - * setting an embed image or author/footer icons. Only one file may be attached. - * @param {FileOptions|string} file Local path or URL to the file to attach, or valid FileOptions for a file to attach - * @returns {RichEmbed} This embed - */ - attachFile(file) { - if (this.file) throw new RangeError('You may not upload more than one file at once.'); - this.file = file; - return this; - } -} - -module.exports = RichEmbed; diff --git a/src/structures/Webhook.js b/src/structures/Webhook.js index 497c8645d..20af8554e 100644 --- a/src/structures/Webhook.js +++ b/src/structures/Webhook.js @@ -1,5 +1,6 @@ const path = require('path'); const Util = require('../util/Util'); +const Embed = require('./MessageEmbed'); /** * Represents a webhook. @@ -124,6 +125,8 @@ class Webhook { } options.content = content; + if (options.embeds) options.embeds = options.embeds.map(embed => new Embed(embed)._apiTransform()); + if (options.file) { if (options.files) options.files.push(options.file); else options.files = [options.file]; diff --git a/src/structures/interfaces/TextBasedChannel.js b/src/structures/interfaces/TextBasedChannel.js index f47db7d1c..5b1936597 100644 --- a/src/structures/interfaces/TextBasedChannel.js +++ b/src/structures/interfaces/TextBasedChannel.js @@ -35,7 +35,7 @@ class TextBasedChannel { * @typedef {Object} MessageOptions * @property {boolean} [tts=false] Whether or not the message should be spoken aloud * @property {string} [nonce=''] The nonce for the message - * @property {RichEmbed|Object} [embed] An embed for the message + * @property {MessageEmbed|Object} [embed] An embed for the message * (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details) * @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here * should be replaced with plain-text diff --git a/src/structures/shared/SendMessage.js b/src/structures/shared/SendMessage.js index f7e8eecf8..3eacb1b57 100644 --- a/src/structures/shared/SendMessage.js +++ b/src/structures/shared/SendMessage.js @@ -1,12 +1,15 @@ const Util = require('../../util/Util'); +const Embed = require('../MessageEmbed'); const { RangeError } = require('../../errors'); -module.exports = function sendMessage(channel, options) { +module.exports = function sendMessage(channel, options) { // eslint-disable-line complexity const User = require('../User'); const GuildMember = require('../GuildMember'); if (channel instanceof User || channel instanceof GuildMember) return channel.createDM().then(dm => dm.send(options)); let { content, nonce, reply, code, disableEveryone, tts, embed, files, split } = options; + if (embed) embed = new Embed(embed)._apiTransform(); + if (typeof nonce !== 'undefined') { nonce = parseInt(nonce); if (isNaN(nonce) || nonce < 0) throw new RangeError('MESSAGE_NONCE_TYPE');