BetterDiscordApp-v2/client/src/ui/profilebadges.js

152 lines
5.4 KiB
JavaScript

/**
* BetterDiscord Developer/Contributor Profile Badges
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { Module, ReactComponents, ReactHelpers, MonkeyPatch, Reflection } from 'modules';
import { ClientLogger as Logger } from 'common';
import { BdBadge } from './components/bd';
import VueInjector from './vueinjector';
import contributors from '../data/contributors';
export default class extends Module {
init() {
this.patchMessage();
this.patchChannelMember();
this.patchNameTag();
this.patchUserProfileModal();
}
get contributors() {
return contributors;
}
/**
* Patches Message to render profile badges.
*/
async patchMessage() {
const Message = await ReactComponents.getComponent('Message');
this.unpatchMessageRender = MonkeyPatch('ProfileBadges', Message.component.prototype).after('render', (component, args, retVal) => {
if (!retVal.props || !retVal.props.children) return;
if (ReactHelpers.findProp(component, 'jumpSequenceId') && ReactHelpers.findProp(component, 'canFlash')) retVal = retVal.props.children;
const message = ReactHelpers.findProp(component, 'message');
if (!message || !message.author) return;
const user = message.author;
const contributor = contributors.find(c => c.id === user.id);
if (!contributor) return;
const username = ReactHelpers.findByProp(retVal, 'type', 'h2');
if (!username) return;
username.props.children.splice(1, 0, VueInjector.createReactElement(BdBadge, {
contributor,
type: 'nametag'
}));
});
// Rerender all messages
Message.forceUpdateAll();
}
/**
* Patches ChannelMember to use the extended NameTag.
* This is because NameTag is also used in places we don't really want any badges.
*/
async patchChannelMember() {
const ChannelMember = await ReactComponents.getComponent('ChannelMember');
this.unpatchChannelMemberRender = MonkeyPatch('ProfileBadges', ChannelMember.component.prototype).after('render', (component, args, retVal) => {
if (!retVal.props || !retVal.props.children) return;
const user = ReactHelpers.findProp(component, 'user');
if (!user) return;
const c = contributors.find(c => c.id === user.id);
if (!c) return;
const nameTag = retVal.props.children.props.children[1].props.children[0];
nameTag.type = this.PatchedNameTag || nameTag.type;
});
// Rerender all channel members
if (this.PatchedNameTag) {
ChannelMember.forceUpdateAll();
}
}
/**
* Creates an extended NameTag component that renders message badges.
*/
async patchNameTag() {
if (this.PatchedNameTag) return this.PatchedNameTag;
const NameTag = await ReactComponents.getComponent('NameTag');
this.PatchedNameTag = class extends NameTag.component {
render() {
const retVal = NameTag.component.prototype.render.call(this, arguments);
try {
if (!retVal.props || !retVal.props.children) return;
const user = ReactHelpers.findProp(this, 'user');
if (!user) return;
const contributor = contributors.find(c => c.id === user.id);
if (!contributor) return;
retVal.props.children.splice(1, 0, VueInjector.createReactElement(BdBadge, {
contributor,
type: 'nametag'
}));
} catch (err) {
Logger.err('ProfileBadges', ['Error thrown while rendering a NameTag', err]);
}
return retVal;
}
};
// Rerender all channel members
if (this.unpatchChannelMemberRender) {
const ChannelMember = await ReactComponents.getComponent('ChannelMember');
ChannelMember.forceUpdateAll();
}
return this.PatchedNameTag;
}
/**
* Patches UserProfileModal to render profile badges.
*/
async patchUserProfileModal() {
const UserProfileModal = await ReactComponents.getComponent('UserProfileModal');
this.unpatchUserProfileModal = MonkeyPatch('ProfileBadges', UserProfileModal.component.prototype).after('renderBadges', (component, args, retVal, setRetVal) => {
const user = ReactHelpers.findProp(component, 'user');
if (!user) return;
const contributor = contributors.find(c => c.id === user.id);
if (!contributor) return;
const element = VueInjector.createReactElement(BdBadge, {
contributor,
type: 'profile-modal'
});
if (!retVal) {
setRetVal(ReactHelpers.React.createElement('div', {
className: 'bd-profileBadgesWrap',
children: element
}));
} else retVal.props.children.splice(0, 0, element);
});
UserProfileModal.forceUpdateAll();
}
}