Use settings structs

This commit is contained in:
Samuel Elliott 2018-03-01 19:00:24 +00:00
parent 3574d6a5ba
commit 3437c36b87
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
13 changed files with 193 additions and 385 deletions

View File

@ -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
};

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -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;
}

View File

@ -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) {

View File

@ -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() {

View File

@ -21,7 +21,7 @@
</div>
</div>
<div class="bd-flex bd-flex-col bd-pluginsView">
<div class="bd-flex bd-flex-col bd-pluginsview">
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-plugins-container bd-local-plugins">
<PluginCard v-for="plugin in localPlugins" :plugin="plugin" :key="plugin.id" :togglePlugin="() => togglePlugin(plugin)" :reloadPlugin="() => reloadPlugin(plugin)" :deletePlugin="e => deletePlugin(plugin, e.shiftKey)" :showSettings="() => showSettings(plugin)" />
</div>

View File

@ -13,7 +13,7 @@
<div class="bd-settings-schemes" v-if="schemes && schemes.length">
<div class="bd-settings-schemes-container">
<template v-for="scheme in schemes">
<div class="bd-settings-scheme" :class="{'bd-active': checkSchemeActive(scheme)}" @click="() => setActiveScheme(scheme)">
<div class="bd-settings-scheme" :class="{'bd-active': scheme.isActive(settings)}" @click="() => scheme.applyTo(settings)">
<div class="bd-settings-scheme-icon" :style="{'background-image': `url(&quot;${scheme.icon_url}&quot;)`}"></div>
<div class="bd-settings-scheme-name" v-if="scheme.name">{{ scheme.name }}</div>
<div class="bd-settings-scheme-hint" v-if="scheme.hint">{{ scheme.hint }}</div>
@ -23,7 +23,7 @@
</div>
<div class="bd-settings-categories">
<template v-for="category in settings">
<template v-for="category in settings.categories">
<div class="bd-settings-category">
<div v-if="category.category === 'default' || !category.type">
<Setting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="v => settingChange(category, setting, v)" />
@ -53,47 +53,15 @@
import Drawer from '../common/Drawer.vue';
export default {
props: ['settings', 'schemes', 'change'],
props: ['settings', 'schemes'],
components: {
Setting,
Drawer
},
methods: {
checkSchemeActive(scheme) {
for (let schemeCategory of scheme.settings) {
const category = this.settings.find(c => c.category === schemeCategory.category);
if (!category) return false;
for (let schemeSetting of schemeCategory.settings) {
const setting = category.settings.find(s => s.id === schemeSetting.id);
if (!setting || !Utils.compare(setting.value, schemeSetting.value)) return false;
}
}
return true;
},
setActiveScheme(scheme) {
for (let schemeCategory of scheme.settings) {
const category = this.settings.find(c => c.category === schemeCategory.category);
if (!category) {
console.err(`Category ${schemeCategory.category} does not exist`);
continue;
}
for (let schemeSetting of schemeCategory.settings) {
const setting = category.settings.find(s => s.id === schemeSetting.id);
if (!setting) {
console.err(`Setting ${schemeCategory.category}/${schemeSetting.id} does not exist`);
continue;
}
this.change(category.category, setting.id, schemeSetting.value);
}
}
},
settingChange(category, setting, value) {
if (setting.disabled) return;
this.change(category.category, setting.id, value);
setting.value = value;
}
}
}

View File

@ -21,7 +21,7 @@
</div>
</div>
<div class="bd-flex bd-flex-col bd-themesView">
<div class="bd-flex bd-flex-col bd-themesview">
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-themes-container bd-local-themes">
<ThemeCard v-for="theme in localThemes" :theme="theme" :key="theme.id" :toggleTheme="() => toggleTheme(theme)" :reloadTheme="e => reloadTheme(theme, e.shiftKey)" :showSettings="() => showSettings(theme)" :deleteTheme="e => deleteTheme(theme, e.shiftKey)" />
</div>

View File

@ -11,7 +11,7 @@
<template>
<div class="bd-settings-modal" :class="{'bd-edited': changed}">
<Modal :headerText="modal.headertext" :close="modal.close" :class="{'bd-modal-out': modal.closing}">
<SettingsPanel :settings="configCache" :schemes="modal.schemes" :change="settingChange" slot="body" class="bd-settings-modal-body" />
<SettingsPanel :settings="settings" :schemes="modal.schemes" slot="body" class="bd-settings-modal-body" />
<div slot="footer" class="bd-footer-alert" :class="{'bd-active': changed, 'bd-warn': warnclose}" :style="{pointerEvents: changed ? 'all' : 'none'}">
<div class="bd-footer-alert-text">Unsaved changes</div>
<div class="bd-button bd-reset-button bd-tp" :class="{'bd-disabled': saving}" @click="resetSettings">Reset</div>
@ -34,9 +34,8 @@
props: ['modal'],
data() {
return {
changed: false,
warnclose: false,
configCache: [],
settings: null,
closing: false,
saving: false
}
@ -45,41 +44,32 @@
Modal,
SettingsPanel
},
computed: {
changed() {
return this.settings.categories.find(category => category.changed);
}
},
methods: {
checkForChanges() {
let changed = false;
for (let category of this.configCache) {
const cat = this.modal.settings.find(c => c.category === category.category);
for (let setting of category.settings) {
if (!Utils.compare(cat.settings.find(s => s.id === setting.id).value, setting.value)) {
changed = true;
Vue.set(setting, 'changed', true);
} else {
Vue.set(setting, 'changed', false);
}
}
}
return changed;
},
settingChange(category_id, setting_id, value) {
const category = this.configCache.find(c => c.category === category_id);
if (!category) return;
const setting = category.settings.find(s => s.id === setting_id);
if (!setting) return;
setting.value = value;
this.changed = this.checkForChanges();
this.$forceUpdate();
},
// settingChange(category_id, setting_id, value) {
// console.log(`Setting ${category_id}/${setting_id} to ${value}`, this.configCache);
//
// const category = this.configCache.find(c => c.category === category_id);
// if (!category) return;
//
// const setting = category.settings.find(s => s.id === setting_id);
// if (!setting) return;
//
// setting.value = value;
//
// // this.changed = this.checkForChanges();
// this.$forceUpdate();
// },
async saveSettings() {
if (this.saving) return;
this.saving = true;
try {
await this.modal.saveSettings(this.configCache);
this.configCache = JSON.parse(JSON.stringify(this.modal.settings));
this.changed = false;
if (this.modal.saveSettings) await this.modal.saveSettings(this.settings);
// this.cloneSettings();
} catch (err) {
// TODO Display error that settings failed to save
console.log(err);
@ -88,9 +78,14 @@
},
resetSettings() {
if (this.saving) return;
this.configCache = JSON.parse(JSON.stringify(this.modal.settings));
this.changed = false;
// this.configCache = JSON.parse(JSON.stringify(this.modal.settings));
// this.changed = false;
this.cloneSettings();
this.$forceUpdate();
},
cloneSettings() {
console.log('Cloning settings');
this.settings = this.modal.dont_clone ? this.modal.settings : this.modal.settings.clone();
}
},
created() {
@ -100,11 +95,19 @@
setTimeout(() => this.warnclose = false, 400);
throw {message: 'Settings have been changed'};
}
}
};
this.modal.settings.on('settings-updated', this.cloneSettings);
},
destroyed() {
this.modal.settings.off('settings-updated', this.cloneSettings);
},
beforeMount() {
this.configCache = JSON.parse(JSON.stringify(this.modal.settings));
this.changed = this.checkForChanges();
// this.configCache = JSON.parse(JSON.stringify(this.modal.settings));
// this.changed = this.checkForChanges();
console.log(this);
this.cloneSettings();
// this.settings = this.modal.dont_clone ? this.modal.settings : this.modal.settings.clone();
}
}
</script>

