XL v1.3.20

This commit is contained in:
_Lighty_ 2020-05-19 17:18:40 +02:00
parent 1f1f9318a8
commit 7b0faabf5d
1 changed files with 44 additions and 97 deletions

View File

@ -41,7 +41,7 @@ var XenoLib = (() => {
twitter_username: ''
}
],
version: '1.3.19',
version: '1.3.20',
description: 'Simple library to complement plugins with shared code without lowering performance.',
github: 'https://github.com/1Lighty',
github_raw: 'https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/1XenoLib.plugin.js'
@ -50,7 +50,7 @@ var XenoLib = (() => {
{
title: 'Boring changes',
type: 'fixed',
items: ['Fix up startup warnings and errors.', 'Fixed notifications closing sometimes if you hover them near the end of the timeout.', 'Future proofing.']
items: ['Fix up a couple of errors related to recent context menu changes.', 'Deprecated global context menu patching.']
}
],
defaultConfig: [
@ -95,7 +95,7 @@ var XenoLib = (() => {
/* Build */
const buildPlugin = ([Plugin, Api]) => {
const { ContextMenu, EmulatedTooltip, Toasts, Settings, Popouts, Modals, Utilities, WebpackModules, Filters, DiscordModules, ColorConverter, DOMTools, DiscordClasses, DiscordSelectors, ReactTools, ReactComponents, DiscordAPI, Logger, Patcher, PluginUpdater, PluginUtilities, DiscordClassModules, Structs } = Api;
const { ContextMenu, EmulatedTooltip, Toasts, Settings, Popouts, Modals, Utilities, WebpackModules, Filters, DiscordModules, ColorConverter, DOMTools, DiscordClasses, DiscordSelectors, ReactTools, ReactComponents, DiscordAPI, Logger, PluginUpdater, PluginUtilities, DiscordClassModules, Structs } = Api;
const { React, ModalStack, ContextMenuActions, ContextMenuItem, ContextMenuItemsGroup, ReactDOM, ChannelStore, GuildStore, UserStore, DiscordConstants, Dispatcher, GuildMemberStore, GuildActions, PrivateChannelActions, LayerManager, InviteActions, FlexChild, Titles, Changelog: ChangelogModal } = DiscordModules;
let CancelledAsync = false;
@ -181,6 +181,25 @@ var XenoLib = (() => {
XenoLib.getClass.__warns = {};
XenoLib.getSingleClass.__warns = {};
XenoLib.createSmartPatcher = patcher => {
const createPatcher = patcher => {
return (moduleToPatch, functionName, callback, options = {}) => {
const origDef = moduleToPatch[functionName];
patcher(moduleToPatch, functionName, callback, options);
if (origDef.isBDFDBpatched && moduleToPatch.BDFDBpatch && typeof moduleToPatch.BDFDBpatch[functionName].originalMethod === 'function') {
patcher(moduleToPatch.BDFDBpatch[functionName], 'originalMethod', callback, options);
}
};
};
return Object.assign({}, patcher, {
before: createPatcher(patcher.before),
instead: createPatcher(patcher.instead),
after: createPatcher(patcher.after)
});
};
const Patcher = XenoLib.createSmartPatcher(Api.Patcher);
const LibrarySettings = XenoLib.loadData(config.info.name, 'settings', DefaultLibrarySettings);
PluginUtilities.addStyle(
@ -380,112 +399,40 @@ var XenoLib = (() => {
}
};
XenoLib.__contextPatches = [];
try {
if (global.XenoLib) if (global.XenoLib.__contextPatches && global.XenoLib.__contextPatches.length) XenoLib.__contextPatches.push(...global.XenoLib.__contextPatches);
const ContextMenuClassname = XenoLib.getSingleClass('subMenuContext contextMenu'); /* I AM *SPEED* */
const getContextMenuChild = val => {
if (!val) return;
const isValid = obj => obj.type === 'div' && obj.props && typeof obj.props.className === 'string' && obj.props.className.indexOf(ContextMenuClassname) !== -1 && Array.isArray(Utilities.getNestedProp(obj, 'props.children.props.children'));
if (isValid(val)) return val.props.children;
const children = Utilities.getNestedProp(val, 'props.children');
if (!children) return;
if (Array.isArray(children)) {
for (let i = 0; i < children.length; i++) {
const ret = getContextMenuChild(children[i]);
if (ret) return ret.props.children;
}
} else if (isValid(children)) return children.props.children;
};
const handleContextMenu = (_this, ret, noRender) => {
const menuGroups = getContextMenuChild(ret) || ret;
if (!menuGroups) return /* Logger.warn('Failed to get context menu groups!', _this, ret) */;
/* emulate a react class component */
if (noRender) {
let [value, set] = React.useState(false);
let [state, setState] = React.useState({});
_this.forceUpdate = () => set(!value);
_this.state = state;
_this.setState = setState;
}
if (!_this.state) _this.state = {};
XenoLib.__contextPatches.forEach(e => {
try {
e(_this, menuGroups);
} catch (e) {
Logger.stacktrace('Error with patched context menu', e);
}
});
};
const getModule = regex => {
try {
const modules = WebpackModules.getAllModules();
for (const index in modules) {
if (!modules.hasOwnProperty(index)) continue;
const module = modules[index];
if (!module.exports || !module.exports.__esModule || !module.exports.default) continue;
/* if BDFDB was inited before us, patch the already patched function */
if (module.exports.default.toString().search(regex) !== -1 || (module.exports.default.isBDFDBpatched && module.exports.default.__originalMethod.toString().search(regex) !== -1)) return module;
}
} catch (e) {
Logger.stacktrace(`Failed to getModule by regex ${regex}`, e);
return null;
}
};
const renderContextMenus = ['NativeContextMenu', 'DeveloperContextMenu'];
const hookContextMenus = [getModule(/case \w.ContextMenuTypes.CHANNEL_LIST_TEXT/), getModule(/case \w.ContextMenuTypes.GUILD_CHANNEL_LIST/), getModule(/case \w.ContextMenuTypes.USER_CHANNEL_MEMBERS/), getModule(/case \w\.ContextMenuTypes\.MESSAGE_MAIN/)];
for (const type of renderContextMenus) {
const module = WebpackModules.getByDisplayName(type);
if (!module) {
Logger.warn(`Failed to find ContextMenu type`, type);
continue;
}
Patcher.after(module.prototype, 'render', (_this, _, ret) => handleContextMenu(_this, ret));
}
for (const menu of hookContextMenus) {
if (!menu) continue;
const origDef = menu.exports.default;
Patcher.after(menu.exports, 'default', (_, [props], ret) => handleContextMenu({ props }, ret, true));
if (origDef.isBDFDBpatched && menu.exports.BDFDBpatch && typeof menu.exports.BDFDBpatch.default.originalMethod === 'function') {
Patcher.after(menu.exports.BDFDBpatch.default, 'originalMethod', (_, [props], ret) => handleContextMenu({ props }, ret, true));
}
}
const GroupDMContextMenu = WebpackModules.getByDisplayName('FluxContainer(GroupDMContextMenu)');
if (GroupDMContextMenu) {
try {
const type = new GroupDMContextMenu({}).render().type;
Patcher.after(type.prototype, 'render', (_this, _, ret) => handleContextMenu(_this, ret));
} catch (e) {
Logger.stacktrace('Failed patching GroupDMContextMenu', e);
}
}
} catch (e) {
Logger.stacktrace('Failed to patch context menus', e);
}
XenoLib.patchContext = callback => {
XenoLib.__contextPatches.push(callback);
};
const deprecateFunction = (name, advice, ret = undefined) => () => (Logger.warn(`XenoLib.${name} is deprecated! ${advice}`), ret);
XenoLib.patchContext = deprecateFunction('patchContext', 'Do manual patching of context menus instead.');
const CTXMenu = WebpackModules.getByProps('default', 'MenuStyle');
class ContextMenuWrapper extends React.PureComponent {
constructor(props) {
super(props);
this.handleOnClose = this.handleOnClose.bind(this);
}
handleOnClose() {
ContextMenuActions.closeContextMenu();
if (this.props.target instanceof HTMLElement) this.props.target.focus();
}
render() {
return React.createElement('div', { className: DiscordClasses.ContextMenu.contextMenu }, this.props.menu);
return React.createElement(CTXMenu.default, { onClose: this.handleOnClose, id: 'xenolib-context' }, this.props.menu);
}
}
XenoLib.createSharedContext = (element, type, menuCreation) => {
XenoLib.createSharedContext = (element, menuCreation) => {
if (element.__XenoLib_ContextMenus) {
element.__XenoLib_ContextMenus.push(menuCreation);
} else {
element.__XenoLib_ContextMenus = [menuCreation];
const oOnContextMenu = element.props.onContextMenu;
element.props.onContextMenu = e => (typeof oOnContextMenu === 'function' && oOnContextMenu(e), ContextMenuActions.openContextMenu(e, _ => React.createElement(ContextMenuWrapper, { menu: element.__XenoLib_ContextMenus.map(m => React.createElement(XenoLib.ReactComponents.ErrorBoundary, { label: 'shared context menu' }, m())), type })));
element.props.onContextMenu = e => (typeof oOnContextMenu === 'function' && oOnContextMenu(e), ContextMenuActions.openContextMenu(e, _ => React.createElement(XenoLib.ReactComponents.ErrorBoundary, { label: 'CTX Menu' }, React.createElement(ContextMenuWrapper, { menu: element.__XenoLib_ContextMenus.map(m => m()), ..._ }))));
}
};
const ContextMenuSubMenuItem = WebpackModules.getByDisplayName('FluxContainer(SubMenuItem)');
XenoLib.unpatchContext = callback => XenoLib.__contextPatches.splice(XenoLib.__contextPatches.indexOf(callback), 1);
XenoLib.createContextMenuItem = (label, action, options = {}) => (!ContextMenuItem ? null : React.createElement(ContextMenuItem, { label, action: () => (!options.noClose && ContextMenuActions.closeContextMenu(), action()), ...options }));
XenoLib.createContextMenuSubMenu = (label, items, options = {}) => (!ContextMenuSubMenuItem ? null : React.createElement(ContextMenuSubMenuItem, { label, render: items, ...options }));
XenoLib.createContextMenuGroup = (children, options) => (!ContextMenuItemsGroup ? null : React.createElement(ContextMenuItemsGroup, { children, ...options }));
const contextMenuItems = WebpackModules.find(m => m.MenuRadioItem && !m.default);
XenoLib.unpatchContext = deprecateFunction('unpatchContext', 'Manual patching needs manual unpatching');
XenoLib.createContextMenuItem = (label, action, id, options = {}) => (!contextMenuItems ? null : React.createElement(contextMenuItems.MenuItem, { label, id, action: () => (!options.noClose && ContextMenuActions.closeContextMenu(), action()), ...options }));
XenoLib.createContextMenuSubMenu = (label, children, id, options = {}) => (!contextMenuItems ? null : React.createElement(contextMenuItems.MenuItem, { label, children, id, ...options }));
XenoLib.createContextMenuGroup = (children, options) => (!contextMenuItems ? null : React.createElement(contextMenuItems.MenuGroup, { children, ...options }));
try {
XenoLib.ReactComponents.ButtonOptions = WebpackModules.getByProps('ButtonLink');
@ -542,7 +489,7 @@ var XenoLib = (() => {
footerProps.children = [];
if (websiteLink) footerProps.children.push(websiteLink);
if (sourceLink) footerProps.children.push(websiteLink ? ' | ' : null, sourceLink);
footerProps.children.push(websiteLink || sourceLink ? ' | ' : null, React.createElement('a', { className: 'bda-link', onClick: e => ContextMenuActions.openContextMenu(e, e => React.createElement('div', { className: DiscordClasses.ContextMenu.contextMenu }, XenoLib.createContextMenuGroup([XenoLib.createContextMenuItem('Paypal', () => window.open('https://paypal.me/lighty13')), XenoLib.createContextMenuItem('Ko-fi', () => window.open('https://ko-fi.com/lighty_')), XenoLib.createContextMenuItem('Patreon', () => window.open('https://www.patreon.com/lightyp'))]))) }, 'Donate'));
footerProps.children.push(websiteLink || sourceLink ? ' | ' : null, React.createElement('a', { className: 'bda-link', onClick: e => ContextMenuActions.openContextMenu(e, e => React.createElement(XenoLib.ReactComponents.ErrorBoundary, { label: 'Donate button CTX menu' }, React.createElement(ContextMenuWrapper, { menu: XenoLib.createContextMenuGroup([XenoLib.createContextMenuItem('Paypal', () => window.open('https://paypal.me/lighty13'), 'paypal'), XenoLib.createContextMenuItem('Ko-fi', () => window.open('https://ko-fi.com/lighty_'), 'kofi'), XenoLib.createContextMenuItem('Patreon', () => window.open('https://www.patreon.com/lightyp'), 'patreon')]), ...e }))) }, 'Donate'));
footerProps.children.push(' | ', supportServerLink || React.createElement('a', { className: 'bda-link', onClick: () => (LayerManager.popLayer(), InviteActions.acceptInviteAndTransitionToInviteChannel('NYvWdN5')) }, 'Support Server'));
footerProps.children.push(' | ', React.createElement('a', { className: 'bda-link', onClick: () => (_this.props.addon.plugin.showChangelog ? _this.props.addon.plugin.showChangelog() : Modals.showChangelogModal(_this.props.addon.plugin.getName() + ' Changelog', _this.props.addon.plugin.getVersion(), _this.props.addon.plugin.getChanges())) }, 'Changelog'));
footerProps = null;