added new settings-system
parent
e0a83728d6
commit
d76ba519d4
@ -1,68 +1,592 @@
|
||||
"use strict";
|
||||
/* global define, socket, app */
|
||||
define(function () {
|
||||
|
||||
/*
|
||||
settings.js 2.0, because version 1:
|
||||
- saved everything in "config" hash
|
||||
- was hand-rolled (mm, salmon hand roll)
|
||||
- Relied on app.config (!!)
|
||||
This module should:
|
||||
- Allow you to save to any specified hash
|
||||
- Rely on jQuery
|
||||
- Use sockets
|
||||
- Be more awesome
|
||||
*/
|
||||
const DEFAULT_PLUGINS = [
|
||||
'settings/checkbox',
|
||||
'settings/textarea',
|
||||
'settings/select',
|
||||
'settings/array',
|
||||
'settings/key'
|
||||
];
|
||||
|
||||
define(function() {
|
||||
var Settings = {};
|
||||
var Settings,
|
||||
onReady = [],
|
||||
waitingJobs = 0,
|
||||
helper;
|
||||
|
||||
Settings.load = function(hash, formEl, callback) {
|
||||
socket.emit('admin.settings.get', {
|
||||
hash: hash
|
||||
}, function(err, values) {
|
||||
if (!err) {
|
||||
$(formEl).deserialize(values);
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
/*
|
||||
* Attributes of HTML-tags that get used by default plugins:
|
||||
* + data-key: the key to save/load the value within configuration-object
|
||||
* + data-type: highest priority type-definition to determine what kind of element it is or which plugin to hook
|
||||
* + type: normal priority type-definition
|
||||
* + data-empty: if 'false' or '0' then values that are assumed as empty turn into null. data-empty of arrays affect
|
||||
* their child-elements
|
||||
* + data-trim: if not 'false' or '0' then values will get trimmed as defined by the elements type
|
||||
* + data-split: if set and the element doesn't belong to any plugin, it's value will get split and joined by its
|
||||
* value into the input-field
|
||||
* array-elements:
|
||||
* + data-split: separator (HTML allowed) between the elements, defaults to ', '
|
||||
* + data-new: value to insert into new created elements
|
||||
* + data-attributes: an object to set the attributes of the child HTML-elements. tagName as special key will set
|
||||
* the tag-name of the child HTML-elements
|
||||
* key-fields:
|
||||
* + data-trim: if 'false' or '0' then the value will get saved as string else as object providing following
|
||||
* properties: ctrl, alt, shift, meta, code, char
|
||||
* + data-split: separator between different modifiers and the key-code of the value that gets saved
|
||||
* (only takes effect if trimming)
|
||||
* + data-short: if not 'false' or '0' then modifier-keys get saved as first uppercase character
|
||||
* (only takes effect if trimming)
|
||||
* select:
|
||||
* + data-options: an array of {"text":"Displayed Text","value":"some_value"}-like objects
|
||||
*
|
||||
* The name of the HTML-tag is lowest priority type-definition
|
||||
*
|
||||
* Examples-HTML:
|
||||
No!
|
||||
<input type="checkbox" data-key="cfg1"></input><br>
|
||||
Yes!
|
||||
<input type="checkbox" data-key="cfg2"></input><br>
|
||||
An array of checkboxes that are selected by default:
|
||||
<div data-key="cfg3" data-attributes='{"data-type":"checkbox"}' data-new='true'></div><br>
|
||||
A simple input-field of any common type:
|
||||
<input type="password" data-key="cfg4"></input><br>
|
||||
A simple textarea:
|
||||
<textarea data-key="cfg5"></textarea><br>
|
||||
Array of textareas:
|
||||
<div data-key="cfg6" data-attributes='{"data-type":"textarea"}' data-new='Hello Kitty, ahem... World!'></div><br>
|
||||
2D-Array of numbers that persist even when empty (but not empty rows):
|
||||
<div data-key="cfg7" data-split="<br>" data-attributes='{"data-type":"array","data-attributes":{"type":"number"}}' data-new='[42,21]'></div><br>
|
||||
Same with persisting empty rows, but not empty numbers, if no row is given null will get saved:
|
||||
<div data-key="cfg8" data-split="<br>" data-empty="false" data-attributes='{"data-type":"array","data-empty":true,"data-attributes":{"type":"number","data-empty":false}}' data-new='[42,21]'></div><br>
|
||||
Array of Key-shortcuts (new: Ctrl+Shift+7):
|
||||
<div data-key="cfg9" data-attributes='{"data-type":"key"}' data-new='Ctrl+Shift+#55'></div><br>
|
||||
Array of numbers (new: 42, step: 21):
|
||||
<div data-key="cfg10" data-attributes='{"data-type":"number","step":21}' data-new='42'></div><br>
|
||||
Select with dynamic options:
|
||||
<select data-key="cfg11" data-options='[{"value":"2","text":"2"},{"value":"3","text":"3"}]'></select><br>
|
||||
Select that loads faster:
|
||||
<select data-key="cfg12"><br>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
*
|
||||
* Matching configuration:
|
||||
{
|
||||
cfg1: false,
|
||||
cfg2: true,
|
||||
cfg3: [false, false, true],
|
||||
cfg4: 'hello world',
|
||||
cfg5: 'some\nlong\ntext',
|
||||
cfg6: ['some\nlong\ntexts', 'and another one'],
|
||||
cfg7: [[]],
|
||||
cfg8: [[]],
|
||||
cfg9: [],
|
||||
cfg10: [],
|
||||
cfg11: 3,
|
||||
cfg12: 2
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
Returns the hook of given name that matches the given type or element.
|
||||
@param type The type of the element to get the matching hook for, or the element itself.
|
||||
@param name The name of the hook.
|
||||
*/
|
||||
function getHook(type, name) {
|
||||
var hook, plugin;
|
||||
if (typeof type !== 'string') {
|
||||
type = $(type);
|
||||
type = type.data('type') || type.attr('type') || type.prop('tagName');
|
||||
}
|
||||
plugin = Settings.plugins[type.toLowerCase()];
|
||||
if (plugin == null) {
|
||||
return void 0;
|
||||
}
|
||||
hook = plugin[name];
|
||||
if (typeof hook === 'function') {
|
||||
return hook;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
helper = {
|
||||
/**
|
||||
@returns Object A deep clone of the given object.
|
||||
*/
|
||||
deepClone: function (obj) {
|
||||
if (typeof obj === 'object') {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
/**
|
||||
Creates a new Element with given data.
|
||||
@param tagName The tag-name of the element to create.
|
||||
@param data The attributes to set.
|
||||
@param text The text to add into the element.
|
||||
@returns HTMLElement The created element.
|
||||
*/
|
||||
createElement: function (tagName, data, text) {
|
||||
var element = document.createElement(tagName);
|
||||
for (var k in data) {
|
||||
element.setAttribute(k, data[k]);
|
||||
}
|
||||
if (text) {
|
||||
element.appendChild(document.createTextNode(text));
|
||||
}
|
||||
return element;
|
||||
},
|
||||
/**
|
||||
Calls the init-hook of the given element.
|
||||
@param element The element to initialize.
|
||||
*/
|
||||
initElement: function (element) {
|
||||
var hook = getHook(element, 'init');
|
||||
if (hook != null) {
|
||||
hook.call(Settings, $(element));
|
||||
}
|
||||
},
|
||||
/**
|
||||
Calls the destruct-hook of the given element.
|
||||
@param element The element to destruct.
|
||||
*/
|
||||
destructElement: function (element) {
|
||||
var hook = getHook(element, 'destruct');
|
||||
if (hook != null) {
|
||||
hook.call(Settings, $(element));
|
||||
}
|
||||
},
|
||||
/**
|
||||
Creates and initializes a new element.
|
||||
@param type The type of the new element.
|
||||
@param tagName The tag-name of the new element.
|
||||
@param data The data to forward to create-hook or use as attributes.
|
||||
@returns JQuery The created element.
|
||||
*/
|
||||
createElementOfType: function (type, tagName, data) {
|
||||
var element, hook = getHook(type, 'create');
|
||||
if (hook != null) {
|
||||
element = $(hook.call(Settings, type, tagName, data));
|
||||
} else {
|
||||
if (data == null) {
|
||||
data = {};
|
||||
}
|
||||
if (type != null) {
|
||||
data.type = type;
|
||||
}
|
||||
element = $(helper.createElement(tagName || 'input', data))
|
||||
}
|
||||
element.data('type', type);
|
||||
helper.initElement(element);
|
||||
return element;
|
||||
},
|
||||
/**
|
||||
Creates a new Array that contains values of given Array depending on trim and empty.
|
||||
@param array The array to clean.
|
||||
@param trim Whether to trim each value if it has a trim-function.
|
||||
@param empty Whether empty values should get added.
|
||||
@returns Array The filtered and/or modified Array.
|
||||
*/
|
||||
cleanArray: function (array, trim, empty) {
|
||||
var cleaned = [];
|
||||
if (!trim && empty) {
|
||||
return array;
|
||||
}
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
var value = array[i];
|
||||
if (trim) {
|
||||
value = value === true ? 1 : value === false ? 0 : typeof value.trim === 'function' ? value.trim() : value;
|
||||
}
|
||||
if (empty || (value != null ? value.length : void 0)) {
|
||||
cleaned.push(value);
|
||||
}
|
||||
}
|
||||
return cleaned;
|
||||
},
|
||||
isTrue: function (value) {
|
||||
return value === 'true' || +value === 1;
|
||||
},
|
||||
isFalse: function (value) {
|
||||
return value === 'false' || +value === 0;
|
||||
},
|
||||
/**
|
||||
Calls the get-hook of the given element and returns its result.
|
||||
If no hook is specified it gets treated as input-field.
|
||||
@param element The element of that the value should get read.
|
||||
@returns Object The value of the element.
|
||||
*/
|
||||
readValue: function (element) {
|
||||
var empty = !helper.isFalse(element.data('empty')),
|
||||
trim = !helper.isFalse(element.data('trim')),
|
||||
split = element.data('split'),
|
||||
hook = getHook(element, 'get'),
|
||||
value;
|
||||
if (hook != null) {
|
||||
return hook.call(Settings, element, trim, empty);
|
||||
}
|
||||
if (split != null) {
|
||||
empty = helper.isTrue(element.data('empty')); // default empty-value is false for arrays
|
||||
value = element.val();
|
||||
var array = (value != null ? value.split(split || ',') : void 0) || [];
|
||||
return helper.cleanArray(array, trim, empty);
|
||||
} else {
|
||||
value = element.val();
|
||||
if (trim && value != null && typeof value.trim === 'function') {
|
||||
value = value.trim();
|
||||
}
|
||||
if (empty || value !== void 0 && (value == null || value.length !== 0)) {
|
||||
return value;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
Calls the set-hook of the given element.
|
||||
If no hook is specified it gets treated as input-field.
|
||||
@param element The JQuery-Object of the element to fill.
|
||||
@param value The value to set.
|
||||
*/
|
||||
fillField: function (element, value) {
|
||||
var hook = getHook(element, 'set'),
|
||||
trim = element.data('trim');
|
||||
trim = trim !== 'false' && +trim !== 0;
|
||||
if (hook != null) {
|
||||
return hook.call(Settings, element, value, trim);
|
||||
}
|
||||
if (value instanceof Array) {
|
||||
value = value.join(element.data('split') || (trim ? ', ' : ','));
|
||||
}
|
||||
if (trim && value && typeof value.trim === 'function') {
|
||||
value = value.trim();
|
||||
if (typeof value.toString === 'function') {
|
||||
value = value.toString();
|
||||
}
|
||||
} else if (value != null) {
|
||||
if (typeof value.toString === 'function') {
|
||||
value = value.toString();
|
||||
}
|
||||
if (trim) {
|
||||
value = value.trim();
|
||||
}
|
||||
} else {
|
||||
value = '';
|
||||
}
|
||||
if (value !== void 0) {
|
||||
element.val(value);
|
||||
}
|
||||
},
|
||||
/**
|
||||
Calls the init-hook and {@link helper.fillField} on each field within wrapper-object.
|
||||
@param wrapper The wrapper-element to set settings within.
|
||||
*/
|
||||
initFields: function (wrapper) {
|
||||
$('[data-key]', wrapper).each(function (ignored, field) {
|
||||
field = $(field);
|
||||
var hook = getHook(field, 'init'),
|
||||
keyParts = field.data('key').split('.'),
|
||||
value = Settings.get();
|
||||
if (hook != null) {
|
||||
hook.call(Settings, field);
|
||||
}
|
||||
for (var i = 0; i < keyParts.length; i++) {
|
||||
var part = keyParts[i];
|
||||
if (part && value != null) {
|
||||
value = value[part];
|
||||
}
|
||||
}
|
||||
helper.fillField(field, value);
|
||||
});
|
||||
},
|
||||
/**
|
||||
Increases the amount of jobs before settings are ready by given amount.
|
||||
@param amount The amount of jobs to register.
|
||||
*/
|
||||
registerReadyJobs: function (amount) {
|
||||
return waitingJobs += amount;
|
||||
},
|
||||
/**
|
||||
Decreases the amount of jobs before settings are ready by given amount or 1.
|
||||
If the amount is less or equal 0 all callbacks registered by {@link helper.whenReady} get called.
|
||||
@param amount The amount of jobs that finished.
|
||||
*/
|
||||
beforeReadyJobsDecreased: function (amount) {
|
||||
if (amount == null) {
|
||||
amount = 1;
|
||||
}
|
||||
if (waitingJobs > 0) {
|
||||
waitingJobs -= amount;
|
||||
if (waitingJobs <= 0) {
|
||||
for (var i = 0; i < onReady.length; i++) {
|
||||
onReady[i]();
|
||||
}
|
||||
onReady = [];
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
Calls the given callback when the settings are ready.
|
||||
@param callback The callback.
|
||||
*/
|
||||
whenReady: function (callback) {
|
||||
if (waitingJobs <= 0) {
|
||||
callback();
|
||||
} else {
|
||||
console.log('[settings] Unable to load settings for hash: ', hash);
|
||||
onReady.push(callback);
|
||||
}
|
||||
},
|
||||
/**
|
||||
Persists the given settings with given hash.
|
||||
@param hash The hash to use as settings-id.
|
||||
@param settings The settings-object to persist.
|
||||
@param notify Whether to send notification when settings got saved.
|
||||
@param callback The callback to call when done.
|
||||
*/
|
||||
persistSettings: function (hash, settings, notify, callback) {
|
||||
if (settings != null && settings._settings != null && typeof settings._settings !== 'string') {
|
||||
settings = helper.deepClone(settings);
|
||||
settings._settings = JSON.stringify(settings._settings);
|
||||
}
|
||||
});
|
||||
socket.emit('admin.settings.set', {
|
||||
hash: hash,
|
||||
values: settings
|
||||
}, function (err) {
|
||||
if (notify) {
|
||||
if (err) {
|
||||
app.alert({
|
||||
title: 'Settings Not Saved',
|
||||
type: 'danger',
|
||||
message: "NodeBB failed to save the settings.",
|
||||
timeout: 5000
|
||||
});
|
||||
console.log('[settings] Unable to set settings for hash: ', hash);
|
||||
} else {
|
||||
app.alert({
|
||||
title: 'Settings Saved',
|
||||
type: 'success',
|
||||
timeout: 2500
|
||||
});
|
||||
}
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
callback(err);
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
Sets the settings to use to given settings.
|
||||
@param settings The settings to use.
|
||||
*/
|
||||
use: function (settings) {
|
||||
try {
|
||||
settings._settings = JSON.parse(settings._settings);
|
||||
} catch (_error) {}
|
||||
Settings.cfg = settings;
|
||||
}
|
||||
};
|
||||
|
||||
Settings.save = function(hash, formEl, callback) {
|
||||
formEl = $(formEl);
|
||||
|
||||
if (formEl.length) {
|
||||
var values = formEl.serializeObject();
|
||||
Settings = {
|
||||
helper: helper,
|
||||
plugins: {},
|
||||
cfg: {},
|
||||
|
||||
// "Fix" checkbox values, so that unchecked options are not omitted
|
||||
formEl.find('input[type="checkbox"]').each(function(idx, inputEl) {
|
||||
inputEl = $(inputEl);
|
||||
if (!inputEl.is(':checked')) {
|
||||
values[inputEl.attr('id')] = 'off';
|
||||
/**
|
||||
Returns the saved settings.
|
||||
@returns Object The settings.
|
||||
*/
|
||||
get: function () {
|
||||
if (Settings.cfg != null && Settings.cfg._settings !== void 0) {
|
||||
return Settings.cfg._settings;
|
||||
}
|
||||
return Settings.cfg;
|
||||
},
|
||||
/**
|
||||
Registers a new plugin and calls its use-hook.
|
||||
A plugin is an object containing a types-property to define its default bindings.
|
||||
A plugin may also provide the following properties of type function with [return-value] (parameters):
|
||||
use [void] - gets called when the Settings initializes the plugin.
|
||||
init [void] (element) - gets called on page-load and every time after the create-hook.
|
||||
; element: The element to initialize.
|
||||
create [JQuery-Object] (type, tagName, data) - gets called when a new HTML-instance needs to get created.
|
||||
; type: A string that identifies the plugin itself within this Settings-instance if set as data-type.
|
||||
; tagName: The tag-name that gets requested.
|
||||
; data: Additional data, plugin-dependent meaning.
|
||||
destruct [void] (element) - gets called after a HTML-instance got removed from DOM
|
||||
; element: The element that got removed.
|
||||
set [void] (element, value, trim) - gets called when the value of the element should be set to the given value.
|
||||
; element: The element to set its value.
|
||||
; value: The value to set.
|
||||
; trim: Whether the value is considered as trimmed.
|
||||
get [value] (element, trim, empty) - gets called when the value of the given instance is needed.
|
||||
; element: The element to get its value.
|
||||
; trim: Whether the result should be trimmed.
|
||||
; empty: Whether considered as empty values should get saved too.
|
||||
All passed elements are JQuery-Objects.
|
||||
@param service The plugin to register.
|
||||
@param types The types to bind the plugin to.
|
||||
*/
|
||||
registerPlugin: function (service, types) {
|
||||
if (types == null) {
|
||||
types = service.types;
|
||||
} else {
|
||||
service.types = types;
|
||||
}
|
||||
if (typeof service.use === 'function') {
|
||||
service.use.call(Settings);
|
||||
}
|
||||
for (var i = 0; i < types.length; i++) {
|
||||
var type = types[i].toLowerCase();
|
||||
if (Settings.plugins[type] == null) {
|
||||
Settings.plugins[type] = service;
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
Sets the settings to given ones, resets the fields within given wrapper and saves the settings server-side.
|
||||
@param hash The hash to use as settings-id.
|
||||
@param settings The settings to set.
|
||||
@param wrapper The wrapper-element to find settings within.
|
||||
@param callback The callback to call when done.
|
||||
@param notify Whether to send notification when settings got saved.
|
||||
*/
|
||||
set: function (hash, settings, wrapper, callback, notify) {
|
||||
if (notify == null) {
|
||||
notify = true;
|
||||
}
|
||||
helper.whenReady(function () {
|
||||
helper.use(settings);
|
||||
helper.initFields(wrapper || 'form');
|
||||
helper.persistSettings(hash, settings, notify, callback);
|
||||
});
|
||||
|
||||
socket.emit('admin.settings.set', {
|
||||
hash: hash,
|
||||
values: values
|
||||
}, function(err) {
|
||||
},
|
||||
/**
|
||||
Fetches the settings from server and calls {@link Settings.helper.initFields} once the settings are ready.
|
||||
@param hash The hash to use as settings-id.
|
||||
@param wrapper The wrapper-element to set settings within.
|
||||
@param callback The callback to call when done.
|
||||
*/
|
||||
sync: function (hash, wrapper, callback) {
|
||||
socket.emit('admin.settings.get', {
|
||||
hash: hash
|
||||
}, function (err, values) {
|
||||
if (err) {
|
||||
console.log('[settings] Unable to load settings for hash: ', hash);
|
||||
if (typeof callback === 'function') {
|
||||
callback(err);
|
||||
}
|
||||
} else {
|
||||
helper.whenReady(function () {
|
||||
helper.use(values);
|
||||
helper.initFields(wrapper || 'form');
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
Reads the settings from fields and saves them server-side.
|
||||
@param hash The hash to use as settings-id.
|
||||
@param wrapper The wrapper-element to find settings within.
|
||||
@param callback The callback to call when done.
|
||||
@param notify Whether to send notification when settings got saved.
|
||||
*/
|
||||
persist: function (hash, wrapper, callback, notify) {
|
||||
var notSaved = [],
|
||||
fields = $('[data-key]', wrapper || 'form').toArray();
|
||||
if (notify == null) {
|
||||
notify = true;
|
||||
}
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var field = $(fields[i]),
|
||||
value = helper.readValue(field),
|
||||
parentCfg = Settings.get(),
|
||||
keyParts = field.data('key').split('.'),
|
||||
lastKey = keyParts[keyParts.length - 1];
|
||||
if (keyParts.length > 1) {
|
||||
for (var j = 0; j < keyParts.length - 1; j++) {
|
||||
var part = keyParts[j];
|
||||
if (part && parentCfg != null) {
|
||||
parentCfg = parentCfg[part];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parentCfg != null) {
|
||||
if (value != null) {
|
||||
parentCfg[lastKey] = value;
|
||||
} else {
|
||||
delete parentCfg[lastKey];
|
||||
}
|
||||
} else {
|
||||
notSaved.push(field.data('key'));
|
||||
}
|
||||
}
|
||||
if (notSaved.length) {
|
||||
app.alert({
|
||||
title: 'Settings Saved',
|
||||
type: 'success',
|
||||
timeout: 2500
|
||||
title: 'Attributes Not Saved',
|
||||
message: "'" + (notSaved.join(', ')) + "' could not be saved. Please contact the plugin-author!",
|
||||
type: 'danger',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
helper.persistSettings(hash, Settings.cfg, notify, callback);
|
||||
},
|
||||
load: function(hash, formEl, callback) {
|
||||
socket.emit('admin.settings.get', {
|
||||
hash: hash
|
||||
}, function(err, values) {
|
||||
if (!err) {
|
||||
$(formEl).deserialize(values);
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
console.log('[settings] Unable to load settings for hash: ', hash);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('[settings] Form not found.');
|
||||
},
|
||||
save: function(hash, formEl, callback) {
|
||||
formEl = $(formEl);
|
||||
if (formEl.length) {
|
||||
var values = formEl.serializeObject();
|
||||
// "Fix" checkbox values, so that unchecked options are not omitted
|
||||
formEl.find('input[type="checkbox"]').each(function(idx, inputEl) {
|
||||
inputEl = $(inputEl);
|
||||
if (!inputEl.is(':checked')) {
|
||||
values[inputEl.attr('id')] = 'off';
|
||||
}
|
||||
});
|
||||
socket.emit('admin.settings.set', {
|
||||
hash: hash,
|
||||
values: values
|
||||
}, function(err) {
|
||||
app.alert({
|
||||
title: 'Settings Saved',
|
||||
type: 'success',
|
||||
timeout: 2500
|
||||
});
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('[settings] Form not found.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
helper.registerReadyJobs(1);
|
||||
require(DEFAULT_PLUGINS, function () {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
Settings.registerPlugin(arguments[i]);
|
||||
}
|
||||
helper.beforeReadyJobsDecreased();
|
||||
});
|
||||
|
||||
return Settings;
|
||||
|
||||
});
|
||||
|
@ -0,0 +1,147 @@
|
||||
define(function () {
|
||||
|
||||
var Settings = null,
|
||||
SettingsArray,
|
||||
helper = null;
|
||||
|
||||
/**
|
||||
Creates a new button that removes itself and the given elements on click.
|
||||
Calls {@link Settings.helper.destructElement} for each given field.
|
||||
@param elements The elements to remove on click.
|
||||
@returns JQuery The created remove-button.
|
||||
*/
|
||||
function createRemoveButton(elements) {
|
||||
var rm = $(helper.createElement('button', {
|
||||
"class": 'btn btn-xs btn-primary remove',
|
||||
title: 'Remove Item'
|
||||
}, '-'));
|
||||
rm.click(function (event) {
|
||||
event.preventDefault();
|
||||
elements.remove();
|
||||
rm.remove();
|
||||
elements.each(function (i, element) {
|
||||
element = $(element);
|
||||
if (element.is('[data-key]')) {
|
||||
helper.destructElement(element);
|
||||
}
|
||||
});
|
||||
});
|
||||
return rm;
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new child-element of given field with given data and calls given callback with elements to add.
|
||||
@param field Any wrapper that contains all fields of the array.
|
||||
@param key The key of the array.
|
||||
@param attributes The attributes to call {@link Settings.helper.createElementOfType} with or to add as
|
||||
element-attributes.
|
||||
@param value The value to call {@link Settings.helper.fillField} with.
|
||||
@param separator The separator to use.
|
||||
@param insertCb The callback to insert the elements.
|
||||
*/
|
||||
function addArrayChildElement(field, key, attributes, value, separator, insertCb) {
|
||||
attributes = helper.deepClone(attributes);
|
||||
var type = attributes['data-type'] || attributes.type || 'text',
|
||||
element = $(helper.createElementOfType(type, attributes.tagName, attributes));
|
||||
element.attr('data-parent', '_' + key);
|
||||
delete attributes['data-type'];
|
||||
delete attributes['tagName'];
|
||||
for (var name in attributes) {
|
||||
var val = attributes[name];
|
||||
if (name.search('data-') === 0) {
|
||||
element.data(name.substring(5), val);
|
||||
} else if (name.search('prop-') === 0) {
|
||||
element.prop(name.substring(5), val);
|
||||
} else {
|
||||
element.attr(name, val);
|
||||
}
|
||||
}
|
||||
helper.fillField(element, value);
|
||||
if ($("[data-parent=\"_" + key + "\"]", field).length) {
|
||||
insertCb(separator);
|
||||
}
|
||||
insertCb(element);
|
||||
insertCb(createRemoveButton(element.add(separator)));
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a new button that adds a new child-element to given element on click.
|
||||
@param element The element to insert the button.
|
||||
@param key The key to forward to {@link addArrayChildElement}.
|
||||
@param attributes The attributes to forward to {@link addArrayChildElement}.
|
||||
@param separator The separator to forward to {@link addArrayChildElement}.
|
||||
*/
|
||||
function addAddButton(element, key, attributes, separator) {
|
||||
var addSpace = $(document.createTextNode(' ')),
|
||||
newValue = element.data('new') || '',
|
||||
add = $(helper.createElement('button', {
|
||||
"class": 'btn btn-sm btn-primary add',
|
||||
title: 'Expand Array'
|
||||
}, '+'));
|
||||
add.click(function (event) {
|
||||
event.preventDefault();
|
||||
addArrayChildElement(element, key, attributes, newValue, separator.clone(), function (el) {
|
||||
addSpace.before(el);
|
||||
});
|
||||
});
|
||||
element.append(addSpace);
|
||||
element.append(add);
|
||||
}
|
||||
|
||||
|
||||
SettingsArray = {
|
||||
types: ['array', 'div'],
|
||||
use: function () {
|
||||
helper = (Settings = this).helper;
|
||||
},
|
||||
create: function (ignored, tagName) {
|
||||
return helper.createElement(tagName || 'div');
|
||||
},
|
||||
set: function (element, value) {
|
||||
var attributes = element.data('attributes'),
|
||||
key = element.data('key') || element.data('parent'),
|
||||
separator = element.data('split') || ', ';
|
||||
separator = (function () {
|
||||
try {
|
||||
return $(separator);
|
||||
} catch (_error) {
|
||||
return $(document.createTextNode(separator));
|
||||
}
|
||||
})();
|
||||
if (typeof attributes !== 'object') {
|
||||
attributes = {};
|
||||
}
|
||||
element.empty();
|
||||
if (!(value instanceof Array)) {
|
||||
value = [];
|
||||
}
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
addArrayChildElement(element, key, attributes, value[i], separator.clone(), function (el) {
|
||||
element.append(el);
|
||||
});
|
||||
}
|
||||
addAddButton(element, key, attributes, separator);
|
||||
},
|
||||
get: function (element, trim, empty) {
|
||||
var key = element.data('key') || element.data('parent'),
|
||||
children = $("[data-parent=\"_" + key + "\"]", element),
|
||||
values = [];
|
||||
children.each(function (i, child) {
|
||||
child = $(child);
|
||||
var val = helper.readValue(child),
|
||||
empty = helper.isTrue(child.data('empty'));
|
||||
if (empty || val !== void 0 && (val == null || val.length !== 0)) {
|
||||
return values.push(val);
|
||||
}
|
||||
});
|
||||
if (empty || values.length) {
|
||||
return values;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return SettingsArray;
|
||||
|
||||
});
|
@ -0,0 +1,36 @@
|
||||
define(function () {
|
||||
|
||||
var Settings = null,
|
||||
SettingsCheckbox;
|
||||
|
||||
SettingsCheckbox = {
|
||||
types: ['checkbox'],
|
||||
use: function () {
|
||||
Settings = this;
|
||||
},
|
||||
create: function () {
|
||||
return Settings.helper.createElement('input', {
|
||||
type: 'checkbox'
|
||||
});
|
||||
},
|
||||
set: function (element, value) {
|
||||
element.prop('checked', value);
|
||||
},
|
||||
get: function (element, trim, empty) {
|
||||
var value = element.prop('checked');
|
||||
if (value == null) {
|
||||
return void 0;
|
||||
}
|
||||
if (empty) {
|
||||
return value || void 0;
|
||||
}
|
||||
if (trim) {
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
return SettingsCheckbox;
|
||||
|
||||
});
|
@ -0,0 +1,221 @@
|
||||
define(function () {
|
||||
|
||||
var Settings = null,
|
||||
SettingsKey,
|
||||
helper = null,
|
||||
lastKey = null,
|
||||
oldKey = null,
|
||||
keyMap = Object.freeze({
|
||||
0: '',
|
||||
8: 'Backspace',
|
||||
9: 'Tab',
|
||||
13: 'Enter',
|
||||
27: 'Escape',
|
||||
32: 'Space',
|
||||
37: 'Left',
|
||||
38: 'Up',
|
||||
39: 'Right',
|
||||
40: 'Down',
|
||||
45: 'Insert',
|
||||
46: 'Delete',
|
||||
187: '=',
|
||||
189: '-',
|
||||
190: '.',
|
||||
191: '/',
|
||||
219: '[',
|
||||
220: '\\',
|
||||
221: ']'
|
||||
});
|
||||
|
||||
function Key() {
|
||||
this.c = false;
|
||||
this.a = false;
|
||||
this.s = false;
|
||||
this.m = false;
|
||||
this.code = 0;
|
||||
this.char = '';
|
||||
}
|
||||
|
||||
/**
|
||||
Returns either a Key-Object representing the given event or null if only modification-keys got released.
|
||||
@param event The event to inspect.
|
||||
@returns Key | null The Key-Object the focused element should be set to.
|
||||
*/
|
||||
function getKey(event) {
|
||||
var anyModChange = event.ctrlKey !== lastKey.c || event.altKey !== lastKey.a || event.shiftKey !== lastKey.s || event.metaKey !== lastKey.m,
|
||||
modChange = event.ctrlKey + event.altKey + event.shiftKey + event.metaKey - lastKey.c - lastKey.a - lastKey.s - lastKey.m,
|
||||
key = new Key();
|
||||
key.c = event.ctrlKey;
|
||||
key.a = event.altKey;
|
||||
key.s = event.shiftKey;
|
||||
key.m = event.metaKey;
|
||||
lastKey = key;
|
||||
if (anyModChange) {
|
||||
if (modChange < 0) {
|
||||
return null;
|
||||
}
|
||||
key.code = oldKey.code;
|
||||
key.char = oldKey.char;
|
||||
} else {
|
||||
key.code = event.which;
|
||||
key.char = convertKeyCodeToChar(key.code);
|
||||
}
|
||||
return oldKey = key;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the string that represents the given key-code.
|
||||
@param code The key-code.
|
||||
@returns String Representation of the given key-code.
|
||||
*/
|
||||
function convertKeyCodeToChar(code) {
|
||||
code = +code;
|
||||
if (code === 0) {
|
||||
return '';
|
||||
} else if (code >= 48 && code <= 90) {
|
||||
return String.fromCharCode(code).toUpperCase();
|
||||
} else if (code >= 112 && code <= 123) {
|
||||
return "F" + (code - 111);
|
||||
} else {
|
||||
return keyMap[code] || ("#" + code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a string to identify a Key-Object.
|
||||
@param key The Key-Object that should get identified.
|
||||
@param human Whether to show 'Enter a key' when key-char is empty.
|
||||
@param short Whether to shorten modification-names to first character.
|
||||
@param separator The separator between modification-names and key-char.
|
||||
@returns String The string to identify the given key-object the given way.
|
||||
*/
|
||||
function getKeyString(key, human, short, separator) {
|
||||
var str = '';
|
||||
if (!(key instanceof Key)) {
|
||||
return str;
|
||||
}
|
||||
if (!key.char) {
|
||||
if (human) {
|
||||
return 'Enter a key';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
if (!separator || /CtrlAShifMea#/.test(separator)) {
|
||||
separator = human ? ' + ' : '+';
|
||||
}
|
||||
if (key.c) {
|
||||
str += (short ? 'C' : 'Ctrl') + separator;
|
||||
}
|
||||
if (key.a) {
|
||||
str += (short ? 'A' : 'Alt') + separator;
|
||||
}
|
||||
if (key.s) {
|
||||
str += (short ? 'S' : 'Shift') + separator;
|
||||
}
|
||||
if (key.m) {
|
||||
str += (short ? 'M' : 'Meta') + separator;
|
||||
}
|
||||
return str + (human ? key.char : key.code ? '#' + key.code : '');
|
||||
}
|
||||
|
||||
/**
|
||||
Parses the given string into a Key-Object.
|
||||
@param str The string to parse.
|
||||
@returns Key The Key-Object that got identified by the given string.
|
||||
*/
|
||||
function getKeyFromString(str) {
|
||||
if (str instanceof Key) {
|
||||
return str;
|
||||
}
|
||||
var key = new Key(),
|
||||
sep = /([^CtrlAShifMea#\d]+)(?:#|\d)/.exec(str),
|
||||
parts = sep != null ? str.split(sep[1]) : [str];
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var part = parts[i];
|
||||
switch (part) {
|
||||
case 'C':
|
||||
case 'Ctrl':
|
||||
key.c = true;
|
||||
break;
|
||||
case 'A':
|
||||
case 'Alt':
|
||||
key.a = true;
|
||||
break;
|
||||
case 'S':
|
||||
case 'Shift':
|
||||
key.s = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'Meta':
|
||||
key.m = true;
|
||||
break;
|
||||
default:
|
||||
var num = /\d+/.exec(part);
|
||||
if (num != null) {
|
||||
key.code = num[0];
|
||||
}
|
||||
key.char = convertKeyCodeToChar(key.code);
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
function handleEvent(element, event) {
|
||||
event = event || window.event;
|
||||
event.which = event.which || event.keyCode || event.key;
|
||||
var key = getKey(event);
|
||||
if (key != null) {
|
||||
SettingsKey.set(element, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SettingsKey = {
|
||||
types: ['key'],
|
||||
use: function () {
|
||||
helper = (Settings = this).helper;
|
||||
},
|
||||
init: function (element) {
|
||||
element.focus(function () {
|
||||
oldKey = element.data('keyData') || new Key();
|
||||
lastKey = new Key();
|
||||
}).keydown(function (event) {
|
||||
event.preventDefault();
|
||||
handleEvent(element, event);
|
||||
}).keyup(function (event) {
|
||||
handleEvent(element, event);
|
||||
});
|
||||
return element;
|
||||
},
|
||||
set: function (element, value) {
|
||||
var key = getKeyFromString(value || '');
|
||||
element.data('keyData', key);
|
||||
if (key.code) {
|
||||
element.removeClass('alert-danger');
|
||||
} else {
|
||||
element.addClass('alert-danger');
|
||||
}
|
||||
element.val(getKeyString(key, true, false, ' + '));
|
||||
},
|
||||
get: function (element, trim, empty) {
|
||||
var key = element.data('keyData'),
|
||||
separator = element.data('split') || element.data('separator') || '+',
|
||||
short = !helper.isFalse(element.data('short'));
|
||||
if (trim) {
|
||||
if (empty || (key != null && key.char)) {
|
||||
return getKeyString(key, false, short, separator);
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
} else if (empty || (key != null && key.code)) {
|
||||
return key;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return SettingsKey;
|
||||
|
||||
});
|
@ -0,0 +1,49 @@
|
||||
define(function () {
|
||||
|
||||
var Settings = null,
|
||||
SettingsSelect;
|
||||
|
||||
function addOptions(element, options) {
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var optionData = options[i],
|
||||
value = optionData.text || optionData.value;
|
||||
delete optionData.text;
|
||||
element.append($(Settings.helper.createElement('option', optionData)).text(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SettingsSelect = {
|
||||
types: ['select'],
|
||||
use: function () {
|
||||
Settings = this;
|
||||
},
|
||||
create: function (ignore, ignored, data) {
|
||||
var element = $(Settings.helper.createElement('select'));
|
||||
// prevent data-options from being attached to DOM
|
||||
addOptions(element, data['data-options']);
|
||||
delete data['data-options'];
|
||||
return element;
|
||||
},
|
||||
init: function (element) {
|
||||
var options = element.data('options');
|
||||
if (options != null) {
|
||||
addOptions(element, options);
|
||||
}
|
||||
},
|
||||
set: function (element, value) {
|
||||
element.val(value || '');
|
||||
},
|
||||
get: function (element, ignored, empty) {
|
||||
var value = element.val();
|
||||
if (empty || value) {
|
||||
return value;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return SettingsSelect;
|
||||
|
||||
});
|
@ -0,0 +1,35 @@
|
||||
define(function () {
|
||||
|
||||
var Settings = null,
|
||||
SettingsArea;
|
||||
|
||||
SettingsArea = {
|
||||
types: ['textarea'],
|
||||
use: function () {
|
||||
Settings = this;
|
||||
},
|
||||
create: function () {
|
||||
return Settings.helper.createElement('textarea');
|
||||
},
|
||||
set: function (element, value, trim) {
|
||||
if (trim && value != null && typeof value.trim === 'function') {
|
||||
value = value.trim();
|
||||
}
|
||||
element.val(value || '');
|
||||
},
|
||||
get: function (element, trim, empty) {
|
||||
var value = element.val();
|
||||
if (trim) {
|
||||
value = value == null ? void 0 : value.trim();
|
||||
}
|
||||
if (empty || value) {
|
||||
return value;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return SettingsArea;
|
||||
|
||||
});
|
@ -0,0 +1,233 @@
|
||||
var meta = require('./meta');
|
||||
|
||||
function expandObjBy(obj1, obj2) {
|
||||
var key, val1, val2;
|
||||
for (key in obj2) {
|
||||
val2 = obj2[key];
|
||||
val1 = obj1[key];
|
||||
if (!obj1.hasOwnProperty(key) || typeof val2 !== typeof val1) {
|
||||
obj1[key] = val2;
|
||||
} else if (typeof val2 === 'object') {
|
||||
expandObjBy(val1, val2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function trim(obj1, obj2) {
|
||||
var key, val1;
|
||||
for (key in obj1) {
|
||||
val1 = obj1[key];
|
||||
if (!obj2.hasOwnProperty(key)) {
|
||||
delete obj1[key];
|
||||
} else if (typeof val1 === 'object') {
|
||||
trim(val1, obj2[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mergeSettings(cfg, defCfg) {
|
||||
if (typeof cfg._settings !== typeof defCfg || typeof defCfg !== 'object') {
|
||||
return cfg._settings = defCfg;
|
||||
} else {
|
||||
expandObjBy(cfg._settings, defCfg);
|
||||
trim(cfg._settings, defCfg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
A class to manage Objects saved in {@link meta.settings} within property "_settings".
|
||||
Constructor, synchronizes the settings and repairs them if version differs.
|
||||
@param hash The hash to use for {@link meta.settings}.
|
||||
@param version The version of the settings, used to determine whether the saved settings may be corrupt.
|
||||
@param defCfg The default settings.
|
||||
@param callback Gets called once the Settings-object is ready.
|
||||
@param forceUpdate Whether to trigger structure-update even if the version doesn't differ from saved one.
|
||||
Should be true while plugin-development to ensure structure-changes within settings persist.
|
||||
@param reset Whether to reset the settings.
|
||||
*/
|
||||
function Settings(hash, version, defCfg, callback, forceUpdate, reset) {
|
||||
this.hash = hash;
|
||||
this.version = version || this.version;
|
||||
this.defCfg = defCfg;
|
||||
if (reset) {
|
||||
this.reset(callback);
|
||||
} else {
|
||||
this.sync(function () {
|
||||
this.checkStructure(callback, forceUpdate);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Settings.prototype.hash = '';
|
||||
Settings.prototype.defCfg = {};
|
||||
Settings.prototype.cfg = {};
|
||||
Settings.prototype.version = '0.0.0';
|
||||
|
||||
/**
|
||||
Synchronizes the local object with the saved object (reverts changes).
|
||||
@param callback Gets called when done.
|
||||
*/
|
||||
Settings.prototype.sync = function (callback) {
|
||||
var _this = this;
|
||||
meta.settings.get(this.hash, function (err, settings) {
|
||||
try {
|
||||
if (settings._settings) {
|
||||
settings._settings = JSON.parse(settings._settings);
|
||||
}
|
||||
} catch (_error) {}
|
||||
_this.cfg = settings;
|
||||
if (typeof callback === 'function') {
|
||||
callback.apply(_this, err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Persists the local object.
|
||||
@param callback Gets called when done.
|
||||
*/
|
||||
Settings.prototype.persist = function (callback) {
|
||||
var conf = this.cfg._settings,
|
||||
_this = this;
|
||||
if (typeof conf === 'object') {
|
||||
conf = JSON.stringify(conf);
|
||||
}
|
||||
meta.settings.set(this.hash, {
|
||||
_settings: conf,
|
||||
version: this.cfg.version
|
||||
}, function () {
|
||||
if (typeof callback === 'function') {
|
||||
callback.apply(_this, arguments || []);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
Persists the settings if no settings are saved.
|
||||
@param callback Gets called when done.
|
||||
*/
|
||||
Settings.prototype.persistOnEmpty = function (callback) {
|
||||
var _this = this;
|
||||
meta.settings.get(this.hash, function (err, settings) {
|
||||
if (!settings._settings) {
|
||||
_this.persist(callback);
|
||||
} else if (typeof callback === 'function') {
|
||||
callback.call(_this);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the setting of given key or default value if not set.
|
||||
@param key The key of the setting to return.
|
||||
@param def The default value, if not set global default value gets used.
|
||||
@returns Object The setting to be used.
|
||||
*/
|
||||
Settings.prototype.get = function (key, def) {
|
||||
var obj = this.cfg._settings,
|
||||
parts = (key || '').split('.'),
|
||||
part;
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
part = parts[i];
|
||||
if (part && obj != null) {
|
||||
obj = obj[part];
|
||||
}
|
||||
}
|
||||
if (obj === void 0) {
|
||||
if (def === void 0) {
|
||||
def = this.defCfg;
|
||||
for (var j = 0; j < parts.length; j++) {
|
||||
part = parts[j];
|
||||
if (part && def != null) {
|
||||
def = def[part];
|
||||
}
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the settings-wrapper object.
|
||||
@returns Object The settings-wrapper.
|
||||
*/
|
||||
Settings.prototype.getWrapper = function () {
|
||||
return this.cfg;
|
||||
};
|
||||
|
||||
/**
|
||||
Creates a new wrapper for the given settings with the given version.
|
||||
@returns Object The new settings-wrapper.
|
||||
*/
|
||||
Settings.prototype.createWrapper = function (version, settings) {
|
||||
return {
|
||||
version: version,
|
||||
_settings: settings
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
Creates a new wrapper for the default settings.
|
||||
@returns Object The new settings-wrapper.
|
||||
*/
|
||||
Settings.prototype.createDefaultWrapper = function () {
|
||||
return this.createWrapper(this.version, this.defCfg);
|
||||
};
|
||||
|
||||
/**
|
||||
Sets the setting of given key to given value.
|
||||
@param key The key of the setting to set.
|
||||
@param val The value to set.
|
||||
*/
|
||||
Settings.prototype.set = function (key, val) {
|
||||
var part, obj, parts;
|
||||
this.cfg.version = this.version;
|
||||
if (val == null || !key) {
|
||||
this.cfg._settings = val || key;
|
||||
} else {
|
||||
obj = this.cfg._settings;
|
||||
parts = key.split('.');
|
||||
for (var i = 0, _len = parts.length - 1; i < _len; i++) {
|
||||
if (part = parts[i]) {
|
||||
if (!obj.hasOwnProperty(part)) {
|
||||
obj[part] = {};
|
||||
}
|
||||
obj = obj[part];
|
||||
}
|
||||
}
|
||||
obj[parts[parts.length - 1]] = val;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
Resets the saved settings to default settings.
|
||||
@param callback Gets called when done.
|
||||
*/
|
||||
Settings.prototype.reset = function (callback) {
|
||||
this.set(this.defCfg).persist(callback);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
If the version differs the settings get updated and persisted.
|
||||
@param callback Gets called when done.
|
||||
@param force Whether to update and persist the settings even if the versions ara equal.
|
||||
*/
|
||||
Settings.prototype.checkStructure = function (callback, force) {
|
||||
if (!force && this.cfg.version === this.version) {
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
mergeSettings(this.cfg, this.defCfg);
|
||||
this.cfg.version = this.version;
|
||||
this.persist(callback);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = Settings;
|
Loading…
Reference in New Issue