Merge pull request #154 from samuelthomas2774/settings

Fix settingsset.findSetting and arraysetting.items
This commit is contained in:
Alexei Stukov 2018-03-05 04:51:19 +02:00 committed by GitHub
commit ccb5a1ce56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 116 additions and 164 deletions

View File

@ -8,27 +8,9 @@
* LICENSE file in the root directory of this source tree.
*/
import { AsyncEventEmitter } from 'common';
import { EventEmitter } from 'events';
class ExtModuleEvents {
constructor(extmodule) {
this.extmodule = extmodule;
this.emitter = new EventEmitter();
}
on(eventname, callback) {
this.emitter.on(eventname, callback);
}
off(eventname, callback) {
this.emitter.removeListener(eventname, callback);
}
emit(...args) {
this.emitter.emit(...args);
}
}
export default class ExtModule {
constructor(pluginInternals) {
@ -57,6 +39,6 @@ export default class ExtModule {
get enabled() { return true }
get config() { return this.userConfig.config || [] }
get data() { return this.userConfig.data || (this.userConfig.data = {}) }
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new ExtModuleEvents(this)) }
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new AsyncEventEmitter()) }
}

View File

@ -8,36 +8,17 @@
* LICENSE file in the root directory of this source tree.
*/
import { Utils, FileUtils } from 'common';
import { Utils, FileUtils, AsyncEventEmitter } from 'common';
import { Modals } from 'ui';
import { EventEmitter } from 'events';
import PluginManager from './pluginmanager';
import { SettingUpdatedEvent, SettingsUpdatedEvent } from 'structs';
class PluginEvents {
constructor(plugin) {
this.plugin = plugin;
this.emitter = new EventEmitter();
}
on(eventname, callback) {
this.emitter.on(eventname, callback);
}
off(eventname, callback) {
this.emitter.removeListener(eventname, callback);
}
emit(...args) {
this.emitter.emit(...args);
}
}
export default class Plugin {
constructor(pluginInternals) {
this.__pluginInternals = pluginInternals;
this.saveSettings = this.saveSettings.bind(this);
this.saveConfiguration = this.saveConfiguration.bind(this);
this.hasSettings = this.config && this.config.length > 0;
this.start = this.start.bind(this);
this.stop = this.stop.bind(this);
@ -70,29 +51,12 @@ export default class Plugin {
get pluginConfig() { return this.config }
get data() { return this.userConfig.data || (this.userConfig.data = {}) }
get exports() { return this._exports ? this._exports : (this._exports = this.getExports()) }
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new PluginEvents(this)) }
getSetting(setting_id, category_id) {
for (let category of this.config) {
if (category_id && category.category !== category_id) continue;
for (let setting of category.settings) {
if (setting.id !== setting_id) continue;
return setting.value;
}
}
}
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new AsyncEventEmitter()) }
showSettingsModal() {
return Modals.contentSettings(this);
}
async saveSettings(newSettings) {
const updatedSettings = this.settings.merge(newSettings);
await this.saveConfiguration();
return updatedSettings;
}
async saveConfiguration() {
try {
await FileUtils.writeFile(`${this.pluginPath}/user.config.json`, JSON.stringify({

View File

@ -13,34 +13,15 @@ import ThemeManager from './thememanager';
import { EventEmitter } from 'events';
import { SettingUpdatedEvent, SettingsUpdatedEvent } from 'structs';
import { DOM, Modals } from 'ui';
import { Utils, FileUtils, ClientIPC, ClientLogger as Logger } from 'common';
import { Utils, FileUtils, ClientIPC, ClientLogger as Logger, AsyncEventEmitter } from 'common';
import filewatcher from 'filewatcher';
class ThemeEvents {
constructor(theme) {
this.theme = theme;
this.emitter = new EventEmitter();
}
on(eventname, callback) {
this.emitter.on(eventname, callback);
}
off(eventname, callback) {
this.emitter.removeListener(eventname, callback);
}
emit(...args) {
this.emitter.emit(...args);
}
}
export default class Theme {
constructor(themeInternals) {
this.__themeInternals = themeInternals;
this.hasSettings = this.config && this.config.length > 0;
this.saveSettings = this.saveSettings.bind(this);
this.saveConfiguration = this.saveConfiguration.bind(this);
this.enable = this.enable.bind(this);
this.disable = this.disable.bind(this);
@ -79,22 +60,12 @@ export default class Theme {
get themeConfig() { return this.config }
get data() { return this.userConfig.data || (this.userConfig.data = {}) }
get css() { return this.data.css }
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new ThemeEvents(this)) }
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new AsyncEventEmitter()) }
showSettingsModal() {
return Modals.contentSettings(this);
}
async saveSettings(newSettings) {
const updatedSettings = this.settings.merge(newSettings);
// As the theme's configuration has changed it needs recompiling
// When the compiled CSS has been saved it will also save the configuration
await this.recompile();
return this.settingsUpdated(updatedSettings);
}
async saveConfiguration() {
try {
await FileUtils.writeFile(`${this.themePath}/user.config.json`, JSON.stringify({

View File

@ -101,17 +101,6 @@ export default class SettingsSet {
return false;
}
/**
* Return the first setting that matches the id in any category
*/
findFirst(settingId) {
for (let cat of this.categories) {
const found = cat.settings.find(s => s.id === settingId);
if (found) return found;
}
return null;
}
/**
* Returns the first category where calling {function} returns true.
* @param {Function} function A function to call to filter categories
@ -146,7 +135,7 @@ export default class SettingsSet {
*/
findSetting(f) {
for (let category of this.categories) {
const setting = category.findSetting(f);
const setting = category.find(f);
if (setting) return setting;
}
}

View File

@ -24,7 +24,7 @@ export default class ArraySetting extends Setting {
this.args.schemes = this.schemes.map(scheme => new SettingsScheme(scheme));
this.args.items = this.value ? this.value.map(item => this.createItem(item.args || item)) : [];
this.updateValue(false, false);
this._setValue(this.getValue());
}
/**
@ -131,43 +131,48 @@ export default class ArraySetting extends Setting {
* @return {SettingsSet} The new set
*/
createItem(item) {
if (item instanceof SettingsSet)
return item;
const set = new SettingsSet({
settings: Utils.deepclone(this.settings),
schemes: this.schemes
}, item ? item.args || item : undefined);
// if (item) set.merge(item.args || item);
set.setSaved();
set.on('settings-updated', () => this.updateValue());
return set;
}
/**
* Sets the value of this setting.
* This is only intended for use by settings.
* @param {SettingsSetting} value The new value of this setting
* @param {Boolean} emit_multi Whether to emit a SettingsUpdatedEvent
* @param {Boolean} emit Whether to emit a SettingUpdatedEvent
* @return {Promise}
* Function to be called after the value changes.
* This can be overridden by other settings types.
* @param {SettingUpdatedEvent} updatedSetting
*/
setValue(value, emit_multi = true, emit = true) {
this.args.items = value ? value.map(item => this.createItem(item)) : [];
this.updateValue(emit_multi, emit);
setValueHook(updatedSetting) {
this.args.items = updatedSetting.value ? updatedSetting.value.map(item => this.createItem(item)) : [];
}
/**
* Updates the value of this array setting.
* This only exists for use by array settings.
* @param {Boolean} emit_multi Whether to emit a SettingsUpdatedEvent
* @param {Boolean} emit Whether to emit a SettingUpdatedEvent
* @return {Promise}
*/
updateValue(emit_multi = true, emit = true) {
return this.__proto__.__proto__.setValue.call(this, this.items.map(item => {
getValue() {
return this.items.map(item => {
if (!item) return;
item.setSaved();
return item.strip();
}), emit_multi, emit);
});
}
/**
* Updates the value of this array setting.
* This only exists for use by array settings.
* @return {Promise}
*/
updateValue(emit_multi = true, emit = true) {
return this.setValue(this.getValue(), emit_multi, emit);
}
/**

View File

@ -107,75 +107,75 @@ export default class Setting {
*/
_merge(newSetting) {
const value = newSetting.args ? newSetting.args.value : newSetting.value;
const old_value = this.args.value;
if (Utils.compare(value, old_value)) return [];
this.args.value = value;
this.changed = !Utils.compare(this.args.value, this.args.saved_value);
return [{
setting: this, setting_id: this.id,
value, old_value
}];
return this._setValue(value);
}
/**
* Merges another setting into this setting.
* @param {SettingsSetting} newSetting The setting to merge into this setting
* @param {Boolean} emit_multi Whether to emit a SettingsUpdatedEvent
* @param {Boolean} emit Whether to emit a SettingUpdatedEvent
* @return {Promise}
*/
async merge(newSetting, emit_multi = true, emit = true) {
const value = newSetting.args ? newSetting.args.value : newSetting.value;
const updatedSettings = this._merge(newSetting);
if (!updatedSettings.length) return [];
const updatedSetting = updatedSettings[0];
if (emit)
await this.emit('setting-updated', updatedSetting);
if (emit_multi)
await this.emit('settings-updated', new SettingsUpdatedEvent({
updatedSettings
}));
return updatedSettings;
}
/**
* Sets the value of this setting.
* This only exists for use by the constructor and SettingsCategory.
*/
_setValue(value) {
const old_value = this.args.value;
if (Utils.compare(value, old_value)) return [];
this.args.value = value;
this.changed = !Utils.compare(this.args.value, this.args.saved_value);
const updatedSetting = {
const updatedSetting = new SettingUpdatedEvent({
setting: this, setting_id: this.id,
value, old_value
};
});
if (emit)
await this.emit('setting-updated', new SettingUpdatedEvent(updatedSetting));
if (emit_multi)
await this.emit('settings-updated', new SettingsUpdatedEvent({
updatedSettings: [updatedSetting]
}));
this.setValueHook(updatedSetting);
return [updatedSetting];
}
/**
* Function to be called after the value changes.
* This can be overridden by other settings types.
* @param {SettingUpdatedEvent} updatedSetting
*/
setValueHook(updatedSetting) {}
/**
* Sets the value of this setting.
* This is only intended for use by settings.
* @param {Any} value The new value of this setting
* @param {Boolean} emit_multi Whether to emit a SettingsUpdatedEvent
* @param {Boolean} emit Whether to emit a SettingUpdatedEvent
* @return {Promise}
*/
setValue(value, emit_multi = true, emit = true) {
const old_value = this.args.value;
if (Utils.compare(value, old_value)) return [];
this.args.value = value;
this.changed = !Utils.compare(this.args.value, this.args.saved_value);
const updatedSetting = {
setting: this, setting_id: this.id,
value, old_value
};
async setValue(value, emit_multi = true, emit = true) {
const updatedSettings = this._setValue(value);
if (!updatedSettings.length) return [];
if (emit)
this.emit('setting-updated', new SettingUpdatedEvent(updatedSetting));
await this.emit('setting-updated', updatedSettings[0]);
if (emit_multi)
this.emit('settings-updated', new SettingsUpdatedEvent({
updatedSettings: [updatedSetting]
await this.emit('settings-updated', new SettingsUpdatedEvent({
updatedSettings
}));
return [updatedSetting];
return updatedSettings;
}
/**

View File

@ -12,4 +12,22 @@ import Setting from './basesetting';
export default class NumberSetting extends Setting {
/**
* The current value.
*/
get value() {
return this.args.value * this.multi;
}
set value(value) {
this.setValue(value / this.multi);
}
/**
* A number to multiply the value by.
*/
get multi() {
return this.args.multi || 1;
}
}

View File

@ -12,6 +12,17 @@ import Setting from './basesetting';
export default class SliderSetting extends Setting {
/**
* The current value.
*/
get value() {
return this.args.value * this.multi;
}
set value(value) {
this.setValue(value / this.multi);
}
/**
* The value to use when the setting doesn't have a value.
*/
@ -47,6 +58,13 @@ export default class SliderSetting extends Setting {
return this.args.unit || '';
}
/**
* A number to multiply the value by.
*/
get multi() {
return this.args.multi || 1;
}
/**
* An object mapping points on the slider to labels.
*/

View File

@ -13,7 +13,7 @@
<div class="bd-title">
<h3 v-if="setting.text">{{setting.text}}</h3>
<div class="bd-number">
<input type="number" :value="setting.value" :min="setting.min" :max="setting.max" :step="setting.step" @keyup.stop @input="input"/>
<input type="number" :value="setting.value / setting.multi" :min="setting.min" :max="setting.max" :step="setting.step" @keyup.stop @input="input"/>
<div class="bd-number-spinner bd-flex bd-flex-col">
<div class="bd-arrow" @click="changeBy(true)"><div class="bd-up-arrow"></div></div>
<div class="bd-arrow" @click="changeBy(false)"><div class="bd-down-arrow"></div></div>
@ -31,11 +31,11 @@
let number = parseFloat(e.target.value)
if (Number.isNaN(number)) return;
this.change(number);
this.change(number * this.setting.multi);
},
changeBy(positive) {
let step = this.setting.step == undefined ? 1 : this.settings.step;
this.change(this.setting.value + (positive ? step : -step));
this.change((this.setting.value + (positive ? step : -step)) * this.setting.multi);
},
handleWheel() {} // No idea why this works but it does
},

View File

@ -21,9 +21,9 @@
<div class="bd-slider-bar-filled" :style="{width: `${getPointPosition() * 100}%`}"></div>
</div>
<div class="bd-slider-thumb-wrap">
<div class="bd-slider-thumb" v-tooltip="{content: (setting.value || '0') + setting.unit, show: toolTip, trigger: 'manual'}" :style="{left: `${getPointPosition() * 100}%`}"></div>
<div class="bd-slider-thumb" v-tooltip="{content: (value || '0') + setting.unit, show: toolTip, trigger: 'manual'}" :style="{left: `${getPointPosition() * 100}%`}"></div>
</div>
<input type="range" :value="setting.value" :min="setting.min || 0" :max="setting.max || 100" :step="setting.step || 1" @keyup.stop @input="input" />
<input type="range" :value="value" :min="setting.min || 0" :max="setting.max || 100" :step="setting.step || 1" @keyup.stop @input="input" />
</div>
</div>
</div>
@ -39,14 +39,19 @@
toolTip: false
};
},
computed: {
value() {
return this.setting.value / this.setting.multi;
}
},
methods: {
input(e) {
let number = parseFloat(e.target.value);
if (Number.isNaN(number)) return;
this.change(number);
this.change(number * this.setting.multi);
},
getPointPosition(value) {
return ((value || this.setting.value) - (this.setting.min || 0)) / ((this.setting.max || 100) - (this.setting.min || 0));
return ((value || this.value) - (this.setting.min || 0)) / ((this.setting.max || 100) - (this.setting.min || 0));
},
showTooltip() {
this.toolTip = true;