aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNuckyz <61953774+Nuckyz@users.noreply.github.com>2023-04-14 21:47:03 -0300
committerGitHub <noreply@github.com>2023-04-15 02:47:03 +0200
commit96f640da674e89824881070c4081b7aee212e619 (patch)
tree9d8dbdf97313c79410c8d1a2b380116d2b7d3a86
parente8809fc57bd1c679e9a84ae6adc949655e3a86ec (diff)
downloadVencord-96f640da674e89824881070c4081b7aee212e619.tar.gz
Vencord-96f640da674e89824881070c4081b7aee212e619.tar.bz2
Vencord-96f640da674e89824881070c4081b7aee212e619.zip
Make Context Menu API support hooks (#902)
Co-authored-by: V <vendicated@riseup.net>
-rw-r--r--src/api/ContextMenu.ts26
-rw-r--r--src/plugins/devCompanion.dev.tsx4
-rw-r--r--src/plugins/emoteCloner.tsx4
-rw-r--r--src/plugins/imageZoom/index.tsx2
-rw-r--r--src/plugins/messageLogger/index.tsx2
-rw-r--r--src/plugins/pinDms/contextMenus.tsx4
-rw-r--r--src/plugins/reverseImageSearch.tsx2
-rw-r--r--src/plugins/searchReply.tsx3
-rw-r--r--src/plugins/settings.tsx2
-rw-r--r--src/plugins/viewIcons.tsx4
10 files changed, 29 insertions, 24 deletions
diff --git a/src/api/ContextMenu.ts b/src/api/ContextMenu.ts
index 4e52131..4d1d577 100644
--- a/src/api/ContextMenu.ts
+++ b/src/api/ContextMenu.ts
@@ -19,17 +19,20 @@
import Logger from "@utils/Logger";
import type { ReactElement } from "react";
+type ContextMenuPatchCallbackReturn = (() => void) | void;
/**
* @param children The rendered context menu elements
* @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example
+ * @returns A callback which is only ran once used to modify the context menu elements (Use to avoid duplicates)
*/
-export type NavContextMenuPatchCallback = (children: Array<React.ReactElement>, ...args: Array<any>) => void;
+export type NavContextMenuPatchCallback = (children: Array<React.ReactElement>, ...args: Array<any>) => ContextMenuPatchCallbackReturn;
/**
- * @param The navId of the context menu being patched
+ * @param navId The navId of the context menu being patched
* @param children The rendered context menu elements
* @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example
+ * @returns A callback which is only ran once used to modify the context menu elements (Use to avoid duplicates)
*/
-export type GlobalContextMenuPatchCallback = (navId: string, children: Array<React.ReactElement>, ...args: Array<any>) => void;
+export type GlobalContextMenuPatchCallback = (navId: string, children: Array<React.ReactElement>, ...args: Array<any>) => ContextMenuPatchCallbackReturn;
const ContextMenuLogger = new Logger("ContextMenu");
@@ -78,6 +81,7 @@ export function removeContextMenuPatch<T extends string | Array<string>>(navId:
/**
* Remove a global context menu patch
+ * @param patch The patch to be removed
* @returns Wheter the patch was sucessfully removed
*/
export function removeGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallback): boolean {
@@ -87,12 +91,13 @@ export function removeGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallba
/**
* A helper function for finding the children array of a group nested inside a context menu based on the id of one of its childs
* @param id The id of the child
+ * @param children The context menu children
*/
-export function findGroupChildrenByChildId(id: string, children: Array<React.ReactElement>, itemsArray?: Array<React.ReactElement>): Array<React.ReactElement> | null {
+export function findGroupChildrenByChildId(id: string, children: Array<React.ReactElement>, _itemsArray?: Array<React.ReactElement>): Array<React.ReactElement> | null {
for (const child of children) {
if (child == null) continue;
- if (child.props?.id === id) return itemsArray ?? null;
+ if (child.props?.id === id) return _itemsArray ?? null;
let nextChildren = child.props?.children;
if (nextChildren) {
@@ -121,9 +126,6 @@ interface ContextMenuProps {
const patchedMenus = new WeakSet();
export function _patchContextMenu(props: ContextMenuProps) {
- if (patchedMenus.has(props)) return;
- patchedMenus.add(props);
-
props.contextMenuApiArguments ??= [];
const contextMenuPatches = navPatches.get(props.navId);
@@ -132,7 +134,8 @@ export function _patchContextMenu(props: ContextMenuProps) {
if (contextMenuPatches) {
for (const patch of contextMenuPatches) {
try {
- patch(props.children, ...props.contextMenuApiArguments);
+ const callback = patch(props.children, ...props.contextMenuApiArguments);
+ if (!patchedMenus.has(props)) callback?.();
} catch (err) {
ContextMenuLogger.error(`Patch for ${props.navId} errored,`, err);
}
@@ -141,9 +144,12 @@ export function _patchContextMenu(props: ContextMenuProps) {
for (const patch of globalPatches) {
try {
- patch(props.navId, props.children, ...props.contextMenuApiArguments);
+ const callback = patch(props.navId, props.children, ...props.contextMenuApiArguments);
+ if (!patchedMenus.has(props)) callback?.();
} catch (err) {
ContextMenuLogger.error("Global patch errored,", err);
}
}
+
+ patchedMenus.add(props);
}
diff --git a/src/plugins/devCompanion.dev.tsx b/src/plugins/devCompanion.dev.tsx
index 67388c8..15cb2b0 100644
--- a/src/plugins/devCompanion.dev.tsx
+++ b/src/plugins/devCompanion.dev.tsx
@@ -238,8 +238,8 @@ function initWs(isManual = false) {
});
}
-const contextMenuPatch: NavContextMenuPatchCallback = kids => {
- kids.unshift(
+const contextMenuPatch: NavContextMenuPatchCallback = children => () => {
+ children.unshift(
<Menu.MenuItem
id={NAV_ID}
label="Reconnect Dev Companion"
diff --git a/src/plugins/emoteCloner.tsx b/src/plugins/emoteCloner.tsx
index 809518c..7b8261e 100644
--- a/src/plugins/emoteCloner.tsx
+++ b/src/plugins/emoteCloner.tsx
@@ -210,7 +210,7 @@ function isGifUrl(url: string) {
return new URL(url).pathname.endsWith(".gif");
}
-const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
+const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
const { favoriteableId, itemHref, itemSrc, favoriteableType } = props ?? {};
if (!favoriteableId || favoriteableType !== "emoji") return;
@@ -223,7 +223,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
if (group) group.push(buildMenuItem(favoriteableId, name, isGifUrl(itemHref ?? itemSrc)));
};
-const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
+const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => () => {
const { id, name, type } = props?.target?.dataset ?? {};
if (!id || !name || type !== "emoji") return;
diff --git a/src/plugins/imageZoom/index.tsx b/src/plugins/imageZoom/index.tsx
index d65df08..9007bf4 100644
--- a/src/plugins/imageZoom/index.tsx
+++ b/src/plugins/imageZoom/index.tsx
@@ -75,7 +75,7 @@ export const settings = definePluginSettings({
});
-const imageContextMenuPatch: NavContextMenuPatchCallback = (children, _) => {
+const imageContextMenuPatch: NavContextMenuPatchCallback = children => () => {
children.push(
<Menu.MenuGroup id="image-zoom">
{/* thanks SpotifyControls */}
diff --git a/src/plugins/messageLogger/index.tsx b/src/plugins/messageLogger/index.tsx
index 808fd34..5ff514e 100644
--- a/src/plugins/messageLogger/index.tsx
+++ b/src/plugins/messageLogger/index.tsx
@@ -44,7 +44,7 @@ function addDeleteStyle() {
}
const MENU_ITEM_ID = "message-logger-remove-history";
-const patchMessageContextMenu: NavContextMenuPatchCallback = (children, props) => {
+const patchMessageContextMenu: NavContextMenuPatchCallback = (children, props) => () => {
const { message } = props;
const { deleted, editHistory, id, channel_id } = message;
diff --git a/src/plugins/pinDms/contextMenus.tsx b/src/plugins/pinDms/contextMenus.tsx
index b04ba8c..d75c9f9 100644
--- a/src/plugins/pinDms/contextMenus.tsx
+++ b/src/plugins/pinDms/contextMenus.tsx
@@ -49,13 +49,13 @@ function PinMenuItem(channelId: string) {
);
}
-const GroupDMContext: NavContextMenuPatchCallback = (children, props) => {
+const GroupDMContext: NavContextMenuPatchCallback = (children, props) => () => {
const container = findGroupChildrenByChildId("leave-channel", children);
if (container)
container.unshift(PinMenuItem(props.channel.id));
};
-const UserContext: NavContextMenuPatchCallback = (children, props) => {
+const UserContext: NavContextMenuPatchCallback = (children, props) => () => {
const container = findGroupChildrenByChildId("close-dm", children);
if (container) {
const idx = container.findIndex(c => c?.props?.id === "close-dm");
diff --git a/src/plugins/reverseImageSearch.tsx b/src/plugins/reverseImageSearch.tsx
index 74b2619..deaa280 100644
--- a/src/plugins/reverseImageSearch.tsx
+++ b/src/plugins/reverseImageSearch.tsx
@@ -34,7 +34,7 @@ function search(src: string, engine: string) {
open(engine + encodeURIComponent(src), "_blank");
}
-const imageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
+const imageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
if (!props) return;
const { reverseImageSearchType, itemHref, itemSrc } = props;
diff --git a/src/plugins/searchReply.tsx b/src/plugins/searchReply.tsx
index 8c7b473..cb09f5b 100644
--- a/src/plugins/searchReply.tsx
+++ b/src/plugins/searchReply.tsx
@@ -28,7 +28,7 @@ const ReplyIcon = LazyComponent(() => findByCode("M10 8.26667V4L3 11.4667L10 18.
const replyFn = findByCodeLazy("showMentionToggle", "TEXTAREA_FOCUS", "shiftKey");
-const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => {
+const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => () => {
// make sure the message is in the selected channel
if (SelectedChannelStore.getChannelId() !== message.channel_id) return;
@@ -61,7 +61,6 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { messag
/>
));
}
-
};
diff --git a/src/plugins/settings.tsx b/src/plugins/settings.tsx
index 74d0496..5dec83c 100644
--- a/src/plugins/settings.tsx
+++ b/src/plugins/settings.tsx
@@ -41,7 +41,7 @@ export default definePlugin({
// doesn't contain our sections. This patches the actions of our
// sections to manually use SettingsRouter (which only works on desktop
// but the context menu is usually not available on mobile anyway)
- addContextMenuPatch("user-settings-cog", children => {
+ addContextMenuPatch("user-settings-cog", children => () => {
const section = children.find(c => Array.isArray(c) && c.some(it => it?.props?.id === "VencordSettings")) as any;
section?.forEach(c => {
if (c?.props?.id?.startsWith("Vencord")) {
diff --git a/src/plugins/viewIcons.tsx b/src/plugins/viewIcons.tsx
index 85105c5..7519d74 100644
--- a/src/plugins/viewIcons.tsx
+++ b/src/plugins/viewIcons.tsx
@@ -81,7 +81,7 @@ function openImage(url: string) {
));
}
-const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: UserContextProps) => {
+const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: UserContextProps) => () => {
const memberAvatar = GuildMemberStore.getMember(guildId!, user.id)?.avatar || null;
children.splice(1, 0, (
@@ -106,7 +106,7 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U
));
};
-const GuildContext: NavContextMenuPatchCallback = (children, { guild: { id, icon, banner } }: GuildContextProps) => {
+const GuildContext: NavContextMenuPatchCallback = (children, { guild: { id, icon, banner } }: GuildContextProps) => () => {
if (!banner && !icon) return;
// before copy id (if it exists)