var _ = require('lodash') module.exports = function SettingsServiceFactory( $rootScope , UserService , socket ) { var SettingsService = {} var settings = UserService.currentUser.settings || {} , syncListeners = [] function createListener(object, options, monitor) { var source = options.source || options.target return function() { var value = object[options.target] = (source in settings) ? settings[source] : options.defaultValue if (monitor) { monitor(value) } } } function applyDelta(delta) { // TODO: This causes chaos $rootScope.safeApply(function() { _.merge(settings, delta, function(a, b) { // New Arrays overwrite old Arrays return _.isArray(b) ? b : undefined }) for (var i = 0, l = syncListeners.length; i < l; ++i) { syncListeners[i]() } }) } SettingsService.update = function(delta) { socket.emit('user.settings.update', delta) applyDelta(delta) } SettingsService.get = function (key) { return settings[key] } SettingsService.set = function(key, value) { var delta = Object.create(null) delta[key] = value SettingsService.update(delta) } SettingsService.reset = function() { socket.emit('user.settings.reset') settings = {} applyDelta(null) } SettingsService.bind = function(scope, options) { function value(possibleValue, defaultValue) { return (possibleValue !== void 0) ? possibleValue : defaultValue } var source = options.source || options.target , defaultValue = value(options.defaultValue, scope[options.target]) scope.$watch( options.target , function(newValue, oldValue) { // Skip initial value. if (newValue !== oldValue) { var delta = Object.create(null) delta[source] = angular.copy(newValue) SettingsService.update(delta) } } , true ) scope.$watch( function() { return settings[source] } , function(newValue, oldValue) { // Skip initial value. The new value might not be different if // settings were reset, for example. In that case we fall back // to the default value. if (newValue !== oldValue) { scope[options.target] = value(newValue, defaultValue) } } , true ) scope[options.target] = value(settings[source], defaultValue) } SettingsService.sync = function(object, options, monitor) { var listener = createListener(object, options, monitor) listener() // Initialize return syncListeners.push(listener) - 1 } SettingsService.unsync = function(id) { syncListeners.splice(id, 1) } socket.on('user.settings.update', applyDelta) return SettingsService }