From 3437c36b87090813a1dd0555967a190ce566f065 Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Thu, 1 Mar 2018 19:00:24 +0000 Subject: [PATCH] Use settings structs --- client/src/modules/contentmanager.js | 43 +++--- client/src/modules/plugin.js | 44 ++---- client/src/modules/settings.js | 130 ++++++------------ client/src/modules/theme.js | 40 ++---- client/src/modules/thememanager.js | 62 +-------- client/src/structs/events/settingupdated.js | 18 ++- client/src/ui/components/bd/PluginsView.vue | 2 +- client/src/ui/components/bd/SettingsPanel.vue | 40 +----- client/src/ui/components/bd/ThemesView.vue | 2 +- .../ui/components/bd/modals/SettingsModal.vue | 79 ++++++----- client/src/ui/components/bd/setting/Array.vue | 70 +++------- .../src/ui/components/bd/setting/Dropdown.vue | 21 ++- client/src/ui/modals.js | 27 +--- 13 files changed, 193 insertions(+), 385 deletions(-) diff --git a/client/src/modules/contentmanager.js b/client/src/modules/contentmanager.js index ad5991bf..d0ad9266 100644 --- a/client/src/modules/contentmanager.js +++ b/client/src/modules/contentmanager.js @@ -12,7 +12,7 @@ import Globals from './globals'; import { FileUtils, ClientLogger as Logger } from 'common'; import path from 'path'; import { Events } from 'modules'; -import { ErrorEvent } from 'structs'; +import { SettingsSet, ErrorEvent } from 'structs'; import { Modals } from 'ui'; /** @@ -54,6 +54,10 @@ export default class { const directories = await FileUtils.listDirectory(this.contentPath); for (let dir of directories) { + try { + await FileUtils.directoryExists(path.join(this.contentPath, dir)); + } catch (err) { continue; } + try { await this.preloadContent(dir); } catch (err) { @@ -98,6 +102,10 @@ export default class { // If content is already loaded this should resolve. if (this.getContentByDirName(dir)) continue; + try { + await FileUtils.directoryExists(path.join(this.contentPath, dir)); + } catch (err) { continue; } + try { // Load if not await this.preloadContent(dir); @@ -168,37 +176,34 @@ export default class { const readConfig = await this.readConfig(contentPath); const mainPath = path.join(contentPath, readConfig.main); - readConfig.defaultConfig = readConfig.defaultConfig || []; - const userConfig = { enabled: false, - config: readConfig.defaultConfig + config: new SettingsSet({ + settings: readConfig.defaultConfig, + schemes: readConfig.configSchemes + }) }; + for (let category of userConfig.config.settings) { + for (let setting of category.settings) { + setting.setContentPath(contentPath); + } + } + try { const readUserConfig = await this.readUserConfig(contentPath); userConfig.enabled = readUserConfig.enabled || false; - for (let category of userConfig.config) { - const newCategory = readUserConfig.config.find(c => c.category === category.category); - - for (let setting of category.settings) { - setting.path = contentPath; - - if (!newCategory) continue; - const newSetting = newCategory.settings.find(s => s.id === setting.id); - if (!newSetting) continue; - - setting.value = newSetting.value; - } - } + userConfig.config.merge({ settings: readUserConfig.config }); + userConfig.config.setSaved(); userConfig.css = readUserConfig.css || null; } 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*/ - + console.info(`Failed reading config for ${this.contentType} ${readConfig.info.name} in ${dirName}`); + console.error(err); } const configs = { defaultConfig: readConfig.defaultConfig, - schemes: readConfig.configSchemes, + schemes: userConfig.schemes, userConfig }; diff --git a/client/src/modules/plugin.js b/client/src/modules/plugin.js index 1ae51846..2f75189b 100644 --- a/client/src/modules/plugin.js +++ b/client/src/modules/plugin.js @@ -42,6 +42,10 @@ export default class Plugin { this.hasSettings = this.config && this.config.length > 0; this.start = this.start.bind(this); this.stop = this.stop.bind(this); + + this.settings.on('setting-updated', event => this.events.emit('setting-updated', event)); + this.settings.on('settings-updated', event => this.events.emit('settings-updated', event)); + this.settings.on('settings-updated', event => this.saveConfiguration()); } get type() { return 'plugin' } @@ -61,7 +65,8 @@ export default class Plugin { get pluginPath() { return this.paths.contentPath } get dirName() { return this.paths.dirName } get enabled() { return this.userConfig.enabled } - get config() { return this.userConfig.config || [] } + get settings() { return this.userConfig.config } + get config() { return this.settings.settings } get pluginConfig() { return this.config } get exports() { return this._exports ? this._exports : (this._exports = this.getExports()) } get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new PluginEvents(this)) } @@ -81,45 +86,22 @@ export default class Plugin { } async saveSettings(newSettings) { - const updatedSettings = []; + const updatedSettings = this.settings.merge(newSettings); - for (let newCategory of newSettings) { - const category = this.config.find(c => c.category === newCategory.category); - for (let newSetting of newCategory.settings) { - const setting = category.settings.find(s => s.id === newSetting.id); - if (Utils.compare(setting.value, newSetting.value)) continue; - - 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); - } - } - - this.saveConfiguration(); - return this.settingsUpdated(updatedSettings); - } - - settingUpdated(category_id, setting_id, value, old_value) { - const event = new SettingUpdatedEvent({ category_id, setting_id, value, old_value }); - this.events.emit('setting-updated', event); - this.events.emit(`setting-updated_{$category_id}_${setting_id}`, event); - } - - settingsUpdated(updatedSettings) { - const event = new SettingsUpdatedEvent({ settings: updatedSettings.map(s => new SettingUpdatedEvent(s)) }); - this.events.emit('settings-updated', event); + await this.saveConfiguration(); + return updatedSettings; } async saveConfiguration() { - window.testConfig = new ContentConfig(this.config); try { - const config = new ContentConfig(this.config).strip(); await FileUtils.writeFile(`${this.pluginPath}/user.config.json`, JSON.stringify({ enabled: this.enabled, - config + config: this.settings.strip().settings })); + + this.settings.setSaved(); } catch (err) { + console.error(`Plugin ${this.id} configuration failed to save`, err); throw err; } } diff --git a/client/src/modules/settings.js b/client/src/modules/settings.js index ff07f7ac..b3273e74 100644 --- a/client/src/modules/settings.js +++ b/client/src/modules/settings.js @@ -13,7 +13,7 @@ import Globals from './globals'; import CssEditor from './csseditor'; import Events from './events'; import { Utils, FileUtils, ClientLogger as Logger } from 'common'; -import { SettingUpdatedEvent } from 'structs'; +import { SettingsSet, SettingUpdatedEvent } from 'structs'; import path from 'path'; export default class { @@ -25,24 +25,22 @@ export default class { const user_config = await FileUtils.readJsonFromFile(settingsPath); const { settings, scss, css_editor_bounds } = user_config; - this.settings = defaultSettings; - - for (let newSet of settings) { - let set = this.settings.find(s => s.id === newSet.id); - if (!set) continue; - - for (let newCategory of newSet.settings) { - let category = set.settings.find(c => c.category === newCategory.category); - if (!category) continue; - - for (let newSetting of newCategory.settings) { - let setting = category.settings.find(s => s.id === newSetting.id); - if (!setting) continue; - - setting.value = newSetting.value; - } - } - } + this.settings = defaultSettings.map(set => { + const newSet = new SettingsSet(set); + newSet.merge(settings.find(s => s.id === newSet.id)); + newSet.setSaved(); + newSet.on('setting-updated', event => { + const { category, setting, value, old_value } = event; + Logger.log('Settings', `${newSet.id}/${category.id}/${setting.id} was changed from ${old_value} to ${value}`); + Events.emit('setting-updated', event); + Events.emit(`setting-updated-${newSet.id}_${category.id}_${setting.id}`, event); + }); + newSet.on('settings-updated', async (event) => { + await this.saveSettings(); + Events.emit('settings-updated', event); + }); + return newSet; + }); CssEditor.updateScss(scss, true); CssEditor.editor_bounds = css_editor_bounds || {}; @@ -59,22 +57,7 @@ export default class { const settingsPath = path.resolve(this.dataPath, 'user.settings.json'); await FileUtils.writeJsonToFile(settingsPath, { - settings: this.getSettings.map(set => { - return { - id: set.id, - settings: set.settings.map(category => { - return { - category: category.category, - settings: category.settings.map(setting => { - return { - id: setting.id, - value: setting.value - }; - }) - }; - }) - }; - }), + settings: this.getSettings.map(set => set.strip()), scss: CssEditor.scss, css_editor_bounds: { width: CssEditor.editor_bounds.width, @@ -83,10 +66,14 @@ export default class { y: CssEditor.editor_bounds.y } }); + + for (let set of this.getSettings) { + set.setSaved(); + } } catch (err) { - // There was an error loading settings - // This probably means that the user doesn't have any settings yet + // There was an error saving settings Logger.err('Settings', err); + throw err; } } @@ -94,76 +81,37 @@ export default class { return this.getSettings.find(s => s.id === set_id); } + static get core() { return this.getSet('core') } + static get ui() { return this.getSet('ui') } + static get emotes() { return this.getSet('emotes') } + static get security() { return this.getSet('security') } + static getCategory(set_id, category_id) { const set = this.getSet(set_id); - if (!set) return; - - return set.settings.find(c => c.category === category_id); + return set ? set.getCategory(category_id) : undefined; } static getSetting(set_id, category_id, setting_id) { - const category = this.getCategory(set_id, category_id); - if (!category) return; - - return category.settings.find(s => s.id === setting_id); + const set = this.getSet(set_id); + return set ? set.getSetting(category_id, setting_id) : undefined; } static get(set_id, category_id, setting_id) { - const setting = this.getSetting(set_id, category_id, setting_id); - return setting ? setting.value : undefined; + const set = this.getSet(set_id); + return set ? set.get(category_id, setting_id) : undefined; } - static mergeSettings(set_id, newSettings, settingsUpdated) { + static async mergeSettings(set_id, newSettings) { const set = this.getSet(set_id); if (!set) return; - const updatedSettings = []; - for (let newCategory of newSettings) { - let category = set.settings.find(c => c.category === newCategory.category); - - for (let newSetting of newCategory.settings) { - let setting = category.settings.find(s => s.id === newSetting.id); - if (Utils.compare(setting.value, newSetting.value)) continue; - - let old_value = setting.value; - setting.value = newSetting.value; - updatedSettings.push({ set_id: set.id, category_id: category.category, setting_id: setting.id, value: setting.value, old_value }); - this.settingUpdated(set.id, category.category, setting.id, setting.value, old_value); - } - } - - this.saveSettings(); - return settingsUpdated ? settingsUpdated(updatedSettings) : updatedSettings; + return await set.merge(newSettings); } static setSetting(set_id, category_id, setting_id, value) { - for (let set of this.getSettings) { - if (set.id !== set_id) continue; - - for (let category of set.settings) { - if (category.category !== category_id) continue; - - for (let setting of category.settings) { - if (setting.id !== setting_id) continue; - if (Utils.compare(setting.value, value)) return true; - - let old_value = setting.value; - setting.value = value; - this.settingUpdated(set_id, category_id, setting_id, value, old_value); - return true; - } - } - } - - return false; - } - - static settingUpdated(set_id, category_id, setting_id, value, old_value) { - Logger.log('Settings', `${set_id}/${category_id}/${setting_id} was changed from ${old_value} to ${value}`); - - const event = new SettingUpdatedEvent({ set_id, category_id, setting_id, value, old_value }); - Events.emit('setting-updated', event); - Events.emit(`setting-updated-${set_id}_{$category_id}_${setting_id}`, event); + const setting = this.getSetting(set_id, category_id, setting_id); + if (!setting) throw {message: `Tried to set ${set_id}/${category_id}/${setting_id}, which doesn't exist`}; + setting.value = value; } static get getSettings() { diff --git a/client/src/modules/theme.js b/client/src/modules/theme.js index 1f2d8021..0659416d 100644 --- a/client/src/modules/theme.js +++ b/client/src/modules/theme.js @@ -42,6 +42,10 @@ export default class Theme { this.saveSettings = this.saveSettings.bind(this); this.enable = this.enable.bind(this); this.disable = this.disable.bind(this); + + this.settings.on('setting-updated', event => this.events.emit('setting-updated', event)); + this.settings.on('settings-updated', event => this.events.emit('settings-updated', event)); + this.settings.on('settings-updated', event => this.saveConfiguration()); } get configs() { return this.__themeInternals.configs } @@ -61,7 +65,8 @@ export default class Theme { get themePath() { return this.paths.contentPath } get dirName() { return this.paths.dirName } get enabled() { return this.userConfig.enabled } - get config() { return this.userConfig.config || [] } + get settings() { return this.userConfig.config } + get config() { return this.settings.settings } get themeConfig() { return this.config } get css() { return this.userConfig.css } get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new ThemeEvents(this)) } @@ -71,47 +76,24 @@ export default class Theme { } async saveSettings(newSettings) { - const updatedSettings = []; - - for (let newCategory of newSettings) { - const category = this.config.find(c => c.category === newCategory.category); - for (let newSetting of newCategory.settings) { - const setting = category.settings.find(s => s.id === newSetting.id); - if (Utils.compare(setting.value, newSetting.value)) continue; - - 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); - } - } + const updatedSettings = this.settings.merge(newSettings); // As the theme's configuration has changed it needs recompiling - // When the compiled CSS has been save it will also save the configuration + // When the compiled CSS has been saved it will also save the configuration await this.recompile(); return this.settingsUpdated(updatedSettings); } - settingUpdated(category_id, setting_id, value, old_value) { - const event = new SettingUpdatedEvent({ category_id, setting_id, value, old_value }); - this.events.emit('setting-updated', event); - this.events.emit(`setting-updated_{$category_id}_${setting_id}`, event); - } - - settingsUpdated(updatedSettings) { - const event = new SettingsUpdatedEvent({ settings: updatedSettings.map(s => new SettingUpdatedEvent(s)) }); - this.events.emit('settings-updated', event); - } - async saveConfiguration() { try { - const config = new ContentConfig(this.config).strip(); await FileUtils.writeFile(`${this.themePath}/user.config.json`, JSON.stringify({ enabled: this.enabled, - config, + config: this.settings.strip().settings, css: this.css })); + + this.settings.setSaved(); } catch (err) { throw err; } diff --git a/client/src/modules/thememanager.js b/client/src/modules/thememanager.js index 599ba83b..011d61d7 100644 --- a/client/src/modules/thememanager.js +++ b/client/src/modules/thememanager.js @@ -101,67 +101,9 @@ export default class ThemeManager extends ContentManager { static async parseSetting(setting) { const { type, id, value } = setting; const name = id.replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-'); + const scss = await setting.toSCSS(); - if (type === 'colour' || type === 'color') { - return [name, value]; - } - - if (type === 'array') { - const items = JSON.parse(JSON.stringify(value)) || []; - const settings_json = JSON.stringify(setting.settings); - - for (let item of items) { - const settings = JSON.parse(settings_json); - - for (let category of settings) { - const newCategory = item.settings.find(c => c.category === category.category); - for (let setting of category.settings) { - const newSetting = newCategory.settings.find(s => s.id === setting.id); - setting.value = setting.old_value = newSetting.value; - setting.changed = false; - } - } - - item.settings = settings; - } - - console.log('items', items); - - // Final comma ensures the variable is a list - const maps = []; - for (let item of items) - maps.push(await this.getConfigAsSCSSMap(item.settings)); - return [name, maps.length ? maps.join(', ') + ',' : '()']; - } - - if (type === 'file' && Array.isArray(value)) { - if (!value || !value.length) return [name, '()']; - - const files = []; - for (let filepath of value) { - const buffer = await FileUtils.readFileBuffer(path.resolve(setting.path, filepath)); - const type = await FileUtils.getFileType(buffer); - files.push(`(data: ${this.toSCSSString(buffer.toString('base64'))}, type: ${this.toSCSSString(type.mime)}, url: ${this.toSCSSString(await FileUtils.toDataURI(buffer, type.mime))})`); - } - - return [name, files.length ? files.join(', ') : '()']; - } - - if (type === 'slider') { - return [name, value * setting.multi || 1]; - } - - if (type === 'dropdown' || type === 'radio') { - return [name, setting.options.find(opt => opt.id === value).value]; - } - - if (typeof value === 'boolean' || typeof value === 'number') { - return [name, value]; - } - - if (typeof value === 'string') { - return [name, this.toSCSSString(value)]; - } + if (scss) return [name, scss]; } static toSCSSString(value) { diff --git a/client/src/structs/events/settingupdated.js b/client/src/structs/events/settingupdated.js index 0cc8ea08..9edbb19f 100644 --- a/client/src/structs/events/settingupdated.js +++ b/client/src/structs/events/settingupdated.js @@ -13,15 +13,27 @@ import Event from './event'; export default class SettingUpdatedEvent extends Event { get set() { - return this.args.set_id; + return this.args.set; + } + + get set_id() { + return this.args.set.id; } get category() { - return this.args.category_id; + return this.args.category; + } + + get category_id() { + return this.args.category.id; } get setting() { - return this.args.setting_id; + return this.args.setting; + } + + get setting_id() { + return this.args.setting.id; } get value() { diff --git a/client/src/ui/components/bd/PluginsView.vue b/client/src/ui/components/bd/PluginsView.vue index d2c2b8cf..9ce02dd6 100644 --- a/client/src/ui/components/bd/PluginsView.vue +++ b/client/src/ui/components/bd/PluginsView.vue @@ -21,7 +21,7 @@ -
+
diff --git a/client/src/ui/components/bd/SettingsPanel.vue b/client/src/ui/components/bd/SettingsPanel.vue index 367f1852..5eb86bed 100644 --- a/client/src/ui/components/bd/SettingsPanel.vue +++ b/client/src/ui/components/bd/SettingsPanel.vue @@ -13,7 +13,7 @@