UNPKG

discord.js

Version:

A powerful library for interacting with the Discord API

257 lines (216 loc) • 7.49 kB
'use strict'; const { Collection } = require('@discordjs/collection'); const { lazy } = require('@discordjs/util'); const BaseInteraction = require('./BaseInteraction'); const InteractionWebhook = require('./InteractionWebhook'); const ModalSubmitFields = require('./ModalSubmitFields'); const InteractionResponses = require('./interfaces/InteractionResponses'); const { transformResolved } = require('../util/Util'); const getMessage = lazy(() => require('./Message').Message); const getAttachment = lazy(() => require('./Attachment')); /** * @typedef {Object} BaseModalData * @property {ComponentType} type The component type of the field * @property {number} id The id of the field */ /** * @typedef {BaseModalData} FileUploadModalData * @property {string} customId The custom id of the file upload * @property {Snowflake[]} values The values of the file upload * @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments */ /** * @typedef {BaseModalData} TextInputModalData * @property {string} customId The custom id of the field * @property {string} value The value of the field */ /** * @typedef {BaseModalData} SelectMenuModalData * @property {string} customId The custom id of the field * @property {string[]} values The values of the field * @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved members * @property {Collection<Snowflake, User|APIUser>} [users] The resolved users * @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles * @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels */ /** * @typedef {BaseModalData} TextDisplayModalData */ /** * @typedef {SelectMenuModalData|TextInputModalData|FileUploadModalData} ModalData */ /** * @typedef {BaseModalData} LabelModalData * @property {ModalData} component The component within the label */ /** * @typedef {BaseModalData} ActionRowModalData * @property {TextInputModalData[]} components The components of this action row */ /** * Represents a modal interaction * @extends {BaseInteraction} * @implements {InteractionResponses} */ class ModalSubmitInteraction extends BaseInteraction { constructor(client, data) { super(client, data); /** * The custom id of the modal. * @type {string} */ this.customId = data.data.custom_id; if ('message' in data) { /** * The message associated with this interaction * @type {?Message} */ this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(this.client, data.message); } else { this.message = null; } /** * The components within the modal * * @type {Array<ActionRowModalData | LabelModalData | TextDisplayModalData>} */ this.components = data.data.components?.map(component => ModalSubmitInteraction.transformComponent(component, data.data.resolved, { client: this.client, guild: this.guild, }), ); /** * The fields within the modal * @type {ModalSubmitFields} */ this.fields = new ModalSubmitFields( this.components, transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved), ); /** * Whether the reply to this interaction has been deferred * @type {boolean} */ this.deferred = false; /** * Whether this interaction has already been replied to * @type {boolean} */ this.replied = false; /** * Whether the reply to this interaction is ephemeral * @type {?boolean} */ this.ephemeral = null; /** * An associated interaction webhook, can be used to further interact with this interaction * @type {InteractionWebhook} */ this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token); } /** * Transforms component data to discord.js-compatible data * @param {*} rawComponent The data to transform * @param {APIInteractionDataResolved} [resolved] The resolved data for the interaction * @param {*} [extra] Extra data required for the transformation * @returns {ModalData[]} */ static transformComponent(rawComponent, resolved, { client, guild } = {}) { if ('components' in rawComponent) { return { type: rawComponent.type, id: rawComponent.id, components: rawComponent.components.map(component => this.transformComponent(component, resolved, { client, guild }), ), }; } if ('component' in rawComponent) { return { type: rawComponent.type, id: rawComponent.id, component: this.transformComponent(rawComponent.component, resolved, { client, guild }), }; } const data = { type: rawComponent.type, id: rawComponent.id, }; // Text display components do not have custom ids. if ('custom_id' in rawComponent) data.customId = rawComponent.custom_id; if ('value' in rawComponent) data.value = rawComponent.value; if (rawComponent.values) { data.values = rawComponent.values; /* eslint-disable max-depth */ if (resolved) { const { members, users, channels, roles, attachments } = resolved; const valueSet = new Set(rawComponent.values); if (users) { data.users = new Collection(); for (const [id, user] of Object.entries(users)) { if (valueSet.has(id)) { data.users.set(id, client.users._add(user)); } } } if (channels) { data.channels = new Collection(); for (const [id, apiChannel] of Object.entries(channels)) { if (valueSet.has(id)) { data.channels.set(id, client.channels._add(apiChannel, guild) ?? apiChannel); } } } if (members) { data.members = new Collection(); for (const [id, member] of Object.entries(members)) { if (valueSet.has(id)) { const user = users?.[id]; data.members.set(id, guild?.members._add({ user, ...member }) ?? member); } } } if (roles) { data.roles = new Collection(); for (const [id, role] of Object.entries(roles)) { if (valueSet.has(id)) { data.roles.set(id, guild?.roles._add(role) ?? role); } } } if (attachments) { data.attachments = new Collection(); for (const [id, attachment] of Object.entries(attachments)) { if (valueSet.has(id)) { data.attachments.set(id, new (getAttachment())(attachment)); } } } } /* eslint-enable max-depth */ } return data; } /** * Whether this is from a {@link MessageComponentInteraction}. * @returns {boolean} */ isFromMessage() { return Boolean(this.message); } // These are here only for documentation purposes - they are implemented by InteractionResponses /* eslint-disable no-empty-function */ deferReply() {} reply() {} fetchReply() {} editReply() {} deleteReply() {} followUp() {} deferUpdate() {} update() {} sendPremiumRequired() {} launchActivity() {} } InteractionResponses.applyToClass(ModalSubmitInteraction, 'showModal'); module.exports = ModalSubmitInteraction;