#include cookies.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(); $arrayRemoveValue(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(); $arrayRemoveValue(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(); $arrayRemoveValue(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); }, }; };