Add patcher to the plugin API and fix error when rendering system messages

This commit is contained in:
Samuel Elliott 2018-03-21 20:48:36 +00:00
parent 74e3605ec6
commit 8a9c8edf39
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
5 changed files with 57 additions and 14 deletions

View File

@ -5,14 +5,16 @@
* https://github.com/JsSucks - 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.
* LICENSE file in the root directory of this source tree.
*/
import { WebpackModules } from './webpackmodules';
import { ClientLogger as Logger, Utils } from 'common';
export class Patcher {
static get patches() { return this._patches || (this._patches = {}) }
static getPatchesByCaller(id) {
const patches = [];
for (const patch in this.patches) {
@ -22,16 +24,21 @@ export class Patcher {
}
return patches;
}
static unpatchAll(patches) {
if (typeof patches === 'string')
patches = this.getPatchesByCaller(patches);
for (const patch of patches) {
for (const child of patch.children) {
child.unpatch();
}
}
}
static resolveModule(module) {
if (module instanceof Function || (module instanceof Object && !(module instanceof Array))) return module;
if ('string' === typeof module) return WebpackModules.getModuleByName(module);
if (typeof module === 'string') return WebpackModules.getModuleByName(module);
if (module instanceof Array) return WebpackModules.getModuleByProps(module);
return null;
}
@ -99,10 +106,12 @@ export class Patcher {
static before() { return this.pushChildPatch(...arguments, 'before') }
static after() { return this.pushChildPatch(...arguments, 'after') }
static instead() { return this.pushChildPatch(...arguments, 'instead') }
static pushChildPatch(caller, unresolvedModule, functionName, callback, displayName, type = 'after') {
const module = this.resolveModule(unresolvedModule);
if (!module || !module[functionName] || !(module[functionName] instanceof Function)) return null;
displayName = 'string' === typeof unresolvedModule ? unresolvedModule : displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
displayName = typeof unresolvedModule === 'string' ? unresolvedModule :
displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${functionName}:${caller}`;
const patch = this.patches[patchId] || this.pushPatch(caller, patchId, module, functionName);

View File

@ -18,8 +18,12 @@ export default class Plugin extends Content {
get start() { return this.enable }
get stop() { return this.disable }
reload() {
return PluginManager.reloadPlugin(this);
}
unload() {
PluginManager.unloadPlugin(this);
return PluginManager.unloadPlugin(this);
}
}

View File

@ -388,10 +388,39 @@ export default class PluginApi {
get ReactComponents() {
return ReactComponents;
}
get Reflection() {
return Reflection;
}
get MonkeyPatch() {
/**
* Patcher
*/
get patches() {
return Patcher.getPatchesByCaller(this.plugin.id);
}
patchBefore(...args) { return this.pushChildPatch(...args, 'before') }
patchAfter(...args) { return this.pushChildPatch(...args, 'after') }
patchInstead(...args) { return this.pushChildPatch(...args, 'instead') }
pushChildPatch(...args) {
return Patcher.pushChildPatch(this.plugin.id, ...args);
}
unpatchAll(patches) {
return Patcher.unpatchAll(patches || this.plugin.id);
}
get Patcher() {
return Object.defineProperty({
before: this.patchBefore.bind(this),
after: this.patchAfter.bind(this),
instead: this.patchInstead.bind(this),
pushChildPatch: this.pushChildPatch.bind(this),
unpatchAll: this.unpatchAll.bind(this),
}, 'patches', {
get: () => this.patches
});
}
get monkeyPatch() {
return module => MonkeyPatch(this.plugin.id, module);
}

View File

@ -59,7 +59,9 @@ export default class extends EventListener {
const c = contributors.find(c => c.id === msgGroup.dataset.authorId);
if (!c) return;
const root = document.createElement('span');
const wrapperParent = msgGroup.querySelector('.username-wrapper').parentElement;
const usernameWrapper = msgGroup.querySelector('.username-wrapper');
if (!usernameWrapper) return;
const wrapperParent = usernameWrapper.parentElement;
if (!wrapperParent || wrapperParent.children.length < 2) return;
wrapperParent.insertBefore(root, wrapperParent.children[1]);
const { developer, contributor, webdev } = c;

View File

@ -1,26 +1,25 @@
module.exports = (Plugin, Api, Vendor) => {
const { ReactComponents } = Api;
const { Logger, ReactComponents, Patcher, monkeyPatch } = Api;
return class extends Plugin {
test() {
}
onStart() {
this.patchMessage();
return true;
}
async patchMessage() {
const Message = await ReactComponents.getComponent('Message');
this.unpatchTest = Api.MonkeyPatch(Message.component.prototype).after('render', () => {
console.log('MESSAGE RENDER!');
monkeyPatch(Message.component.prototype).after('render', e => {
Logger.log('MESSAGE RENDER!', e);
});
}
onStop() {
this.unpatchTest(); // The automatic unpatcher is not there yet
// The automatic unpatcher is not there yet
Patcher.unpatchAll();
return true;
}
}
}
};