From bfc9ecb5e7af4c9a32009f36ea88586d9898a229 Mon Sep 17 00:00:00 2001 From: Key Date: Tue, 27 Jan 2026 22:49:28 +0000 Subject: [PATCH] Make Messageclickactions Great Again! (#695) forgive me father for i have sinned, and thank you prism for fixing my awful code --- src/plugins/messageClickActions/index.ts | 86 +++++++++--------------- 1 file changed, 32 insertions(+), 54 deletions(-) diff --git a/src/plugins/messageClickActions/index.ts b/src/plugins/messageClickActions/index.ts index 91b5dcffa..3f86fbef3 100644 --- a/src/plugins/messageClickActions/index.ts +++ b/src/plugins/messageClickActions/index.ts @@ -11,9 +11,9 @@ import { Devs, EquicordDevs } from "@utils/constants"; import { copyWithToast, insertTextIntoChatInputBox } from "@utils/discord"; import { Logger } from "@utils/Logger"; import definePlugin, { OptionType } from "@utils/types"; -import type { Message } from "@vencord/discord-types"; +import type { Channel, Message } from "@vencord/discord-types"; import { ApplicationIntegrationType, MessageFlags } from "@vencord/discord-types/enums"; -import { AuthenticationStore, Constants, EditMessageStore, FluxDispatcher, MessageActions, MessageTypeSets, PermissionsBits, PermissionStore, PinActions, RestAPI, showToast, Toasts, WindowStore } from "@webpack/common"; +import { AuthenticationStore, Constants, EditMessageStore, FluxDispatcher, MessageActions, MessageTypeSets, PermissionsBits, PermissionStore, PinActions, RestAPI, Toasts, WindowStore } from "@webpack/common"; type Modifier = "NONE" | "SHIFT" | "CTRL" | "ALT" | "BACKSPACE" | "DELETE"; type ClickAction = "NONE" | "DELETE" | "COPY_LINK" | "COPY_ID" | "COPY_CONTENT" | "COPY_USER_ID" | "EDIT" | "REPLY" | "REACT" | "OPEN_THREAD" | "OPEN_TAB" | "EDIT_REPLY" | "QUOTE" | "PIN"; @@ -201,11 +201,20 @@ function showWarning(message: string) { }); } -function isMessageReplyable(msg: Message) { - return MessageTypeSets.REPLYABLE.has(msg.type) && !msg.hasFlag(MessageFlags.EPHEMERAL); -} +const canSend = (channel: Channel) => + !channel.guild_id || PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel); -async function toggleReaction(channelId: string, messageId: string, emoji: string, channel: { id: string; guild_id?: string | null; }, msg: Message) { +const canDelete = (msg: Message, channel: Channel) => { + const myId = AuthenticationStore.getId(); + return msg.author.id === myId || + PermissionStore.can(PermissionsBits.MANAGE_MESSAGES, channel) || + msg.interactionMetadata?.authorizing_integration_owners?.[ApplicationIntegrationType.USER_INSTALL] === myId; +}; + +const canReply = (msg: Message) => + MessageTypeSets.REPLYABLE.has(msg.type) && !msg.hasFlag(MessageFlags.EPHEMERAL); + +async function toggleReaction(channelId: string, messageId: string, emoji: string, channel: Channel, msg: Message) { const trimmed = emoji.trim(); if (!trimmed) return; @@ -241,37 +250,11 @@ async function toggleReaction(channelId: string, messageId: string, emoji: strin } } -async function copyMessageLink(msg: Message, channel: { id: string; guild_id?: string | null; }) { - const guildId = channel.guild_id ?? "@me"; - const link = `https://discord.com/channels/${guildId}/${channel.id}/${msg.id}`; - - try { - await navigator.clipboard.writeText(link); - showToast("Message link copied", Toasts.Type.SUCCESS); - } catch (e) { - new Logger("MessageClickActions").error("Failed to copy link:", e); - } +function copyLink(msg: Message, channel: Channel) { + copyWithToast(`https://discord.com/channels/${channel.guild_id ?? "@me"}/${channel.id}/${msg.id}`, "Link copied!"); } -async function copyMessageId(msg: Message) { - try { - await navigator.clipboard.writeText(msg.id); - showToast("Message ID copied", Toasts.Type.SUCCESS); - } catch (e) { - new Logger("MessageClickActions").error("Failed to copy message ID:", e); - } -} - -async function copyUserId(msg: Message) { - try { - await navigator.clipboard.writeText(msg.author.id); - showToast("User ID copied", Toasts.Type.SUCCESS); - } catch (e) { - new Logger("MessageClickActions").error("Failed to copy user ID:", e); - } -} - -function togglePin(channel: { id: string; }, msg: Message) { +function togglePin(channel: Channel, msg: Message) { if (!PermissionStore.can(PermissionsBits.MANAGE_MESSAGES, channel)) { showWarning("Cannot pin: Missing permissions"); return; @@ -284,8 +267,8 @@ function togglePin(channel: { id: string; }, msg: Message) { } } -function quoteMessage(channel: { id: string; guild_id?: string | null; isPrivate?: () => boolean; }, msg: Message) { - if (!isMessageReplyable(msg)) { +function quoteMessage(channel: Channel, msg: Message) { + if (!canReply(msg)) { showWarning("Cannot quote this message type"); return; } @@ -314,13 +297,13 @@ function quoteMessage(channel: { id: string; guild_id?: string | null; isPrivate } } -function openInNewTab(msg: Message, channel: { id: string; guild_id?: string | null; }) { +function openInNewTab(msg: Message, channel: Channel) { const guildId = channel.guild_id ?? "@me"; const link = `https://discord.com/channels/${guildId}/${channel.id}/${msg.id}`; VencordNative.native.openExternal(link); } -function openInThread(msg: Message, channel: { id: string; }) { +function openInThread(msg: Message, channel: Channel) { FluxDispatcher.dispatch({ type: "OPEN_THREAD_FLOW_MODAL", channelId: channel.id, @@ -331,16 +314,15 @@ function openInThread(msg: Message, channel: { id: string; }) { async function executeAction( action: ClickAction, msg: Message, - channel: { id: string; guild_id?: string | null; isDM?: () => boolean; isSystemDM?: () => boolean; isPrivate?: () => boolean; }, + channel: Channel, event: MouseEvent ) { const myId = AuthenticationStore.getId(); const isMe = msg.author.id === myId; - const isSelfInvokedUserApp = msg.interactionMetadata?.authorizing_integration_owners?.[ApplicationIntegrationType.USER_INSTALL] === myId; switch (action) { case "DELETE": - if (!(isMe || PermissionStore.can(PermissionsBits.MANAGE_MESSAGES, channel) || isSelfInvokedUserApp)) return; + if (!canDelete(msg, channel)) return; if (msg.deleted) { FluxDispatcher.dispatch({ @@ -356,12 +338,12 @@ async function executeAction( break; case "COPY_LINK": - await copyMessageLink(msg, channel); + copyLink(msg, channel); event.preventDefault(); break; case "COPY_ID": - await copyMessageId(msg); + copyWithToast(msg.id, "Message ID copied!"); event.preventDefault(); break; @@ -371,7 +353,7 @@ async function executeAction( break; case "COPY_USER_ID": - await copyUserId(msg); + copyWithToast(msg.author.id, "User ID copied!"); event.preventDefault(); break; @@ -383,8 +365,8 @@ async function executeAction( break; case "REPLY": - if (!MessageTypeSets.REPLYABLE.has(msg.type) || msg.hasFlag(MessageFlags.EPHEMERAL)) return; - if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return; + if (!canReply(msg)) return; + if (!canSend(channel)) return; const isShiftPress = event.shiftKey; const shouldMention = isPluginEnabled(NoReplyMentionPlugin.name) @@ -406,8 +388,8 @@ async function executeAction( if (EditMessageStore.isEditing(channel.id, msg.id) || msg.state !== "SENT") return; MessageActions.startEditMessage(channel.id, msg.id, msg.content); } else { - if (!MessageTypeSets.REPLYABLE.has(msg.type) || msg.hasFlag(MessageFlags.EPHEMERAL)) return; - if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return; + if (!canReply(msg)) return; + if (!canSend(channel)) return; const shouldMentionReply = isPluginEnabled(NoReplyMentionPlugin.name) ? NoReplyMentionPlugin.shouldMention(msg, false) @@ -490,10 +472,6 @@ export default definePlugin({ let target = event.target as HTMLElement; if (target.nodeType === Node.TEXT_NODE) target = target.parentElement as HTMLElement; - // dont look, please just dont - if (target.closest('a, button, input, img, video, audio, [role="button"], [role="link"], [role="menuitem"], [class*="repliedTextPreview"], [class*="threadMessageAccessory"], [class*="spoilerText"], [class*="mention"]')) return; - if (!target.closest('[class*="message"]')) return; - const myId = AuthenticationStore.getId(); const isMe = msg.author.id === myId; const isDM = channel.isDM(); @@ -545,7 +523,7 @@ export default definePlugin({ } const executeDoubleClick = () => { - if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return; + if (!canSend(channel)) return; if (msg.deleted === true) return; if (canDoubleClick) { executeAction(doubleClickAction, msg, channel, event);