|
|
|
@ -17,22 +17,20 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { Logger } from "@utils/Logger";
|
|
|
|
|
import { Menu, React } from "@webpack/common";
|
|
|
|
|
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<ReactElement | null>, ...args: Array<any>) => ContextMenuPatchCallbackReturn;
|
|
|
|
|
export type NavContextMenuPatchCallback = (children: Array<ReactElement | null>, ...args: Array<any>) => void;
|
|
|
|
|
/**
|
|
|
|
|
* @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<ReactElement | null>, ...args: Array<any>) => ContextMenuPatchCallbackReturn;
|
|
|
|
|
export type GlobalContextMenuPatchCallback = (navId: string, children: Array<ReactElement | null>, ...args: Array<any>) => void;
|
|
|
|
|
|
|
|
|
|
const ContextMenuLogger = new Logger("ContextMenu");
|
|
|
|
|
|
|
|
|
@ -93,14 +91,19 @@ export function removeGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallba
|
|
|
|
|
* @param id The id of the child. If an array is specified, all ids will be tried
|
|
|
|
|
* @param children The context menu children
|
|
|
|
|
*/
|
|
|
|
|
export function findGroupChildrenByChildId(id: string | string[], children: Array<ReactElement | null>, _itemsArray?: Array<ReactElement | null>): Array<ReactElement | null> | null {
|
|
|
|
|
export function findGroupChildrenByChildId(id: string | string[], children: Array<ReactElement | null>): Array<ReactElement | null> | null {
|
|
|
|
|
for (const child of children) {
|
|
|
|
|
if (child == null) continue;
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(child)) {
|
|
|
|
|
const found = findGroupChildrenByChildId(id, child);
|
|
|
|
|
if (found !== null) return found;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
(Array.isArray(id) && id.some(id => child.props?.id === id))
|
|
|
|
|
|| child.props?.id === id
|
|
|
|
|
) return _itemsArray ?? null;
|
|
|
|
|
) return children;
|
|
|
|
|
|
|
|
|
|
let nextChildren = child.props?.children;
|
|
|
|
|
if (nextChildren) {
|
|
|
|
@ -109,7 +112,7 @@ export function findGroupChildrenByChildId(id: string | string[], children: Arra
|
|
|
|
|
child.props.children = nextChildren;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const found = findGroupChildrenByChildId(id, nextChildren, nextChildren);
|
|
|
|
|
const found = findGroupChildrenByChildId(id, nextChildren);
|
|
|
|
|
if (found !== null) return found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -126,9 +129,12 @@ interface ContextMenuProps {
|
|
|
|
|
onClose: (callback: (...args: Array<any>) => any) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const patchedMenus = new WeakSet();
|
|
|
|
|
export function _usePatchContextMenu(props: ContextMenuProps) {
|
|
|
|
|
props = {
|
|
|
|
|
...props,
|
|
|
|
|
children: cloneMenuChildren(props.children),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function _patchContextMenu(props: ContextMenuProps) {
|
|
|
|
|
props.contextMenuApiArguments ??= [];
|
|
|
|
|
const contextMenuPatches = navPatches.get(props.navId);
|
|
|
|
|
|
|
|
|
@ -137,8 +143,7 @@ export function _patchContextMenu(props: ContextMenuProps) {
|
|
|
|
|
if (contextMenuPatches) {
|
|
|
|
|
for (const patch of contextMenuPatches) {
|
|
|
|
|
try {
|
|
|
|
|
const callback = patch(props.children, ...props.contextMenuApiArguments);
|
|
|
|
|
if (!patchedMenus.has(props)) callback?.();
|
|
|
|
|
patch(props.children, ...props.contextMenuApiArguments);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
ContextMenuLogger.error(`Patch for ${props.navId} errored,`, err);
|
|
|
|
|
}
|
|
|
|
@ -147,12 +152,30 @@ export function _patchContextMenu(props: ContextMenuProps) {
|
|
|
|
|
|
|
|
|
|
for (const patch of globalPatches) {
|
|
|
|
|
try {
|
|
|
|
|
const callback = patch(props.navId, props.children, ...props.contextMenuApiArguments);
|
|
|
|
|
if (!patchedMenus.has(props)) callback?.();
|
|
|
|
|
patch(props.navId, props.children, ...props.contextMenuApiArguments);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
ContextMenuLogger.error("Global patch errored,", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
patchedMenus.add(props);
|
|
|
|
|
return props;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cloneMenuChildren(obj: ReactElement | Array<ReactElement | null> | null) {
|
|
|
|
|
if (Array.isArray(obj)) {
|
|
|
|
|
return obj.map(cloneMenuChildren);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (React.isValidElement(obj)) {
|
|
|
|
|
obj = React.cloneElement(obj);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
obj?.props?.children &&
|
|
|
|
|
(obj.type !== Menu.MenuControlItem || obj.type === Menu.MenuControlItem && obj.props.control != null)
|
|
|
|
|
) {
|
|
|
|
|
obj.props.children = cloneMenuChildren(obj.props.children);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|