View File

@ -12,11 +12,11 @@
<div class="bd-form-settingsarray" :class="{'bd-form-settingsarray-inline': setting.inline}">
<div class="bd-title">
<h3>{{ setting.text }}</h3>
<button class="bd-button bd-button-primary" :class="{'bd-disabled': setting.disabled || setting.max && items.length >= setting.max}" @click="() => addItem(!setting.inline)">Add</button>
<button class="bd-button bd-button-primary" :class="{'bd-disabled': setting.disabled || setting.max && setting.items.length >= setting.max}" @click="() => addItem(!setting.inline)">Add</button>
</div>
<div class="bd-hint">{{ setting.hint }}</div>
<div class="bd-settingsarray-items">
<div class="bd-settingsarray-item" v-for="(item, index) in items">
<div class="bd-settingsarray-item" v-for="(item, index) in setting.items">
<div class="bd-settingsarray-item-marker">{{ index + 1 }}</div>
<SettingsPanel class="bd-settingsarray-item-contents" v-if="setting.inline" :settings="item.settings" :change="(c, s, v) => changeInItem(item, c, s, v)" />
@ -28,7 +28,7 @@
<div class="bd-settingsarray-item-controls">
<span class="bd-settingsarray-open" v-if="typeof setting.allow_external !== 'undefined' ? setting.allow_external || !setting.inline : true" @click="() => showModal(item, index)"><MiOpenInNew v-if="setting.inline" /><MiSettings v-else /></span>
<span class="bd-settingsarray-remove" :class="{'bd-disabled': setting.disabled || setting.min && items.length <= setting.min}" @click="() => removeItem(item)"><MiMinus /></span>
<span class="bd-settingsarray-remove" :class="{'bd-disabled': setting.disabled || setting.min && setting.items.length <= setting.min}" @click="() => removeItem(item)"><MiMinus /></span>
</div>
</div>
</div>
@ -47,29 +47,26 @@
components: {
MiSettings, MiOpenInNew, MiMinus
},
data() {
return {
items: []
};
},
watch: {
setting(value) {
// this.setting was changed
this.reloadSettings();
}
},
methods: {
addItem(openModal) {
if (this.setting.disabled || this.setting.max && this.items.length >= this.setting.max) return;
const item = { settings: this.getItemSettings({}) };
if (openModal) this.showModal(item, this.items.length);
this.items.push(item);
this.update();
if (this.setting.disabled || this.setting.max && this.setting.items.length >= this.setting.max) return;
// const item = { settings: this.getItemSettings({}) };
const item = this.setting.addItem();
if (openModal) this.showModal(item, this.setting.items.length);
// this.update();
// this.$forceUpdate();
},
removeItem(item) {
if (this.setting.disabled || this.setting.min && this.items.length <= this.setting.min) return;
this.items = this.items.filter(i => i !== item);
this.update();
if (this.setting.disabled || this.setting.min && this.setting.items.length <= this.setting.min) return;
// this.setting.items = this.setting.items.filter(i => i !== item);
this.setting.removeItem(item);
// this.update();
this.$forceUpdate();
},
changeInItem(item, category_id, setting_id, value) {
console.log('Setting', item, category_id, setting_id, 'to', value);
@ -82,50 +79,15 @@
setting.value = value;
setting.changed = !Utils.compare(setting.value, setting.old_value);
this.update();
},
update() {
this.change(this.items.map(item => ({
settings: item.settings ? item.settings.map(category => ({
category: category.category,
settings: category.settings.map(setting => ({
id: setting.id,
value: setting.value
}))
})) : []
})));
// this.update();
},
showModal(item, index) {
Modals.settings(this.setting.headertext ? this.setting.headertext.replace(/%n/, index + 1) : this.setting.text + ` #${index + 1}`, item.settings, this.setting.schemes, () => this.update());
},
getItemSettings(item) {
const settings = JSON.parse(JSON.stringify(this.setting.settings));
const newSettings = item.settings || [];
for (let newCategory of newSettings) {
const category = settings.find(c => c.category === newCategory.category);
if (!category) continue;
for (let newSetting of newCategory.settings) {
const setting = category.settings.find(s => s.id === newSetting.id);
if (!setting) continue;
setting.value = setting.old_value = newSetting.value;
setting.changed = false;
}
}
return settings;
},
reloadSettings() {
this.items = JSON.parse(JSON.stringify(this.setting.value)) || [];
this.items = this.items.map(item => ({ settings: this.getItemSettings(item) }));
Modals.settings(item, this.setting.headertext ? this.setting.headertext.replace(/%n/, index + 1) : this.setting.text + ` #${index + 1}`);
}
},
beforeCreate() {
// https://vuejs.org/v2/guide/components.html#Circular-References-Between-Components
this.$options.components.SettingsPanel = SettingsPanel;
},
beforeMount() {
this.reloadSettings();
}
}
</script>

