Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Switch direction of bindings

  • Loading branch information...
commit bb71b0cec39f11fea16833315ae97ddfca2d4c5c 1 parent aa68deb
@kriszyp authored
Showing with 118 additions and 79 deletions.
  1. +104 −64 bind.js
  2. +14 −15 tests/testForm.js
View
168 bind.js
@@ -7,25 +7,68 @@ define([], function(){
}
}
Binding.prototype = {
- then: function(callback){
+ to: function(callback){
// get the value of this binding, notifying the callback of changes
- var callbacks= this.callbacks;
- (callbacks || (this.callbacks = [])).push(callback);
- if(callbacks){
- if("value" in this){
- callback(this.value);
+ if(typeof callback == "function"){
+ var toBindings= this.toBindings;
+ var resultBinding = new Binding();
+ resultBinding.func = callback;
+ (toBindings || (this.toBindings = [])).push(resultBinding);
+ if(toBindings){
+ if("value" in this){
+ resultBinding.is(this.value);
+ callback(this.value);
+ }
+ }else{
+ var self = this;
+ toBindings = this.toBindings;
+ this.getValue(function(value){
+ self.value = value;
+ for(var i = 0; i < toBindings.length; i++){
+ toBindings[i].is(toBindings[i].func(value));
+ }
+ });
}
+ return resultBinding;
+ // TODO: return a new binding
}else{
- var self = this;
- callbacks = this.callbacks;
- this.getValue(function(value){
- self.value = value;
- for(var i = 0; i < callbacks.length; i++){
- callbacks[i](value);
- }
- });
+ return callback && callback.from ? callback.from(this) : bind(callback).from(this);
}
},
+ toArgs: function(callback){
+ return this.to(function(array){
+ var length = array.length;
+ var fulfilled = [], currentValues = [], updates = 0;
+ var outerCallback, functionResult;
+ // watch each of the items in the array
+ for(var i = 0; i < length; i++){
+ fulfilled[i] = false;
+ (function(i, source){
+ source.to(function(value){
+ currentValues[i] = value;
+ if(!fulfilled[i]){
+ fulfilled[i] = true;
+ updates++;
+ }
+ if(updates >= length){
+ functionResult = callback.apply(this, currentValues);
+ if(outerCallback){
+ outerCallback(functionResult);
+ }
+ }
+ });
+ })(i, array[i]);
+ }
+ return {
+ to: function(callback){
+ if(functionResult){
+ callback(functionResult);
+ }
+ outerCallback = callback;
+ }
+ }
+ });
+ },
getValue: function(callback){
if(this.hasOwnProperty("value")){
callback(this.value);
@@ -38,7 +81,7 @@ define([], function(){
(value = this.value[key]) && typeof value != "object" ? new PropertyBinding(this.value, key) :
convertToBindable(value) : new Binding());
if(callback){
- return child.then(callback);
+ return child.to(callback);
}
return child;
},
@@ -48,19 +91,31 @@ define([], function(){
}
this.is(value);
},
+ set: function(key, value){
+ return this.get(key).put(value);
+ },
is: function(value){
if(value !== this.value){
this.value = value;
- if(typeof this.value == "object"){
- for(var i in value){
- if(i.charAt(0) != '_'){
- this.get(i).is(value[i]);
+ if(typeof value == "object"){
+ if(value.to){
+ var self = this;
+ value.to(function(value){
+ self.is(value)
+ });
+ return;
+ }else{
+ for(var i in value){
+ if(i.charAt(0) != '_'){
+ this.get(i).is(value[i]);
+ }
}
}
}
- if(this.callbacks){
- for(var i = 0; i < this.callbacks.length; i++){
- this.callbacks[i](value);
+ var toBindings = this.toBindings;
+ if(toBindings){
+ for(var i = 0; i < toBindings.length; i++){
+ toBindings[i].is(toBindings[i].func(value));
}
}
}
@@ -74,14 +129,14 @@ define([], function(){
callback(i, this.get(i));
}
}
- },
+ },
from: function(source, property){
source = convertToBindable(source);
if(property){
source = source.get(property);
}
var self = this;
- this.source = source;
+ this.source = source;
source.to(function(value){
self.is(value);
});
@@ -90,7 +145,7 @@ define([], function(){
i = i.slice(1);
var child = self.get(i);
var sourceChild = source.get(i);
- if(child != sourceChild){
+ if(child != sourceChild){
child.from(sourceChild);
}
}
@@ -98,7 +153,7 @@ define([], function(){
source.keys(function(i, sourceChild){
if(!(('_' + i) in self)){
var child = self.get(i);
- if(child != sourceChild){
+ if(child != sourceChild){
child.from(sourceChild);
}
}
@@ -111,11 +166,11 @@ define([], function(){
this.stateful = stateful;
stateful._binding = this;
}
- StatefulBinding.prototype = new Binding({});
- StatefulBinding.prototype.to = function(source){
+ StatefulBinding.prototype = new Binding({});
+ StatefulBinding.prototype.from = function(source){
Binding.prototype.from.apply(this, arguments);
source = this.source;
- var stateful = this.stateful;
+ var stateful = this.stateful;
source.from(function(value){
stateful.set('value', value);
});
@@ -187,7 +242,19 @@ define([], function(){
element.checked = value;
}else{
element.value = value || "";
- }
+ }
+ }else if(value && value.sort){
+ var each = this.each;
+ var renderItem = each ||
+ function(item){
+ var li = element.appendChild(document.createElement('li'));
+ li.appendChild(document.createTextNode(item));
+ };
+ // TODO: handle old IE?
+ value.forEach(renderItem);
+ value.observe && value.observe(function(object, from, to){
+ // TODO: handle changes
+ });
}else{
element.innerText = value || "";
}
@@ -197,8 +264,8 @@ define([], function(){
"INPUT":1,
"SELECT":1,
"TEXTAREA":1
- };
- ElementBinding.prototype.to = function(source){
+ };
+ ElementBinding.prototype.from = function(source){
Binding.prototype.from.apply(this, arguments);
source = this.source;
var element = this.element;
@@ -234,7 +301,7 @@ define([], function(){
}
}
return this;
- }
+ }
ElementBinding.prototype.toOnce = function(callback){
var element = this.element;
if(this.container){
@@ -281,33 +348,6 @@ define([], function(){
PropertyBinding.prototype.put = function(value){
this.object[this.name] = value;
this.is(value);
- }
- function FunctionBinding(func, reverseFunc){
- this.func = func;
- this.reverseFunc = reverseFunc;
- }
- FunctionBinding.prototype = {
- then: function(callback){
- if(callback){
- var func = this.func;
- return this.source.then(function(value){
- callback(value.slice ? func.apply(this, value) : func(value));
- });
- }
- },
- get: function(key){
- return this[key] || (this[key] = new Binding('None'));
- },
- put: function(value){
- this.source.put(this.reverseFunc(value));
- },
- is: function(){},
- to: function(source){
- source = bind.apply(this, arguments);
- this.source = source;
- return this;
- },
- keys: function(){}
}
function convertToBindable(object){
return object ?
@@ -319,8 +359,8 @@ define([], function(){
object.nodeType ?
new ElementBinding(object) :
typeof object == "function" ?
- new FunctionBinding(object) :
- object instanceof Array ?
+ new FunctionBinding(object) :
+// object instanceof Array ?
// new ArrayBinding(object) :
new Binding(object))
: new Binding(object);
@@ -375,8 +415,8 @@ define([], function(){
bind.Binding = Binding;
- function when(value, callback){
- if(value && value.then){
+ function when(value, callback){
+ if(value && value.to){
return value.to(callback);
}
return callback(value);
View
29 tests/testForm.js
@@ -3,9 +3,8 @@ define(['dbind/bind', 'dbind/Validator', 'put-selector/put'], function(bind, Val
myObject = {quantity: 3, price: 5, discounted: true, color: "red", pattern: "striped"};
return function(form){
// TODO: put this in a model module
- var quantity = bind(
- new Validator({type:"number", maximum: 20, minimum: 10})).to
- (get(myObject, 'quantity'));
+ var quantity = get(myObject, 'quantity').to(
+ new Validator({type:"number", maximum: 20, minimum: 10}));
quantity.get("title").is("Quantity");
@@ -14,36 +13,36 @@ define(['dbind/bind', 'dbind/Validator', 'put-selector/put'], function(bind, Val
var mainElement = put('div');
var binding = new bind.Container(mainElement);
// the label
- bind(put(mainElement, 'label')).to(binding.get('title'));
+ binding.get('title').to(bind(put(mainElement, 'label')));
// the main value is bound to the input
- bind(put(mainElement, 'input[type=text]')).to(binding);
+ binding.to(put(mainElement, 'input[type=text]'));
// any errors go after it
- bind(put(mainElement, 'span.error-message')).to(binding, 'error');
+ binding.get('error').to(put(mainElement, 'span.error-message'));
return mainElement;
}
// create the form elements
var quantityRow = put(form, 'div');
var quantityTextBox = ValidationTextBox();
put(quantityRow, quantityTextBox);
- bind(quantityTextBox).to(quantity);
+ quantity.to(quantityTextBox);
- bind(put(form, "div", "Price", "input[type=text]")).to(myObject, "price");
+ bind(myObject, "price").to(put(form, "div", "Price", "input[type=text]"));
- bind(put(form, "div", "Discounted", "input[type=checkbox]")).to(myObject, "discounted");
+ bind(myObject, "discounted").to(put(form, "div", "Discounted", "input[type=checkbox]"));
var patternSelect = put(form, "div", "Pattern", "select");
put(patternSelect, "option[value=striped]", "Striped");
put(patternSelect, "option[value=solid]", "Solid");
- bind(patternSelect).to(myObject, "pattern");
+ bind(myObject, "pattern").to(patternSelect);
var colorDiv = put(form, "div", "Color");
var colorProperty = bind(myObject, "color");
- bind(put(colorDiv, "div", "Red", "input[type=radio][value=red]")).to(colorProperty);
- bind(put(colorDiv, "div", "Green", "input[type=radio][value=green]")).to(colorProperty);
- bind(put(colorDiv, "div", "Blue", "input[type=radio][value=blue]")).to(colorProperty);
+ colorProperty.to(put(colorDiv, "div", "Red", "input[type=radio][value=red]"));
+ colorProperty.to(put(colorDiv, "div", "Green", "input[type=radio][value=green]"));
+ colorProperty.to(put(colorDiv, "div", "Blue", "input[type=radio][value=blue]"));
- bind(put(form, 'div label', 'Total Price: ', '< span'), bind(function(quantity, price, discounted){
+ bind([quantity, bind(myObject, "price"), bind(myObject, "discounted")]).toArgs(function(quantity, price, discounted){
return "$" + quantity * price * (discounted ? 0.9 : 1);
- }).to([quantity, bind(myObject, "price"), bind(myObject, "discounted")]));
+ }).to(put(form, 'div label', 'Total Price: ', '< span'));
}
});
Please sign in to comment.
Something went wrong with that request. Please try again.