ami/src/ami.js/settings.js

232 lines
7.2 KiB
JavaScript

#include cookies.js
#include utility.js
#include watcher.js
// really need to replace null with undefined where possible, in mami too
// wondering if there's room for the different backends here
var AmiSettings = function() {
var pub = {};
var prefix = 'ami_',
types = ['boolean', 'number', 'string'];
var settings = new Map,
locked = [];
var createSetting = function(name, type, defaultValue, mutable, virtual) {
var pub = {},
cookieName = prefix + name,
watchers = new AmiWatcher;
var virtualValue = undefined;
var getValue = function() {
if(!mutable)
return defaultValue;
var value = virtual ? virtualValue : AmiCookies.getCookie(cookieName);
if(value === undefined)
return defaultValue;
value = JSON.parse(value);
if(value === null)
return defaultValue;
return value;
};
var callWatchers = function() {
watchers.call(pub, getValue(), name);
};
var removeValue = function() {
if(locked.indexOf(name) >= 0)
return;
locked.push(name);
if(virtual) virtualValue = undefined;
else AmiCookies.removeCookie(cookieName);
callWatchers();
$ari(locked, name);
};
var setValue = function(value) {
if(value === undefined || value === null || value === defaultValue) {
removeValue();
return;
}
if(typeof value !== type)
throw 'value is not correct type';
if(locked.indexOf(name) >= 0)
return;
locked.push(name);
value = JSON.stringify(value);
if(virtual) virtualValue = value;
else AmiCookies.setCookie(cookieName, value);
callWatchers();
$ari(locked, name);
};
pub.getName = function() { return name; };
pub.getType = function() { return type; };
pub.getDefault = function() { return defaultValue; };
pub.isMutable = function() { return mutable; };
pub.isVirtual = function() { return virtual; };
pub.getValue = getValue;
pub.setValue = setValue;
pub.removeValue = removeValue;
pub.touch = callWatchers;
pub.hasValue = function() {
if(!mutable) return false;
var value = virtual ? virtualValue : AmiCookies.getCookie(cookieName);
if(value === undefined) return false;
value = JSON.parse(value);
if(value === null || value === defaultValue) return false;
return true;
};
pub.toggleValue = function() {
if(type !== 'boolean')
throw 'cannot toggle non-boolean setting';
if(locked.indexOf(name) >= 0)
return;
locked.push(name);
var value = virtual ? virtualValue : AmiCookies.getCookie(cookieName);
if(value === undefined)
value = defaultValue;
else
value = JSON.parse(virtual ? virtualValue : AmiCookies.getCookie(cookieName));
value = JSON.stringify(!value);
if(virtual) virtualValue = value;
else AmiCookies.setCookie(cookieName, value);
callWatchers();
$ari(locked, name);
};
pub.watch = function(watcher) {
if(typeof watcher !== 'function')
throw 'watcher must be a function';
watchers.watch(watcher, pub, getValue(), name);
};
pub.unwatch = function(watcher) {
watchers.unwatch(watcher);
};
pub.virtualise = function() {
if(!mutable || virtual)
return;
virtual = true;
virtualValue = AmiCookies.getCookie(cookieName);
};
return pub;
};
return {
has: function(name) {
var setting = settings.get(name);
if(setting === undefined) return false;
return setting.hasValue();
},
get: function(name) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to get value of undefined setting';
return setting.getValue();
},
getSetting: function() {
return settings.get(name);
},
set: function(name, value) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to set value of undefined setting';
setting.setValue(value);
},
remove: function(name) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to remove value of undefined setting';
setting.removeValue();
},
toggle: function(name) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to toggle undefined setting';
setting.toggleValue();
},
touch: function(name) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to touch undefined setting';
setting.touch();
},
watch: function(name, watcher) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to watch undefined setting';
setting.watch(watcher);
},
unwatch: function(name, watcher) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to unwatch undefined setting';
setting.unwatch(watcher);
},
virtualise: function(name) {
var setting = settings.get(name);
if(setting === undefined)
throw 'attempting to virtualise undefined setting';
setting.virtualise();
},
define: function(name, type, defaultValue, mutable, virtual) {
if(typeof name !== 'string')
throw 'name must be string';
name = name.trim();
if(types.indexOf(type) < 0)
throw 'invalid type specified';
if(mutable === undefined) mutable = true;
else mutable = !!mutable;
virtual = !!virtual;
if(defaultValue !== null) {
if(defaultValue === undefined)
defaultValue = null;
else if(type !== typeof defaultValue)
throw 'defaultValue type must match setting type or be null';
}
var setting = createSetting(name, type, defaultValue, mutable, virtual);
settings.set(name, setting);
return setting;
},
undefine: function(name) {
var setting = settings.get(name);
if(setting === undefined)
return;
settings.delete(name);
setting.removeValue();
},
forEach: function(body) {
settings.forEach(body);
},
};
};