solidstate
Version:
An observable REST client for Javascript with a dramatically simple & fluent API.
79 lines (64 loc) • 2.55 kB
JavaScript
if (typeof define !== 'function') { var define = require('amdefine')(module); }
define([
'knockout',
'underscore',
'URIjs',
'when',
'zoetropic'
], function(ko, _, URI, when, z) {
'use strict';
/** @class Attributes
@classdesc An observable dictionary with the property that writing the whole dictionary
actually writes individually to each attribute.
*/
var o = ko.observable,
u = ko.utils.unwrapObservable,
c = ko.computed,
w = function(v) { return ko.isObservable(v) ? v : o(v); };
/** @callback Attributes~makeAttribute
@param {String} key
@param value
@returns {Observable}
@desc
When a new attribute is added to the dictionary, this callback constructs the observable
from the key and the value. By default, it uses ko.observable(value).
*/
/**
Foo bar baz
@param {{attributes: Object, ?makeAttribute: Attributes~makeAttribute}} args Named arguments to the constructor.
*/
var Attributes = function(args) {
args = args || {};
var makeAttribute = args.makeAttribute || function(key, value) { return ko.observable(value); };
var actualAttributes = o({});
var wrappedAttributes = c({
read: function() {
return actualAttributes();
},
write: function(_newAttributes) {
var keysChanged = false;
var nextAttributes = _(actualAttributes.peek()).clone();
var newAttributes = _newAttributes.peek ? _newAttributes.peek() : _newAttributes;
_(newAttributes).each(function(value, key) {
value = (value && value.peek)
? value.peek()
: value;
if (_(nextAttributes).has(key)) {
nextAttributes[key](value);
} else {
nextAttributes[key] = makeAttribute(key, value);
keysChanged = true;
}
});
// Note that there is currently no way to remove an attribute (because that is a weird thing to do and the semantics aren't clean)
if (keysChanged)
actualAttributes(nextAttributes);
}
});
if ( args.attributes ) {
wrappedAttributes( args.attributes );
}
return wrappedAttributes;
};
return Attributes;
});