From 13437c56d4c8d1710c8623cd347065541ca49d96 Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Mon, 6 Aug 2018 04:30:48 +0100 Subject: [PATCH 1/3] =?UTF-8?q?Search=20all=20matching=20elements=20instea?= =?UTF-8?q?d=20of=20just=20the=20first=20and=20don=E2=80=99t=20fail=20if?= =?UTF-8?q?=20a=20filter=20function=20is=20passed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/modules/reactcomponents.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/client/src/modules/reactcomponents.js b/client/src/modules/reactcomponents.js index 7d62dcbc..22ca257e 100644 --- a/client/src/modules/reactcomponents.js +++ b/client/src/modules/reactcomponents.js @@ -233,12 +233,23 @@ export class ReactComponents { return; } - const element = document.querySelector(important.selector); - if (!element) return; + const elements = document.querySelectorAll(important.selector); + if (!elements.length) return; + + let component, reflect; + for (let element of elements) { + reflect = Reflection(element); + component = filter ? reflect.components.find(filter) : reflect.component; + if (component) break; + } + + if (!component && filter) { + Logger.log('ReactComponents', ['Found elements matching the query selector but no components passed the filter']); + return; + } DOM.observer.unsubscribe(observerSubscription); - const reflect = Reflection(element); - const component = filter ? reflect.components.find(filter) : reflect.component; + if (!component) { Logger.err('ReactComponents', [`FAILED TO GET IMPORTANT COMPONENT ${name} WITH REFLECTION FROM`, element]); return; @@ -250,7 +261,7 @@ export class ReactComponents { this.push(component, undefined, important); }; - const observerSubscription = DOM.observer.subscribeToQuerySelector(callback, important.selector); + const observerSubscription = DOM.observer.subscribeToQuerySelector(callback, important.selector, null, true); setTimeout(callback, 0); } From e2f05d9a6424d8c363ab0d1ebaba575fa40ecd9e Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Mon, 6 Aug 2018 04:48:10 +0100 Subject: [PATCH 2/3] Patch all channel components --- client/src/modules/reactcomponents.js | 73 ++++++++++++++++++--------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/client/src/modules/reactcomponents.js b/client/src/modules/reactcomponents.js index 22ca257e..934eab22 100644 --- a/client/src/modules/reactcomponents.js +++ b/client/src/modules/reactcomponents.js @@ -309,7 +309,7 @@ export class ReactComponents { export class ReactAutoPatcher { /** * Wait for React to be loaded and patch it's createElement to store all unknown components. - * Also patches of some known components. + * Also patches some known components. */ static async autoPatch() { const React = await WebpackModules.waitForModuleByName('React'); @@ -323,16 +323,8 @@ export class ReactAutoPatcher { * Patches a few known components. */ static patchComponents() { - return Promise.all([ - this.patchMessage(), - this.patchMessageGroup(), - this.patchChannelMember(), - this.patchGuild(), - this.patchChannel(), - this.patchChannelList(), - this.patchUserProfileModal(), - this.patchUserPopout() - ]); + const componentPatchFunctions = Object.getOwnPropertyNames(this).filter(p => p.startsWith('patch') && p !== 'patchComponents'); + return Promise.all(componentPatchFunctions.map(p => this[p].call(this))); } static async patchMessage() { @@ -407,6 +399,9 @@ export class ReactAutoPatcher { this.Guild.forceUpdateAll(); } + /** + * The Channel component contains the header, message scroller, message form and member list. + */ static async patchChannel() { const selector = '.chat'; this.Channel = await ReactComponents.getComponent('Channel', {selector}); @@ -424,21 +419,53 @@ export class ReactAutoPatcher { this.Channel.forceUpdateAll(); } - static async patchChannelList() { + /** + * The GuildTextChannel component represents a text channel in the guild channel list. + */ + static async patchGuildTextChannel() { const selector = '.' + WebpackModules.getClassName('containerDefault', 'actionIcon'); - this.GuildChannel = await ReactComponents.getComponent('GuildChannel', {selector}); + this.GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel', {selector}, c => c.prototype.renderMentionBadge); - this.unpatchGuildChannel = MonkeyPatch('BD:ReactComponents', this.GuildChannel.component.prototype).after('render', (component, args, retVal) => { - const { channel } = component.props; - if (!channel) return; - retVal.props['data-channel-id'] = channel.id; - retVal.props['data-channel-name'] = channel.name; - if ([0, 2, 4].includes(channel.type)) retVal.props.className += ' bd-isGuildChannel'; - if ([1, 3].includes(channel.type)) retVal.props.className += ' bd-isPrivateChannel'; - if (channel.type === 3) retVal.props.className += ' bd-isGroupChannel'; - }); + this.unpatchGuildTextChannel = MonkeyPatch('BD:ReactComponents', this.GuildTextChannel.component.prototype).after('render', this._afterChannelRender); - this.GuildChannel.forceUpdateAll(); + this.GuildTextChannel.forceUpdateAll(); + } + + /** + * The GuildVoiceChannel component represents a voice channel in the guild channel list. + */ + static async patchGuildVoiceChannel() { + const selector = '.' + WebpackModules.getClassName('containerDefault', 'actionIcon'); + this.GuildVoiceChannel = await ReactComponents.getComponent('GuildVoiceChannel', {selector}, c => c.prototype.handleVoiceConnect); + + this.unpatchGuildVoiceChannel = MonkeyPatch('BD:ReactComponents', this.GuildVoiceChannel.component.prototype).after('render', this._afterChannelRender); + + this.GuildVoiceChannel.forceUpdateAll(); + } + + /** + * The DirectMessage component represents a channel in the direct messages list. + */ + static async patchDirectMessage() { + const selector = '.channel.private'; + this.DirectMessage = await ReactComponents.getComponent('DirectMessage', {selector}, c => c.prototype.renderAvatar); + + this.unpatchDirectMessage = MonkeyPatch('BD:ReactComponents', this.DirectMessage.component.prototype).after('render', this._afterChannelRender); + + this.DirectMessage.forceUpdateAll(); + } + + static _afterChannelRender(component, args, retVal) { + const { channel } = component.props; + if (!channel) return; + + retVal.props['data-channel-id'] = channel.id; + retVal.props['data-channel-name'] = channel.name; + if ([0, 2, 4].includes(channel.type)) retVal.props.className += ' bd-isGuildChannel'; + if (channel.type === 2) retVal.props.className += ' bd-isVoiceChannel'; + // if (channel.type === 4) retVal.props.className += ' bd-isChannelCategory'; + if ([1, 3].includes(channel.type)) retVal.props.className += ' bd-isPrivateChannel'; + if (channel.type === 3) retVal.props.className += ' bd-isGroupChannel'; } static async patchUserProfileModal() { From c0a971a27bd3a3dfdac6d1cfe9e672d67e97d14b Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Tue, 7 Aug 2018 00:08:13 +0100 Subject: [PATCH 3/3] Fix element is not defined --- client/src/modules/reactcomponents.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/modules/reactcomponents.js b/client/src/modules/reactcomponents.js index 934eab22..0b9e5bbe 100644 --- a/client/src/modules/reactcomponents.js +++ b/client/src/modules/reactcomponents.js @@ -251,7 +251,7 @@ export class ReactComponents { DOM.observer.unsubscribe(observerSubscription); if (!component) { - Logger.err('ReactComponents', [`FAILED TO GET IMPORTANT COMPONENT ${name} WITH REFLECTION FROM`, element]); + Logger.err('ReactComponents', [`FAILED TO GET IMPORTANT COMPONENT ${name} WITH REFLECTION FROM`, elements]); return; }