Skip to content
Browse files

Add a proper data-bind-style binding.

Supports both CSS string bindings and Batman.Hashes. Note that
Batman.Objects are not supported since they don't have item
added/removed events.

Fixes #176.
  • Loading branch information...
1 parent c9b2602 commit ca641670b2d663a211de9f7a741a2daafd6cbc48 Kamil Tusznio committed
Showing with 106 additions and 5 deletions.
  1. +37 −3 lib/batman.js
  2. +33 −2 src/batman.coffee
  3. +36 −0 tests/batman/view/simple_rendering_test.coffee
View
40 lib/batman.js
@@ -613,6 +613,7 @@
};
Property.prototype.setValue = function(val) {
var result, _ref;
+ this.cached = false;
result = (_ref = this.accessor().set) != null ? _ref.call(this.base, this.key, val) : void 0;
this.refresh();
return result;
@@ -1222,8 +1223,7 @@
Hash.accessor({
get: Batman.SimpleHash.prototype.get,
set: Hash.mutation(function(key, value) {
- var old, result;
- old = this.get(key);
+ var result;
result = Batman.SimpleHash.prototype.set.call(this, key, value);
this.fire('itemsWereAdded', key);
return result;
@@ -4204,7 +4204,6 @@
});
break;
case 'value':
- case 'style':
case 'href':
case 'src':
case 'size':
@@ -4223,6 +4222,8 @@
return subContext.set(key, node.className);
};
break;
+ case 'style':
+ return Batman.DOM.binders.style(node, attr, key, context, renderer, only);
default:
dataChange = function(value) {
return node.setAttribute(attr, value);
@@ -4377,6 +4378,39 @@
});
return true;
},
+ style: function(node, attr, key, context, renderer, only) {
+ var dataChange, nodeChange;
+ dataChange = function(value) {
+ var oldHash, onItemsAdded, onItemsRemoved;
+ if (!value) {
+ return node.setAttribute('style', '');
+ }
+ if (typeof value === 'string') {
+ return node.setAttribute('style', value);
+ }
+ if (value instanceof Batman.Hash) {
+ onItemsAdded = function(newKey) {
+ return node.style[newKey] = value.get(newKey);
+ };
+ onItemsRemoved = function(oldKey) {
+ return node.style[oldKey] = '';
+ };
+ if (oldHash) {
+ oldHash.forget('itemsWereAdded', onItemsAdded);
+ oldHash.forget('itemsWereRemoved', onItemsRemoved);
+ }
+ oldHash = value;
+ value.on('itemsWereAdded', onItemsAdded);
+ value.on('itemsWereRemoved', onItemsRemoved);
+ return value.keys().forEach(onItemsAdded);
+ }
+ };
+ nodeChange = function(node, subContext) {
+ return subContext.set(key, node.style.cssText);
+ };
+ context.bind(node, key, dataChange, nodeChange, only);
+ return true;
+ },
radio: function(node, key, context, renderer, only) {
var dataChange, nodeChange;
dataChange = function(value) {
View
35 src/batman.coffee
@@ -434,6 +434,7 @@ class Batman.Property
valueFromAccessor: -> @accessor().get?.call(@base, @key)
setValue: (val) ->
+ @cached = no
result = @accessor().set?.call(@base, @key, val)
@refresh()
result
@@ -867,7 +868,6 @@ class Batman.Hash extends Batman.Object
@accessor
get: Batman.SimpleHash::get
set: @mutation (key, value) ->
- old = @get(key)
result = Batman.SimpleHash::set.call(@, key, value)
@fire 'itemsWereAdded', key
result
@@ -3023,12 +3023,14 @@ Batman.DOM = {
context: context
key: key
- when 'value', 'style', 'href', 'src', 'size'
+ when 'value', 'href', 'src', 'size'
dataChange = (value) -> node[attr] = value
nodeChange = (node, subContext) -> subContext.set(key, Batman.DOM.attrReaders._parseAttribute(node[attr]))
when 'class'
dataChange = (value) -> node.className = value
nodeChange = (node, subContext) -> subContext.set key, node.className
+ when 'style'
+ return Batman.DOM.binders.style node, attr, key, context, renderer, only
else
dataChange = (value) -> node.setAttribute(attr, value)
nodeChange = (node, subContext) -> subContext.set(key, Batman.DOM.attrReaders._parseAttribute(node.getAttribute(attr)))
@@ -3146,6 +3148,35 @@ Batman.DOM = {
context.bind node, key, dataChange, nodeChange, only
true
+ style: (node, attr, key, context, renderer, only) ->
+ dataChange = (value) ->
+ return node.setAttribute('style', '') unless value
+ return node.setAttribute('style', value) if typeof value is 'string'
+
+ if value instanceof Batman.Hash
+ onItemsAdded = (newKey) ->
+ node.style[newKey] = value.get(newKey)
+ onItemsRemoved = (oldKey) ->
+ node.style[oldKey] = ''
+
+ # remove listeners from a previously bound hash
+ if oldHash
+ oldHash.forget 'itemsWereAdded', onItemsAdded
+ oldHash.forget 'itemsWereRemoved', onItemsRemoved
+ oldHash = value
+
+ # attach listeners
+ value.on 'itemsWereAdded', onItemsAdded
+ value.on 'itemsWereRemoved', onItemsRemoved
+
+ # initialize styles
+ value.keys().forEach onItemsAdded
+
+ nodeChange = (node, subContext) -> subContext.set(key, node.style.cssText)
+
+ context.bind(node, key, dataChange, nodeChange, only)
+ true
+
radio: (node, key, context, renderer, only) ->
dataChange = (value) ->
# don't overwrite `checked` attributes in the HTML unless a bound
View
36 tests/batman/view/simple_rendering_test.coffee
@@ -486,6 +486,42 @@ asyncTest 'should bind to the value of radio buttons', ->
delay =>
equal context.get('ad.sale_type'), 'fixed'
+asyncTest 'data-bind-style should bind to a string', 4, ->
+ source = '<div data-bind-style="string"></div>'
+ context = Batman
+ string: 'background-color:blue; color:green;'
+
+ helpers.render source, context, (node) ->
+ equal node[0].style['background-color'], 'blue'
+ equal node[0].style['color'], 'green'
+ context.set 'string', 'background-color:green'
+ delay =>
+ equal node[0].style['background-color'], 'green'
+ equal node[0].style['color'], ''
+
+asyncTest 'data-bind-style should bind to a Batman object', 8, ->
+ source = '<div data-bind-style="object"></div>'
+ context = Batman
+ object: new Batman.Hash
+ 'background-color': 'blue'
+ color: 'green'
+
+ helpers.render source, context, (node) ->
+ equal node[0].style['background-color'], 'blue'
+ equal node[0].style['color'], 'green'
+ context.set 'object.color', 'blue'
+ delay =>
+ equal node[0].style['color'], 'blue'
+ equal node[0].style['background-color'], 'blue'
+ context.unset 'object.color'
+ delay =>
+ equal node[0].style['color'], ''
+ equal node[0].style['background-color'], 'blue'
+ context.set 'object', new Batman.Hash color: 'yellow'
+ delay =>
+ equal node[0].style['color'], 'yellow'
+ equal node[0].style['background-color'], 'blue'
+
QUnit.module "Memory safety"
test "addEventListener and removeEventListener store and remove callbacks using Batman.data", ->

0 comments on commit ca64167

Please sign in to comment.
Something went wrong with that request. Please try again.