Skip to content

Right-click menus and the message box

With ui, a plugin can add items to Fluxer’s right-click menus for messages, people and channels. With messages, it can type text into the message box after the user acts. Neither sends anything.

cleanup.push(
await api.ui.registerContextMenuItem(
{
id: "copy-id",
label: "Copy ID",
targets: ["message", "user", "channel"],
},
async (target) => {
const id =
target.kind === "message"
? target.messageId
: target.kind === "user"
? target.userId
: target.channelId;
await api.ui.notify("ID: " + id);
},
),
);

targets says which menus the item appears in. The item shows at the end of the menu with a tooltip naming your plugin. Group items under submenu: { id, label } the same way as attachment actions. A plugin may add up to 16 items.

Set only: “self” to show the item only on the user’s own messages and on their own name, or only: “others” for everyone else’s. Channels have no owner, so an item with only can’t target them. Fluxer’s user area at the bottom left has no right-click menu; users reach their own menu from their name on a message or in the member list.

The handler gets what was right-clicked, only when the user picks your item:

kind Fields
message messageId, channelId, guildId, authorId, flags, and text with message_content
user userId, guildId, channelId, self, bot
channel channelId, guildId

flags holds bot, webhook, self, reply, system, edited, pinned, mentioned and pending, which is true while Fluxer hasn’t confirmed the message: it is still sending, or failed. Names are never included. A right-click on a person’s name inside a message counts as a person, not the message. Links and text fields keep Fluxer’s own menus.

If the page changed before the user picked the item, for example the message was deleted or the user navigated away, the handler isn’t called.

cleanup.push(
await api.ui.registerContextMenuItem(
{ id: "quote", label: "Quote", targets: ["message"] },
async (target) => {
if (target.kind !== "message" || !target.text) return;
const quoted = target.text
.split("\n")
.map((line) => "> " + line)
.join("\n");
await api.messages.insertText(quoted + "\n");
},
),
);

messages.insertText(text) types up to 4000 characters at the cursor in the message box, as if the user typed or pasted them. Line breaks become soft breaks, so nothing is sent. It needs a user action in your plugin’s UI within the last 1.5 seconds: picking a menu item, a decoration button, a dialog submit or a shortcut. The action is used up.

This example also needs message_content to read the message’s text.

Error Meaning
user_gesture_required No recent user action, or it was already used
composer_unavailable No message box is open, or it can’t take text right now
composer_insert_failed The message box didn’t accept the text
context_menu_unavailable The runtime can’t add menu items on this page; skip the feature