From 977fd80d0c6e78a9775288bc441f0e771308b146 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sat, 25 Aug 2018 22:34:18 +0300 Subject: [PATCH 1/9] add walkers to pluginapi --- client/src/modules/pluginapi.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/modules/pluginapi.js b/client/src/modules/pluginapi.js index 387b7515..bf987018 100644 --- a/client/src/modules/pluginapi.js +++ b/client/src/modules/pluginapi.js @@ -105,7 +105,9 @@ export default class PluginApi { removeFromArray: (...args) => Utils.removeFromArray.apply(Utils, args), defineSoftGetter: (...args) => Utils.defineSoftGetter.apply(Utils, args), wait: (...args) => Utils.wait.apply(Utils, args), - until: (...args) => Utils.until.apply(Utils, args) + until: (...args) => Utils.until.apply(Utils, args), + findInTree: (...args) => Utils.findInTree.apply(Utils, args), + findInReactTree: (...args) => Utils.findInReactTree.apply(Utils, args) }; } From d4aa8fb377722129e5ba0b648fe2b1f64b76f861 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sat, 25 Aug 2018 23:29:54 +0300 Subject: [PATCH 2/9] Custom element example --- .../Custom Elements Example/config.json | 17 ++++ .../plugins/Custom Elements Example/index.js | 89 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 tests/ext/plugins/Custom Elements Example/config.json create mode 100644 tests/ext/plugins/Custom Elements Example/index.js diff --git a/tests/ext/plugins/Custom Elements Example/config.json b/tests/ext/plugins/Custom Elements Example/config.json new file mode 100644 index 00000000..daac514d --- /dev/null +++ b/tests/ext/plugins/Custom Elements Example/config.json @@ -0,0 +1,17 @@ +{ + "info": { + "id": "custom-elements", + "name": "Custom Elements Example", + "authors": [ + { + "name": "Jiiks", + "discord_id": "81388395867156480", + "github_username": "Jiiks", + "twitter_username": "Jiiksi" + } + ], + "version": 1.0, + "description": "Custom Elements Description" + }, + "main": "index.js" +} diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js new file mode 100644 index 00000000..6365e980 --- /dev/null +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -0,0 +1,89 @@ +/** + * This is an example of how you should add custom elements instead of manipulating the DOM directly + */ + +module.exports = (Plugin, Api, Vendor) => { + + // Destructure some apis + const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils } = Api; + const { React } = Reflection.modules; // This should be in vendor + + return class extends Plugin { + + async onStart() { + Logger.log('Custom Elements Example Started'); + this.injectStyle(); + this.patchGuildTextChannel(); + return true; + } + + async onStop() { + Logger.log('Custom Elements Example Stopped'); + // The automatic unpatcher is not there yet + Patcher.unpatchAll(); + CssUtils.deleteAllStyles(); + + // Force update elements to remove our changes + const GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel'); + GuildTextChannel.forceUpdateAll(); + return true; + } + + /* Inject some style for our custom element */ + async injectStyle() { + const css = ` + .exampleCustomElement { + background: #7a7d82; + color: #FFF; + border-radius: 5px; + font-size: 12px; + font-weight: 600; + opacity: .5; + &:hover { + opacity: 1; + } + }`; + await CssUtils.injectSass(css); + } + + async patchGuildTextChannel() { + // Get the GuildTextChannel component and patch it's render function + const GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel'); + monkeyPatch(GuildTextChannel.component.prototype).after('render', this.injectReact.bind(this)); + // Force update to see our changes immediatly + GuildTextChannel.forceUpdateAll(); + } + + /* Injecting a custom Vue element */ + injectVue() { + // TODO + } + + /* + * Injecting a custom React element using React.createElement + * https://reactjs.org/docs/react-api.html#createelement + **/ + injectReact(that, args, returnValue) { + // Get the child we want using a treewalker since we know the child we want has a channel property and children. + const child = Utils.findInReactTree(returnValue, filter => filter.hasOwnProperty('channel') && filter.children); + if (!child) return; + // If children is not an array make it into one + if (!child.children instanceof Array) child.children = [child.children]; + + // add our custom component to children + child.children.push(React.createElement( + 'button', + { className: 'exampleCustomElement', onClick: e => this.handleReactClick(e, child.channel) }, + 'i' + )); + } + + /** + * Will log the channel object + */ + handleReactClick(e, channel) { + Logger.log('Clicked!', channel); + } + } + +}; From 4a9cc603d28410eb33af2c5dd132e5d2c0b8f3cf Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sun, 26 Aug 2018 00:59:07 +0300 Subject: [PATCH 3/9] add vue component --- .../plugins/Custom Elements Example/index.js | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js index 6365e980..7fca8a75 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -5,7 +5,8 @@ module.exports = (Plugin, Api, Vendor) => { // Destructure some apis - const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils } = Api; + const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector } = Api; + const { Vue } = Vendor; const { React } = Reflection.modules; // This should be in vendor return class extends Plugin { @@ -70,18 +71,34 @@ module.exports = (Plugin, Api, Vendor) => { // If children is not an array make it into one if (!child.children instanceof Array) child.children = [child.children]; - // add our custom component to children - child.children.push(React.createElement( + // Create custom components + const reactComponent = React.createElement( 'button', - { className: 'exampleCustomElement', onClick: e => this.handleReactClick(e, child.channel) }, - 'i' - )); + { className: 'exampleCustomElement', onClick: e => this.handleClick(e, child.channel) }, + 'r' + ); + + // Using Vue might be preferred to some + const vueComponent = Vue.component('somecomponent', { + render: createElement => { + return createElement('button', { + class: 'exampleCustomElement', + on: { + click: e => this.handleClick(e, child.channel) + } + }, 'v') + } + }); + + // Add our custom components to children + child.children.push(reactComponent); + child.children.push(VueInjector.createReactElement(vueComponent)); // We need to wrap our vue component inside react } /** * Will log the channel object */ - handleReactClick(e, channel) { + handleClick(e, channel) { Logger.log('Clicked!', channel); } } From 6538442b0b243a6ea72f2aea153aa84babeb2cc3 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sun, 26 Aug 2018 01:03:03 +0300 Subject: [PATCH 4/9] Correct callback --- tests/ext/plugins/Custom Elements Example/index.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js index 7fca8a75..5643357b 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -50,21 +50,18 @@ module.exports = (Plugin, Api, Vendor) => { async patchGuildTextChannel() { // Get the GuildTextChannel component and patch it's render function const GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel'); - monkeyPatch(GuildTextChannel.component.prototype).after('render', this.injectReact.bind(this)); + monkeyPatch(GuildTextChannel.component.prototype).after('render', this.injectCustomElements.bind(this)); // Force update to see our changes immediatly GuildTextChannel.forceUpdateAll(); } - /* Injecting a custom Vue element */ - injectVue() { - // TODO - } - /* * Injecting a custom React element using React.createElement * https://reactjs.org/docs/react-api.html#createelement + * Injecting a custom Vue element using Vue.component + * https://vuejs.org/v2/guide/render-function.html **/ - injectReact(that, args, returnValue) { + injectCustomElements(that, args, returnValue) { // Get the child we want using a treewalker since we know the child we want has a channel property and children. const child = Utils.findInReactTree(returnValue, filter => filter.hasOwnProperty('channel') && filter.children); if (!child) return; From e12dc280529e08c1ee949609b97fdc01aa00f3d8 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sun, 26 Aug 2018 01:37:37 +0300 Subject: [PATCH 5/9] Vuewrap --- client/src/modules/pluginapi.js | 5 +++++ .../ext/plugins/Custom Elements Example/index.js | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/client/src/modules/pluginapi.js b/client/src/modules/pluginapi.js index bf987018..8a5c1768 100644 --- a/client/src/modules/pluginapi.js +++ b/client/src/modules/pluginapi.js @@ -24,6 +24,7 @@ import DiscordApi from './discordapi'; import { ReactComponents, ReactHelpers } from './reactcomponents'; import { Patcher, MonkeyPatch } from './patcher'; import GlobalAc from '../ui/autocomplete'; +import Vue from 'vue'; export default class PluginApi { @@ -607,6 +608,10 @@ export default class PluginApi { }); } + Vuewrap(id, args) { + return VueInjector.createReactElement(Vue.component(id, args)); + } + } // Stop plugins from modifying the plugin API for all plugins diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js index 5643357b..9c00fbe5 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -5,7 +5,7 @@ module.exports = (Plugin, Api, Vendor) => { // Destructure some apis - const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector } = Api; + const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector, Vuewrap } = Api; const { Vue } = Vendor; const { React } = Reflection.modules; // This should be in vendor @@ -87,9 +87,22 @@ module.exports = (Plugin, Api, Vendor) => { } }); + // You can also use Vuewrap which does the wrapping for us + const vueWrapComponent = Vuewrap('somecomponent', { + render: createElement => { + return createElement('button', { + class: 'exampleCustomElement', + on: { + click: e => this.handleClick(e, child.channel) + } + }, 'vw') + } + }); + // Add our custom components to children child.children.push(reactComponent); child.children.push(VueInjector.createReactElement(vueComponent)); // We need to wrap our vue component inside react + child.children.push(vueWrapComponent); } /** From 23b8e2dd76bc1ba89398094696ff2d00386d03e5 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sun, 26 Aug 2018 03:48:23 +0300 Subject: [PATCH 6/9] add and use the relative api --- client/src/modules/pluginapi.js | 15 ++++++- .../components/reactcomponent.js | 7 ++++ .../components/vuecomponent.js | 13 ++++++ .../plugins/Custom Elements Example/index.js | 42 ++++--------------- 4 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 tests/ext/plugins/Custom Elements Example/components/reactcomponent.js create mode 100644 tests/ext/plugins/Custom Elements Example/components/vuecomponent.js diff --git a/client/src/modules/pluginapi.js b/client/src/modules/pluginapi.js index 8a5c1768..9f933102 100644 --- a/client/src/modules/pluginapi.js +++ b/client/src/modules/pluginapi.js @@ -25,6 +25,8 @@ import { ReactComponents, ReactHelpers } from './reactcomponents'; import { Patcher, MonkeyPatch } from './patcher'; import GlobalAc from '../ui/autocomplete'; import Vue from 'vue'; +import path from 'path'; +import Globals from './globals'; export default class PluginApi { @@ -56,6 +58,15 @@ export default class PluginApi { return null; } + relativeRequire(file) { + const absolutePath = path.join(this.pluginPath, file); + delete Globals.require.cache[Globals.require.resolve(absolutePath)]; + return Globals.require(absolutePath); + } + get relative() { + return this.relativeRequire.bind(this); + } + get Api() { return this } get AsyncEventEmitter() { return AsyncEventEmitter } @@ -608,8 +619,8 @@ export default class PluginApi { }); } - Vuewrap(id, args) { - return VueInjector.createReactElement(Vue.component(id, args)); + Vuewrap(id, component, props) { + return VueInjector.createReactElement(Vue.component(id, component), props); } } diff --git a/tests/ext/plugins/Custom Elements Example/components/reactcomponent.js b/tests/ext/plugins/Custom Elements Example/components/reactcomponent.js new file mode 100644 index 00000000..36222d14 --- /dev/null +++ b/tests/ext/plugins/Custom Elements Example/components/reactcomponent.js @@ -0,0 +1,7 @@ +module.exports = (React, props) => { + return React.createElement( + 'button', + { className: 'exampleCustomElement', onClick: props.onClick }, + 'r' + ); +} diff --git a/tests/ext/plugins/Custom Elements Example/components/vuecomponent.js b/tests/ext/plugins/Custom Elements Example/components/vuecomponent.js new file mode 100644 index 00000000..197f72cc --- /dev/null +++ b/tests/ext/plugins/Custom Elements Example/components/vuecomponent.js @@ -0,0 +1,13 @@ +module.exports = (VueWrap, props) => { + return VueWrap('somecomponent', { + render: function (createElement) { + return createElement('button', { + class: 'exampleCustomElement', + on: { + click: this.onClick + } + }, 'v'); + }, + props: ['onClick'] + }, props); +} diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js index 9c00fbe5..904d8982 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -5,10 +5,14 @@ module.exports = (Plugin, Api, Vendor) => { // Destructure some apis - const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector, Vuewrap } = Api; + const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector, Vuewrap, relative } = Api; const { Vue } = Vendor; const { React } = Reflection.modules; // This should be in vendor + // Import custom components from relative paths + const customVueComponent = relative('./components/vuecomponent'); + const customReactComponent = relative('./components/reactcomponent'); + return class extends Plugin { async onStart() { @@ -68,41 +72,9 @@ module.exports = (Plugin, Api, Vendor) => { // If children is not an array make it into one if (!child.children instanceof Array) child.children = [child.children]; - // Create custom components - const reactComponent = React.createElement( - 'button', - { className: 'exampleCustomElement', onClick: e => this.handleClick(e, child.channel) }, - 'r' - ); - - // Using Vue might be preferred to some - const vueComponent = Vue.component('somecomponent', { - render: createElement => { - return createElement('button', { - class: 'exampleCustomElement', - on: { - click: e => this.handleClick(e, child.channel) - } - }, 'v') - } - }); - - // You can also use Vuewrap which does the wrapping for us - const vueWrapComponent = Vuewrap('somecomponent', { - render: createElement => { - return createElement('button', { - class: 'exampleCustomElement', - on: { - click: e => this.handleClick(e, child.channel) - } - }, 'vw') - } - }); - // Add our custom components to children - child.children.push(reactComponent); - child.children.push(VueInjector.createReactElement(vueComponent)); // We need to wrap our vue component inside react - child.children.push(vueWrapComponent); + child.children.push(customReactComponent(React, { onClick: e => this.handleClick(e, child.channel) })); + child.children.push(customVueComponent(Vuewrap, { onClick: e => this.handleClick(e, child.channel) })); } /** From 8146e0e7f23374752706f87452c40dd486516367 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sun, 26 Aug 2018 05:03:54 +0300 Subject: [PATCH 7/9] Make pluginmanager delete all relative modules from cache insted --- client/src/modules/pluginapi.js | 9 --------- client/src/modules/pluginmanager.js | 6 ++++++ tests/ext/plugins/Custom Elements Example/index.js | 10 +++++----- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/client/src/modules/pluginapi.js b/client/src/modules/pluginapi.js index 9f933102..953a0ce2 100644 --- a/client/src/modules/pluginapi.js +++ b/client/src/modules/pluginapi.js @@ -58,15 +58,6 @@ export default class PluginApi { return null; } - relativeRequire(file) { - const absolutePath = path.join(this.pluginPath, file); - delete Globals.require.cache[Globals.require.resolve(absolutePath)]; - return Globals.require(absolutePath); - } - get relative() { - return this.relativeRequire.bind(this); - } - get Api() { return this } get AsyncEventEmitter() { return AsyncEventEmitter } diff --git a/client/src/modules/pluginmanager.js b/client/src/modules/pluginmanager.js index 079a9ae1..e1c0d04b 100644 --- a/client/src/modules/pluginmanager.js +++ b/client/src/modules/pluginmanager.js @@ -130,6 +130,12 @@ export default class extends ContentManager { static unloadContentHook(content, reload) { delete Globals.require.cache[Globals.require.resolve(content.paths.mainPath)]; + const uncache = []; + for (const required in Globals.require.cache) { + if (!required.includes(content.paths.contentPath)) continue; + uncache.push(Globals.require.resolve(required)); + } + for (const u of uncache) delete Globals.require.cache[u]; } /** diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js index 904d8982..d441bfee 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -2,17 +2,17 @@ * This is an example of how you should add custom elements instead of manipulating the DOM directly */ +// Import custom components +const customVueComponent = require('./components/vuecomponent'); +const customReactComponent = require('./components/reactcomponent'); + module.exports = (Plugin, Api, Vendor) => { // Destructure some apis - const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector, Vuewrap, relative } = Api; + const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector, Vuewrap, requireUncached } = Api; const { Vue } = Vendor; const { React } = Reflection.modules; // This should be in vendor - // Import custom components from relative paths - const customVueComponent = relative('./components/vuecomponent'); - const customReactComponent = relative('./components/reactcomponent'); - return class extends Plugin { async onStart() { From 6d8ef35bd642480a544f2e043ed5a5e1e9f0eacc Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sun, 26 Aug 2018 17:34:54 +0300 Subject: [PATCH 8/9] add api's for easy generic components --- client/src/modules/pluginapi.js | 2 + client/src/ui/components/generic/Button.vue | 21 +++++++++ .../src/ui/components/generic/ButtonGroup.vue | 23 ++++++++++ client/src/ui/components/generic/index.js | 29 ++++++++++++ .../plugins/Custom Elements Example/index.js | 44 ++++++++++++++++++- 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 client/src/ui/components/generic/Button.vue create mode 100644 client/src/ui/components/generic/ButtonGroup.vue create mode 100644 client/src/ui/components/generic/index.js diff --git a/client/src/modules/pluginapi.js b/client/src/modules/pluginapi.js index 953a0ce2..ac5bfae7 100644 --- a/client/src/modules/pluginapi.js +++ b/client/src/modules/pluginapi.js @@ -12,6 +12,7 @@ import { EmoteModule } from 'builtin'; import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs'; import { BdMenu, Modals, DOM, DOMObserver, VueInjector, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui'; import * as CommonComponents from 'commoncomponents'; +import { default as Components } from '../ui/components/generic'; import { Utils, Filters, ClientLogger as Logger, ClientIPC, AsyncEventEmitter } from 'common'; import Settings from './settings'; import ExtModuleManager from './extmodulemanager'; @@ -64,6 +65,7 @@ export default class PluginApi { get EventsWrapper() { return EventsWrapper } get CommonComponents() { return CommonComponents } + get Components() { return Components } get Filters() { return Filters } get Discord() { return DiscordApi } get DiscordApi() { return DiscordApi } diff --git a/client/src/ui/components/generic/Button.vue b/client/src/ui/components/generic/Button.vue new file mode 100644 index 00000000..190d5507 --- /dev/null +++ b/client/src/ui/components/generic/Button.vue @@ -0,0 +1,21 @@ +/** + * BetterDiscord Generic Button Component + * 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. +*/ + + + + diff --git a/client/src/ui/components/generic/ButtonGroup.vue b/client/src/ui/components/generic/ButtonGroup.vue new file mode 100644 index 00000000..d57011cd --- /dev/null +++ b/client/src/ui/components/generic/ButtonGroup.vue @@ -0,0 +1,23 @@ +/** + * BetterDiscord Generic Button Group Component + * 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. +*/ + + + + diff --git a/client/src/ui/components/generic/index.js b/client/src/ui/components/generic/index.js new file mode 100644 index 00000000..e89b4651 --- /dev/null +++ b/client/src/ui/components/generic/index.js @@ -0,0 +1,29 @@ +import VrWrapper from '../../vrwrapper'; + +import ButtonGroupComponent from './ButtonGroup.vue'; +class ButtonGroupWrapper extends VrWrapper { + get component() { return ButtonGroupComponent } + constructor(props) { + super(); + this.props = props; + } +} + +import ButtonComponent from './Button.vue'; +class ButtonWrapper extends VrWrapper { + get component() { return ButtonComponent } + constructor(props) { + super(); + this.props = props; + } +} + +export default class { + static Button(props) { + return new ButtonWrapper(props); + } + + static ButtonGroup(props) { + return new ButtonGroupWrapper(props); + } +} diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js index d441bfee..f54c8bda 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -19,6 +19,7 @@ module.exports = (Plugin, Api, Vendor) => { Logger.log('Custom Elements Example Started'); this.injectStyle(); this.patchGuildTextChannel(); + this.patchMessages(); return true; } @@ -31,6 +32,8 @@ module.exports = (Plugin, Api, Vendor) => { // Force update elements to remove our changes const GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel'); GuildTextChannel.forceUpdateAll(); + const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }); + MessageContent.forceUpdateAll(); return true; } @@ -47,7 +50,14 @@ module.exports = (Plugin, Api, Vendor) => { &:hover { opacity: 1; } - }`; + } + .exampleBtnGroup { + .bd-button { + font-size: 14px; + padding: 5px; + } + } + `; await CssUtils.injectSass(css); } @@ -59,6 +69,14 @@ module.exports = (Plugin, Api, Vendor) => { GuildTextChannel.forceUpdateAll(); } + async patchMessages() { + // Get Message component and patch it's render function + const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }); + monkeyPatch(MessageContent.component.prototype).after('render', this.injectGenericComponents.bind(this)); + // Force update to see our changes immediatly + MessageContent.forceUpdateAll(); + } + /* * Injecting a custom React element using React.createElement * https://reactjs.org/docs/react-api.html#createelement @@ -77,6 +95,30 @@ module.exports = (Plugin, Api, Vendor) => { child.children.push(customVueComponent(Vuewrap, { onClick: e => this.handleClick(e, child.channel) })); } + /** + * Inject generic components provided by BD + */ + injectGenericComponents(that, args, returnValue) { + // If children is not an array make it into one + if (!returnValue.props.children instanceof Array) returnValue.props.children = [returnValue.props.children]; + // Add a generic Button component provided by BD + returnValue.props.children.push(Api.Components.ButtonGroup({ + classes: [ 'exampleBtnGroup' ], // Additional classes for button group + buttons: [ + { + classes: ['exampleBtn'], // Additional classes for button + text: 'Hello World!', // Text for button + onClick: e => Logger.log('Hello World!') // Button click handler + }, + { + classes: ['exampleBtn'], + text: 'Button', + onClick: e => Logger.log('Button!') + } + ] + }).render()); // Render will return the wrapped component that can then be displayed + } + /** * Will log the channel object */ From b18559aa5e958d323185e32c4869b80b6c7bb523 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Sun, 26 Aug 2018 17:38:22 +0300 Subject: [PATCH 9/9] Rename to render example --- .../components/reactcomponent.js | 0 .../components/vuecomponent.js | 0 .../{Custom Elements Example => Render Example}/config.json | 6 +++--- .../{Custom Elements Example => Render Example}/index.js | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-) rename tests/ext/plugins/{Custom Elements Example => Render Example}/components/reactcomponent.js (100%) rename tests/ext/plugins/{Custom Elements Example => Render Example}/components/vuecomponent.js (100%) rename tests/ext/plugins/{Custom Elements Example => Render Example}/config.json (70%) rename tests/ext/plugins/{Custom Elements Example => Render Example}/index.js (97%) diff --git a/tests/ext/plugins/Custom Elements Example/components/reactcomponent.js b/tests/ext/plugins/Render Example/components/reactcomponent.js similarity index 100% rename from tests/ext/plugins/Custom Elements Example/components/reactcomponent.js rename to tests/ext/plugins/Render Example/components/reactcomponent.js diff --git a/tests/ext/plugins/Custom Elements Example/components/vuecomponent.js b/tests/ext/plugins/Render Example/components/vuecomponent.js similarity index 100% rename from tests/ext/plugins/Custom Elements Example/components/vuecomponent.js rename to tests/ext/plugins/Render Example/components/vuecomponent.js diff --git a/tests/ext/plugins/Custom Elements Example/config.json b/tests/ext/plugins/Render Example/config.json similarity index 70% rename from tests/ext/plugins/Custom Elements Example/config.json rename to tests/ext/plugins/Render Example/config.json index daac514d..ea3abb01 100644 --- a/tests/ext/plugins/Custom Elements Example/config.json +++ b/tests/ext/plugins/Render Example/config.json @@ -1,7 +1,7 @@ { "info": { - "id": "custom-elements", - "name": "Custom Elements Example", + "id": "render-example", + "name": "Render Example", "authors": [ { "name": "Jiiks", @@ -11,7 +11,7 @@ } ], "version": 1.0, - "description": "Custom Elements Description" + "description": "Example for rendering stuff" }, "main": "index.js" } diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Render Example/index.js similarity index 97% rename from tests/ext/plugins/Custom Elements Example/index.js rename to tests/ext/plugins/Render Example/index.js index f54c8bda..60297e5d 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Render Example/index.js @@ -16,7 +16,6 @@ module.exports = (Plugin, Api, Vendor) => { return class extends Plugin { async onStart() { - Logger.log('Custom Elements Example Started'); this.injectStyle(); this.patchGuildTextChannel(); this.patchMessages(); @@ -24,7 +23,6 @@ module.exports = (Plugin, Api, Vendor) => { } async onStop() { - Logger.log('Custom Elements Example Stopped'); // The automatic unpatcher is not there yet Patcher.unpatchAll(); CssUtils.deleteAllStyles();