View File

@ -12,7 +12,7 @@
<div class="bd-form-dropdown">
<div class="bd-title">
<h3 v-if="setting.text">{{setting.text}}</h3>
<Dropdown v-if="!setting.fullwidth" :options="setting.options" :selected="setting.value" :disabled="setting.disabled" :change="change" />
<Dropdown v-if="!setting.fullwidth" :options="setting.options" :selected="setting.args.value" :disabled="setting.disabled" :change="change" />
</div>
<div class="bd-hint">{{setting.hint}}</div>
<Dropdown v-if="setting.fullwidth" :options="setting.options" :selected="setting.value" :disabled="setting.disabled" :change="change" />
@ -25,6 +25,25 @@
props: ['setting', 'change'],
components: {
Dropdown
},
data() {
return {
active: false
};
},
methods: {
selectOption(option) {
this.active = false;
this.change(option.id);
}
},
mounted() {
document.addEventListener("click", e => {
let options = this.$refs.options;
if (options && !options.contains(e.target) && options !== e.target) {
this.active = false;
}
});
}
}
</script>

View File

@ -123,27 +123,11 @@ export default class {
}
}
static settings(headertext, settings, schemes, settingsUpdated, settingUpdated, saveSettings) {
static settings(settings, headertext, saveSettings) {
return this.add({
headertext, settings, schemes,
headertext, settings, schemes: settings.schemes,
saveSettings: saveSettings ? saveSettings : newSettings => {
const updatedSettings = [];
for (let newCategory of newSettings) {
let category = 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({ category_id: category.category, setting_id: setting.id, value: setting.value, old_value });
if (settingUpdated) settingUpdated(category.category, setting.id, setting.value, old_value);
}
}
return settingsUpdated ? settingsUpdated(updatedSettings) : updatedSettings;
return settings.merge(newSettings);
}
}, SettingsModal);
}
@ -151,11 +135,12 @@ export default class {
static internalSettings(set_id) {
const set = Settings.getSet(set_id);
if (!set) return;
return this.settings(set.headertext, set.settings, set.schemes, null, null, newSettings => Settings.mergeSettings(set.id, newSettings));
// return this.settings(set, set.headertext, newSettings => Settings.mergeSettings(set.id, newSettings));
return this.settings(set, set.headertext);
}
static contentSettings(content) {
return this.settings(content.name + ' Settings', content.config, content.configSchemes, null, null, content.saveSettings.bind(content));
return this.settings(content.settings, content.name + ' Settings');
}
static get stack() {