diff --git a/client/src/modules/contentconfig.js b/client/src/modules/contentconfig.js new file mode 100644 index 00000000..b5c23cca --- /dev/null +++ b/client/src/modules/contentconfig.js @@ -0,0 +1,31 @@ +/** + * BetterDiscord Content Config Utility + * 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. +*/ + + +export default class ContentConfig { + + constructor(data) { + this.data = data; + } + + map(cb) { + return this.data.map(cb); + } + + strip() { + return this.map(cat => ({ + category: cat.category, + settings: cat.settings.map(setting => ({ + id: setting.id, value: setting.value + })) + })); + } + +} diff --git a/client/src/modules/contentmanager.js b/client/src/modules/contentmanager.js index d13f9442..c53bbaf1 100644 --- a/client/src/modules/contentmanager.js +++ b/client/src/modules/contentmanager.js @@ -15,21 +15,40 @@ import { Events } from 'modules'; import { ErrorEvent } from 'structs'; import { Modals } from 'ui'; +/** + * Base class for external content managing + */ export default class { + /** + * Any errors that happened + * returns {Array} + */ static get errors() { return this._errors || (this._errors = []); } + /** + * Locallly stored content + * returns {Array} + */ static get localContent() { return this._localContent ? this._localContent : (this._localContent = []); } + /** + * Local path for content + * returns {String} + */ static get contentPath() { return this._contentPath ? this._contentPath : (this._contentPath = Globals.getObject('paths').find(path => path.id === this.pathId).path); } - static async loadAllContent(suppressErrors) { + /** + * Load all locally stored content + * @param {bool} suppressErrors Suppress any errors that occur during loading of content + */ + static async loadAllContent(suppressErrors = false) { try { await FileUtils.ensureDirectory(this.contentPath); const directories = await FileUtils.listDirectory(this.contentPath); @@ -64,6 +83,9 @@ export default class { } } + /** + * Refresh locally stored content + */ static async refreshContent() { if (!this.localContent.length) return this.loadAllContent(); @@ -97,6 +119,12 @@ export default class { } } + /** + * Common loading procedure for loading content before passing it to the actual loader + * @param {any} dirName Base directory for content + * @param {any} reload Is content being reloaded + * @param {any} index Index of content in {localContent} + */ static async preloadContent(dirName, reload = false, index) { try { const contentPath = path.join(this.contentPath, dirName); @@ -164,16 +192,28 @@ export default class { } } + /** + * 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); } + /** + * Wildcard content finder + * @param {any} wild Content name | id | path | dirname + */ //TODO make this nicer static findContent(wild) { let content = this.getContentByName(wild); @@ -191,6 +231,10 @@ export default class { static getContentByPath(path) { return this.localContent.find(c => c.contentPath === path) } static getContentByDirName(dirName) { return this.localContent.find(c => c.dirName === dirName) } + /** + * Wait for content to load + * @param {any} content_id + */ static waitForContent(content_id) { return new Promise((resolve, reject) => { const check = () => { diff --git a/client/src/modules/csseditor.js b/client/src/modules/csseditor.js index c6614417..9f686ded 100644 --- a/client/src/modules/csseditor.js +++ b/client/src/modules/csseditor.js @@ -12,8 +12,14 @@ import { ClientIPC } from 'common'; import Settings from './settings'; import { DOM } from 'ui'; +/** + * Custom css editor communications + */ export default class { + /** + * Init css editor + */ static init() { ClientIPC.on('bd-get-scss', () => this.sendToEditor('set-scss', { scss: this.scss })); ClientIPC.on('bd-update-scss', (e, scss) => this.updateScss(scss)); @@ -25,10 +31,18 @@ export default class { }); } + /** + * Show css editor, flashes if already visible + */ static 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 + */ static updateScss(scss, sendSource) { if (sendSource) this.sendToEditor('set-scss', { scss }); @@ -46,31 +60,57 @@ export default class { }); } + /** + * Save css to file + */ static async save() { Settings.saveSettings(); } + /** + * Save current editor bounds + * @param {Rectangle} bounds editor bounds + */ static saveEditorBounds(bounds) { this.editor_bounds = bounds; Settings.saveSettings(); } + /** + * Send scss to core for compilation + * @param {String} scss scss string + */ static async compile(scss) { return await ClientIPC.send('bd-compileSass', { data: scss }); } + /** + * Send css to open editor + * @param {any} channel + * @param {any} data + */ static async sendToEditor(channel, data) { return await ClientIPC.send('sendToCssEditor', { channel, data }); } + /** + * Current uncompiled scss + */ static get scss() { return this._scss || ''; } + /** + * Set current scss + */ static set scss(scss) { this.updateScss(scss, true); } + /** + * Inject compiled css to head + * {DOM} + */ static set css(css) { DOM.injectStyle(css, 'bd-customcss'); } diff --git a/client/src/modules/eventhook.js b/client/src/modules/eventhook.js index 7b5f8ca8..399fa6ac 100644 --- a/client/src/modules/eventhook.js +++ b/client/src/modules/eventhook.js @@ -17,6 +17,10 @@ import { } from '../structs/socketstructs'; +/** + * Discord socket event hook + * @extends {EventListener} + */ export default class extends EventListener { bindings() { @@ -29,14 +33,16 @@ export default class extends EventListener { ]; } - hook() { + hook() {} - } - - get eventsModule() { - - } + get eventsModule() {} + /** + * Discord emit overload + * @param {any} e + * @param {any} action + * @param {any} data + */ emit(e, action, data) { switch (e) { case 'dispatch': @@ -44,6 +50,11 @@ export default class extends EventListener { } } + /** + * Emit callback + * @param {any} e Event Action + * @param {any} d Event Args + */ dispatch(e, d) { Events.emit('raw-event', { type: e, data: d }); @@ -77,6 +88,9 @@ export default class extends EventListener { } } + /** + * All known socket actions + */ get actions() { return { READY: 'READY', // Socket ready diff --git a/client/src/modules/plugin.js b/client/src/modules/plugin.js index c4ae5c9d..25cca7a7 100644 --- a/client/src/modules/plugin.js +++ b/client/src/modules/plugin.js @@ -11,6 +11,7 @@ import { FileUtils } from 'common'; import { Modals } from 'ui'; import { EventEmitter } from 'events'; +import ContentConfig from './contentconfig'; import { SettingUpdatedEvent, SettingsUpdatedEvent } from 'structs'; class PluginEvents { @@ -85,7 +86,7 @@ export default class Plugin { const setting = category.settings.find(s => s.id === newSetting.id); if (setting.value === newSetting.value) continue; - let old_value = setting.value; + const old_value = setting.value; setting.value = newSetting.value; updatedSettings.push({ category_id: category.category, setting_id: setting.id, value: setting.value, old_value }); this.settingUpdated(category.category, setting.id, setting.value, old_value); @@ -108,20 +109,12 @@ export default class Plugin { } async saveConfiguration() { + window.testConfig = new ContentConfig(this.pluginConfig); try { + const config = new ContentConfig(this.pluginConfig).strip(); await FileUtils.writeFile(`${this.pluginPath}/user.config.json`, JSON.stringify({ enabled: this.enabled, - config: this.pluginConfig.map(category => { - return { - category: category.category, - settings: category.settings.map(setting => { - return { - id: setting.id, - value: setting.value - }; - }) - }; - }) + config })); } catch (err) { throw err; diff --git a/client/src/modules/theme.js b/client/src/modules/theme.js index d269926f..5cf124e9 100644 --- a/client/src/modules/theme.js +++ b/client/src/modules/theme.js @@ -13,6 +13,7 @@ import { EventEmitter } from 'events'; import { SettingUpdatedEvent, SettingsUpdatedEvent } from 'structs'; import { DOM, Modals } from 'ui'; import { FileUtils, ClientIPC } from 'common'; +import ContentConfig from './contentconfig'; class ThemeEvents { constructor(theme) { @@ -70,12 +71,12 @@ export default class Theme { const updatedSettings = []; for (let newCategory of newSettings) { - const category = this.pluginConfig.find(c => c.category === newCategory.category); + const category = this.themeConfig.find(c => c.category === newCategory.category); for (let newSetting of newCategory.settings) { const setting = category.settings.find(s => s.id === newSetting.id); if (setting.value === newSetting.value) continue; - let old_value = setting.value; + const old_value = setting.value; setting.value = newSetting.value; updatedSettings.push({ category_id: category.category, setting_id: setting.id, value: setting.value, old_value }); this.settingUpdated(category.category, setting.id, setting.value, old_value); @@ -102,19 +103,10 @@ export default class Theme { async saveConfiguration() { try { + const config = new ContentConfig(this.themeConfig).strip(); await FileUtils.writeFile(`${this.themePath}/user.config.json`, JSON.stringify({ enabled: this.enabled, - config: this.themeConfig.map(category => { - return { - category: category.category, - settings: category.settings.map(setting => { - return { - id: setting.id, - value: setting.value - }; - }) - }; - }), + config, css: this.css })); } catch (err) {