From 0f805d57e3835f92cb355d314607b99c87eae443 Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Thu, 22 Mar 2018 02:13:32 +0000 Subject: [PATCH] More comments --- client/src/builtin/EmoteModule.js | 22 +++++-- client/src/modules/content.js | 27 ++++----- client/src/modules/contentmanager.js | 82 ++++++++++----------------- client/src/modules/csseditor.js | 51 +++++++++-------- client/src/modules/eventhook.js | 2 +- client/src/modules/globals.js | 32 +++++------ client/src/modules/pluginmanager.js | 36 ++++++------ client/src/modules/reactcomponents.js | 16 +++++- client/src/modules/thememanager.js | 4 +- client/src/modules/webpackmodules.js | 4 -- client/src/plugins/TimeStamps.js | 3 - client/src/plugins/index.js | 0 12 files changed, 134 insertions(+), 145 deletions(-) delete mode 100644 client/src/plugins/TimeStamps.js delete mode 100644 client/src/plugins/index.js diff --git a/client/src/builtin/EmoteModule.js b/client/src/builtin/EmoteModule.js index df3e2337..6de5693b 100644 --- a/client/src/builtin/EmoteModule.js +++ b/client/src/builtin/EmoteModule.js @@ -8,27 +8,33 @@ * LICENSE file in the root directory of this source tree. */ -import { FileUtils, ClientLogger as Logger } from 'common'; import { Events, Globals, WebpackModules, ReactComponents, MonkeyPatch } from 'modules'; import { DOM, VueInjector, Reflection } from 'ui'; +import { FileUtils, ClientLogger as Logger } from 'common'; +import path from 'path'; import EmoteComponent from './EmoteComponent.vue'; let emotes = null; const emotesEnabled = true; export default class { + static get searchCache() { return this._searchCache || (this._searchCache = {}); } + static get emoteDb() { return emotes; } + static get React() { return WebpackModules.getModuleByName('React'); } + static get ReactDOM() { return WebpackModules.getModuleByName('ReactDOM'); } + static processMarkup(markup) { if (!emotesEnabled) return markup; // TODO Get it from setttings const newMarkup = []; @@ -94,13 +100,20 @@ export default class { } static async observe() { - const dataPath = Globals.getObject('paths').find(path => path.id === 'data').path; + const dataPath = Globals.getPath('data'); + try { + emotes = await FileUtils.readJsonFromFile(path.join(dataPath, 'emotes.json')); + } catch (err) { + Logger.err('EmoteModule', [`Failed to load emote data. Make sure you've downloaded the emote data and placed it in ${dataPath}:`, err]); + return; + } + try { - emotes = await FileUtils.readJsonFromFile(dataPath + '/emotes.json'); const Message = await ReactComponents.getComponent('Message'); this.unpatchRender = MonkeyPatch('BD:EmoteModule', Message.component.prototype).after('render', (component, args, retVal) => { try { - const markup = this.findByProp(retVal, 'className', 'markup'); // First child has all the actual text content, second is the edited timestamp + // First child has all the actual text content, second is the edited timestamp + const markup = this.findByProp(retVal, 'className', 'markup'); if (!markup) return; markup.children[0] = this.processMarkup(markup.children[0]); } catch (err) { @@ -180,4 +193,5 @@ export default class { } }); } + } diff --git a/client/src/modules/content.js b/client/src/modules/content.js index fdc6c463..ce2047fd 100644 --- a/client/src/modules/content.js +++ b/client/src/modules/content.js @@ -59,6 +59,7 @@ export default class Content { /** * Opens a settings modal for this content. + * @return {Modal} */ showSettingsModal() { return Modals.contentSettings(this); @@ -73,16 +74,10 @@ export default class Content { /** * Saves the content's current configuration. + * @return {Promise} */ async saveConfiguration() { try { - /* - await FileUtils.writeFile(`${this.contentPath}/user.config.json`, JSON.stringify({ - enabled: this.enabled, - config: this.settings.strip().settings, - data: this.data - })); - */ Database.insertOrUpdate({ type: 'contentconfig', $or: [{ id: this.id }, { name: this.name }] }, { type: 'contentconfig', id: this.id, @@ -143,15 +138,6 @@ export default class Content { return this.events.on(...args); } - /** - * Removes an event listener. - * @param {String} event The event to remove the listener from - * @param {Function} callback The bound callback (optional) - */ - off(...args) { - return this.events.removeListener(...args); - } - /** * Adds an event listener that removes itself when called, therefore only being called once. * @param {String} event The event to add the listener to @@ -162,6 +148,15 @@ export default class Content { return this.events.once(...args); } + /** + * Removes an event listener. + * @param {String} event The event to remove the listener from + * @param {Function} callback The bound callback (optional) + */ + off(...args) { + return this.events.removeListener(...args); + } + /** * Emits an event. * @param {String} event The event to emit diff --git a/client/src/modules/contentmanager.js b/client/src/modules/contentmanager.js index 2826120c..55fcb18e 100644 --- a/client/src/modules/contentmanager.js +++ b/client/src/modules/contentmanager.js @@ -24,31 +24,31 @@ import Combokeys from 'combokeys'; export default class { /** - * Any errors that happened - * returns {Array} + * Any errors that happened. + * @return {Array} */ static get errors() { return this._errors || (this._errors = []); } /** - * Locallly stored content - * returns {Array} + * Locally stored content. + * @return {Array} */ static get localContent() { return this._localContent ? this._localContent : (this._localContent = []); } /** - * Local path for content - * returns {String} + * Local path for content. + * @return {String} */ static get contentPath() { return Globals.getPath(this.pathId); } /** - * Load all locally stored content + * Load all locally stored content. * @param {bool} suppressErrors Suppress any errors that occur during loading of content */ static async loadAllContent(suppressErrors = false) { @@ -83,8 +83,6 @@ export default class { }); this._errors = []; } - - return this.localContent; } catch (err) { throw err; } @@ -150,8 +148,6 @@ export default class { }); this._errors = []; } - - return this.localContent; } catch (err) { throw err; } @@ -169,15 +165,12 @@ export default class { await FileUtils.directoryExists(contentPath); - if (!reload) { - const loaded = this.localContent.find(content => content.contentPath === contentPath); - if (loaded) { - throw { 'message': `Attempted to load already loaded user content: ${path}` }; - } - } + if (!reload && this.getContentByPath(contentPath)) + throw { 'message': `Attempted to load already loaded user content: ${path}` }; - const readConfig = await this.readConfig(contentPath); - const mainPath = path.join(contentPath, readConfig.main); + const configPath = path.resolve(contentPath, 'config.json'); + const readConfig = await FileUtils.readJsonFromFile(configPath); + const mainPath = path.join(contentPath, readConfig.main || 'index.js'); const defaultConfig = new SettingsSet({ settings: readConfig.defaultConfig, @@ -191,17 +184,15 @@ export default class { }; try { - //const readUserConfig = await this.readUserConfig(contentPath); - const readUserConfig = await Database.find({ type: 'contentconfig', name: readConfig.info.name }); + const id = readConfig.info.id || readConfig.info.name.toLowerCase().replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-'); + const readUserConfig = await Database.find({ type: 'contentconfig', id }); if (readUserConfig.length) { userConfig.enabled = readUserConfig[0].enabled || false; - // await userConfig.config.merge({ settings: readUserConfig.config }); - // userConfig.config.setSaved(); - // userConfig.config = userConfig.config.clone({ settings: readUserConfig.config }); userConfig.config = readUserConfig[0].config; userConfig.data = readUserConfig[0].data || {}; } - } catch (err) { /*We don't care if this fails it either means that user config doesn't exist or there's something wrong with it so we revert to default config*/ + } catch (err) { + // We don't care if this fails it either means that user config doesn't exist or there's something wrong with it so we revert to default config Logger.info(this.moduleName, `Failed reading config for ${this.contentType} ${readConfig.info.name} in ${dirName}`); Logger.err(this.moduleName, err); } @@ -244,9 +235,10 @@ export default class { } /** - * Unload content - * @param {any} content Content to unload - * @param {bool} reload Whether to reload the content after + * Unload content. + * @param {Content|String} content Content to unload + * @param {Boolean} reload Whether to reload the content after + * @return {Content} */ static async unloadContent(content, reload) { content = this.findContent(content); @@ -275,34 +267,18 @@ export default class { } /** - * Reload content - * @param {any} content Content to reload + * Reload content. + * @param {Content|String} content Content to reload + * @return {Content} */ static reloadContent(content) { return this.unloadContent(content, true); } - /** - * Read content config file - * @param {any} configPath Config file path - */ - static async readConfig(configPath) { - configPath = path.resolve(configPath, 'config.json'); - return FileUtils.readJsonFromFile(configPath); - } - - /** - * Read content user config file - * @param {any} configPath User config file path - */ - static async readUserConfig(configPath) { - configPath = path.resolve(configPath, 'user.config.json'); - return FileUtils.readJsonFromFile(configPath); - } - /** * Checks if the passed object is an instance of this content type. - * @param {any} content Object to check + * @param {Any} content Object to check + * @return {Boolean} */ static isThisContent(content) { return content instanceof Content; @@ -318,8 +294,9 @@ export default class { /** * Wildcard content finder - * @param {any} wild Content ID / directory name / path / name - * @param {bool} nonunique Allow searching attributes that may not be unique + * @param {String} wild Content ID / directory name / path / name + * @param {Boolean} nonunique Allow searching attributes that may not be unique + * @return {Content} */ static findContent(wild, nonunique) { if (this.isThisContent(wild)) return wild; @@ -338,7 +315,8 @@ export default class { /** * Wait for content to load - * @param {any} content_id + * @param {String} content_id + * @return {Promise} */ static waitForContent(content_id) { return new Promise((resolve, reject) => { diff --git a/client/src/modules/csseditor.js b/client/src/modules/csseditor.js index ebc17c16..5dbd1846 100644 --- a/client/src/modules/csseditor.js +++ b/client/src/modules/csseditor.js @@ -32,7 +32,7 @@ export default new class { } /** - * Init css editor + * Init css editor. */ init() { ClientIPC.on('bd-get-scss', () => this.scss, true); @@ -60,16 +60,16 @@ export default new class { } /** - * Show css editor, flashes if already visible + * Show css editor, flashes if already visible. */ async show() { await ClientIPC.send('openCssEditor', this.editor_bounds); } /** - * Update css in client - * @param {String} scss scss to compile - * @param {bool} sendSource send to css editor instance + * Update css in client. + * @param {String} scss SCSS to compile + * @param {bool} sendSource Whether to send to css editor instance */ async updateScss(scss, sendSource) { if (sendSource) @@ -97,15 +97,15 @@ export default new class { } /** - * Save css to file + * Save css to file. */ async save() { Settings.saveSettings(); } /** - * Save current editor bounds - * @param {Rectangle} bounds editor bounds + * Save current editor bounds. + * @param {Rectangle} bounds Editor bounds */ saveEditorBounds(bounds) { this.editor_bounds = bounds; @@ -113,8 +113,8 @@ export default new class { } /** - * Send scss to core for compilation - * @param {String} scss scss string + * Send SCSS to core for compilation. + * @param {String} scss SCSS string */ async compile(scss) { return await ClientIPC.send('bd-compileSass', { @@ -124,7 +124,7 @@ export default new class { } /** - * Recompile the current SCSS + * Recompile the current SCSS. * @return {Promise} */ async recompile() { @@ -132,16 +132,18 @@ export default new class { } /** - * Send data to open editor - * @param {any} channel - * @param {any} data + * Send data to open editor. + * @param {String} channel + * @param {Any} data + * @return {Promise} */ async sendToEditor(channel, data) { return ClientIPC.sendToCssEditor(channel, data); } /** - * Opens an SCSS file in a system editor + * Opens an SCSS file in a system editor. + * @return {Promise} */ async openSystemEditor() { try { @@ -160,7 +162,8 @@ export default new class { throw {message: 'Failed to open system editor.'}; } - /** Set current state + /** + * Set current state * @param {String} scss Current uncompiled SCSS * @param {String} css Current compiled CSS * @param {String} files Files imported in the SCSS @@ -175,29 +178,28 @@ export default new class { } /** - * Current uncompiled scss + * Current uncompiled scss. */ get scss() { return this._scss || ''; } /** - * Set current scss + * Set current scss. */ set scss(scss) { this.updateScss(scss, true); } /** - * Current compiled css + * Current compiled css. */ get css() { return this._css || ''; } /** - * Inject compiled css to head - * {DOM} + * Inject compiled css to head. */ set css(css) { this._css = css; @@ -205,15 +207,14 @@ export default new class { } /** - * Current error + * Current error. */ get error() { return this._error || undefined; } /** - * Set current error - * {DOM} + * Set current error. */ set error(err) { this._error = err; @@ -293,7 +294,7 @@ export default new class { /** * Checks if the system editor's file exists. - * @return {Boolean} + * @return {Promise} */ async fileExists() { try { diff --git a/client/src/modules/eventhook.js b/client/src/modules/eventhook.js index d6ba83b4..c2665e18 100644 --- a/client/src/modules/eventhook.js +++ b/client/src/modules/eventhook.js @@ -52,7 +52,7 @@ export default class extends EventListener { /** * Discord emit overload - * @param {any} e + * @param {any} event * @param {any} action * @param {any} data */ diff --git a/client/src/modules/globals.js b/client/src/modules/globals.js index bb4792b4..6b0312f4 100644 --- a/client/src/modules/globals.js +++ b/client/src/modules/globals.js @@ -29,26 +29,24 @@ export default new class extends Module { this.getObject = this.getObject.bind(this); } - first() { - (async() => { - const config = await ClientIPC.send('getConfig'); - this.setState({ config }); + async first() { + const config = await ClientIPC.send('getConfig'); + this.setState({ config }); - // This is for Discord to stop error reporting :3 - window.BetterDiscord = { - version: config.version, - v: config.version - }; - window.jQuery = {}; + // This is for Discord to stop error reporting :3 + window.BetterDiscord = { + version: config.version, + v: config.version + }; + window.jQuery = {}; - if (sparkplug.bd) { - this.setState({ bd: sparkplug.bd }); - sparkplug.bd.setWS = this.setWS; - } + if (sparkplug.bd) { + this.setState({ bd: sparkplug.bd }); + sparkplug.bd.setWS = this.setWS; + } - Events.emit('global-ready'); - Events.emit('socket-created', this.state.wsHook); - })(); + Events.emit('global-ready'); + Events.emit('socket-created', this.state.wsHook); } setWS(wSocket) { diff --git a/client/src/modules/pluginmanager.js b/client/src/modules/pluginmanager.js index 9275eda2..181335a0 100644 --- a/client/src/modules/pluginmanager.js +++ b/client/src/modules/pluginmanager.js @@ -90,9 +90,7 @@ export default class extends ContentManager { for (const [key, value] of Object.entries(dependencies)) { const extModule = ExtModuleManager.findModule(key); if (!extModule) { - throw { - 'message': `Dependency: ${key}:${value} is not loaded` - }; + throw {message: `Dependency ${key}:${value} is not loaded.`}; } deps[key] = extModule.__require; } @@ -121,24 +119,24 @@ export default class extends ContentManager { static get unloadPlugin() { return this.unloadContent } static get reloadPlugin() { return this.reloadContent } - static stopPlugin(name) { - const plugin = name instanceof Plugin ? name : this.getPluginByName(name); - try { - if (plugin) return plugin.stop(); - } catch (err) { - // Logger.err('PluginManager', err); - } - return true; //Return true anyways since plugin doesn't exist + /** + * Stops a plugin. + * @param {Plugin|String} plugin + * @return {Promise} + */ + static stopPlugin(plugin) { + plugin = this.isPlugin(plugin) ? plugin : this.getPluginById(plugin); + return plugin.stop(); } - static startPlugin(name) { - const plugin = name instanceof Plugin ? name : this.getPluginByName(name); - try { - if (plugin) return plugin.start(); - } catch (err) { - // Logger.err('PluginManager', err); - } - return true; //Return true anyways since plugin doesn't exist + /** + * Starts a plugin. + * @param {Plugin|String} plugin + * @return {Promise} + */ + static startPlugin(plugin) { + plugin = this.isPlugin(plugin) ? plugin : this.getPluginById(plugin); + return plugin.start(); } static get isPlugin() { return this.isThisContent } diff --git a/client/src/modules/reactcomponents.js b/client/src/modules/reactcomponents.js index c0ed473c..4ba8137b 100644 --- a/client/src/modules/reactcomponents.js +++ b/client/src/modules/reactcomponents.js @@ -6,7 +6,7 @@ * 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 { MonkeyPatch, Patcher } from './patcher'; @@ -19,6 +19,7 @@ class Helpers { static get plannedActions() { return this._plannedActions || (this._plannedActions = new Map()); } + static recursiveArray(parent, key, count = 1) { let index = 0; function* innerCall(parent, key) { @@ -34,13 +35,15 @@ class Helpers { return innerCall(parent, key); } + static recursiveArrayCount(parent, key) { let count = 0; // eslint-disable-next-line no-empty-pattern - for (let { } of this.recursiveArray(parent, key)) + for (let {} of this.recursiveArray(parent, key)) ++count; return this.recursiveArray(parent, key, count); } + static get recursiveChildren() { return function* (parent, key, index = 0, count = 1) { const item = parent[key]; @@ -52,12 +55,14 @@ class Helpers { } } } + static returnFirst(iterator, process) { for (let child of iterator) { const retVal = process(child); if (retVal !== undefined) return retVal; } } + static getFirstChild(rootParent, rootKey, selector) { const getDirectChild = (item, selector) => { if (item && item.props && item.props.children) { @@ -116,11 +121,13 @@ class Helpers { }; return this.returnFirst(this.recursiveChildren(rootParent, rootKey), checkFilter.bind(null, selector)) || {}; } + static parseSelector(selector) { if (selector.startsWith('.')) return { className: selector.substr(1) } if (selector.startsWith('#')) return { id: selector.substr(1) } return {} } + static findByProp(obj, what, value) { if (obj.hasOwnProperty(what) && obj[what] === value) return obj; if (obj.props && !obj.children) return this.findByProp(obj.props, what, value); @@ -132,6 +139,7 @@ class Helpers { } return null; } + static findProp(obj, what) { if (obj.hasOwnProperty(what)) return obj[what]; if (obj.props && !obj.children) return this.findProp(obj.props, what); @@ -144,6 +152,7 @@ class Helpers { } return null; } + static get ReactDOM() { return WebpackModules.getModuleByName('ReactDOM'); } @@ -155,12 +164,15 @@ class ReactComponent { this._component = component; this._retVal = retVal; } + get id() { return this._id; } + get component() { return this._component; } + get retVal() { return this._retVal; } diff --git a/client/src/modules/thememanager.js b/client/src/modules/thememanager.js index dfaf7a37..2ddf8bd8 100644 --- a/client/src/modules/thememanager.js +++ b/client/src/modules/thememanager.js @@ -62,11 +62,11 @@ export default class ThemeManager extends ContentManager { } static enableTheme(theme) { - theme.enable(); + return theme.enable(); } static disableTheme(theme) { - theme.disable(); + return theme.disable(); } static get isTheme() { return this.isThisContent } diff --git a/client/src/modules/webpackmodules.js b/client/src/modules/webpackmodules.js index 71b03ecd..59bcf371 100644 --- a/client/src/modules/webpackmodules.js +++ b/client/src/modules/webpackmodules.js @@ -91,7 +91,6 @@ const KnownModules = { UserActivityStore: Filters.byProperties(['getActivity']), UserNameResolver: Filters.byProperties(['getName']), - /* Emoji Store and Utils */ EmojiInfo: Filters.byProperties(['isEmojiDisabled']), EmojiUtils: Filters.byProperties(['getGuildEmoji']), @@ -102,7 +101,6 @@ const KnownModules = { InviteResolver: Filters.byProperties(['findInvite']), InviteActions: Filters.byProperties(['acceptInvite']), - /* Discord Objects & Utils */ DiscordConstants: Filters.byProperties(["Permissions", "ActivityTypes", "StatusTypes"]), Permissions: Filters.byProperties(['getHighestRole']), @@ -128,7 +126,6 @@ const KnownModules = { ExperimentsManager: Filters.byProperties(['isDeveloper']), CurrentExperiment: Filters.byProperties(['getExperimentId']), - /* Images, Avatars and Utils */ ImageResolver: Filters.byProperties(["getUserAvatarURL"]), ImageUtils: Filters.byProperties(['getSizedImageSrc']), @@ -182,7 +179,6 @@ const KnownModules = { URLParser: Filters.byProperties(['Url', 'parse']), ExtraURLs: Filters.byProperties(['getArticleURL']), - /* DOM/React Components */ /* ==================== */ UserSettingsWindow: Filters.byProperties(['open', 'updateAccount']), diff --git a/client/src/plugins/TimeStamps.js b/client/src/plugins/TimeStamps.js deleted file mode 100644 index 3509c96a..00000000 --- a/client/src/plugins/TimeStamps.js +++ /dev/null @@ -1,3 +0,0 @@ -export default class { - -} diff --git a/client/src/plugins/index.js b/client/src/plugins/index.js deleted file mode 100644 index e69de29b..00000000