f1d4a2c9 by Michael Richards

Implement wildcard attribute bindings so that it's possible to bind to any arbitrary attribute.

1 parent d1af20dd
...@@ -24,7 +24,7 @@ No contrived example here yet, but the `rivets` module is simple. It exposes a s ...@@ -24,7 +24,7 @@ No contrived example here yet, but the `rivets` module is simple. It exposes a s
24 - **data-unchecked**: two-way inverse binding that sets the node's checked state. 24 - **data-unchecked**: two-way inverse binding that sets the node's checked state.
25 - **data-selected**: two-way binding that sets the node's selected state. 25 - **data-selected**: two-way binding that sets the node's selected state.
26 - **data-unselected**: two-way inverse binding that sets the node's checked state. 26 - **data-unselected**: two-way inverse binding that sets the node's checked state.
27 - **data-[attribute]**: one-way binding that sets the node's attribute value (currently only for a few select attributes). 27 - **data-[attribute]**: one-way binding that sets the node's attribute value.
28 28
29 ## Adapters 29 ## Adapters
30 30
......
...@@ -3,11 +3,13 @@ ...@@ -3,11 +3,13 @@
3 var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 3 var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
4 4
5 window.rivets = (function() { 5 window.rivets = (function() {
6 var attr, bidirectionalBindings, bindableAttributes, bindings, getInputValue, registerBinding, setAttribute, _fn, _i, _len; 6 var attributeBinding, bidirectionalBindings, bindings, getInputValue, registerBinding, setAttribute;
7 registerBinding = function(el, adapter, type, context, keypath) { 7 registerBinding = function(el, adapter, type, context, keypath) {
8 bindings[type](el, adapter.read(context, keypath)); 8 var bind;
9 bind = bindings[type] || attributeBinding(type);
10 bind(el, adapter.read(context, keypath));
9 adapter.subscribe(context, keypath, function(value) { 11 adapter.subscribe(context, keypath, function(value) {
10 return bindings[type](el, value); 12 return bind(el, value);
11 }); 13 });
12 if (__indexOf.call(bidirectionalBindings, type) >= 0) { 14 if (__indexOf.call(bidirectionalBindings, type) >= 0) {
13 return $(el).bind('change', function() { 15 return $(el).bind('change', function() {
...@@ -76,42 +78,35 @@ ...@@ -76,42 +78,35 @@
76 return $(el).val(value); 78 return $(el).val(value);
77 } 79 }
78 }; 80 };
79 bidirectionalBindings = ['value', 'checked', 'unchecked', 'selected', 'unselected']; 81 attributeBinding = function(attr) {
80 bindableAttributes = ['id', 'class', 'name', 'src', 'href', 'alt', 'title', 'placeholder']; 82 return function(el, value) {
81 _fn = function(attr) {
82 return bindings[attr] = function(el, value) {
83 return setAttribute(el, attr, value); 83 return setAttribute(el, attr, value);
84 }; 84 };
85 }; 85 };
86 for (_i = 0, _len = bindableAttributes.length; _i < _len; _i++) { 86 bidirectionalBindings = ['value', 'checked', 'unchecked', 'selected', 'unselected'];
87 attr = bindableAttributes[_i];
88 _fn(attr);
89 }
90 return { 87 return {
91 bind: function(el, adapter, contexts) { 88 bind: function(el, adapter, contexts) {
92 if (contexts == null) { 89 if (contexts == null) {
93 contexts = {}; 90 contexts = {};
94 } 91 }
95 return $(el).add($('*', el)).each(function() { 92 return $(el).add($('*', el)).each(function() {
96 var nodeMap, target, _j, _ref, _results; 93 var nodeMap, target, _i, _ref, _results;
97 target = this; 94 target = this;
98 nodeMap = target.attributes; 95 nodeMap = target.attributes;
99 if (nodeMap.length > 0) { 96 if (nodeMap.length > 0) {
100 return (function() { 97 return (function() {
101 _results = []; 98 _results = [];
102 for (var _j = 0, _ref = nodeMap.length - 1; 0 <= _ref ? _j <= _ref : _j >= _ref; 0 <= _ref ? _j++ : _j--){ _results.push(_j); } 99 for (var _i = 0, _ref = nodeMap.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }
103 return _results; 100 return _results;
104 }).apply(this).forEach(function(n) { 101 }).apply(this).forEach(function(n) {
105 var context, keypath, node, path, type; 102 var context, keypath, node, path, type;
106 node = nodeMap[n]; 103 node = nodeMap[n];
107 if (/^data-/.test(node.name)) { 104 if (/^data-/.test(node.name)) {
108 type = node.name.replace('data-', ''); 105 type = node.name.replace('data-', '');
109 if (type in bindings) { 106 path = node.value.split('.');
110 path = node.value.split('.'); 107 context = path.shift();
111 context = path.shift(); 108 keypath = path.join('.');
112 keypath = path.join('.'); 109 return registerBinding($(target), adapter, type, contexts[context], keypath);
113 return registerBinding($(target), adapter, type, contexts[context], keypath);
114 }
115 } 110 }
116 }); 111 });
117 } 112 }
......
...@@ -5,14 +5,15 @@ ...@@ -5,14 +5,15 @@
5 5
6 window.rivets = do -> 6 window.rivets = do ->
7 registerBinding = (el, adapter, type, context, keypath) -> 7 registerBinding = (el, adapter, type, context, keypath) ->
8 bindings[type] el, adapter.read(context, keypath) 8 bind = bindings[type] || attributeBinding type
9 bind el, adapter.read context, keypath
9 10
10 adapter.subscribe context, keypath, (value) -> 11 adapter.subscribe context, keypath, (value) ->
11 bindings[type] el, value 12 bind el, value
12 13
13 if type in bidirectionalBindings 14 if type in bidirectionalBindings
14 $(el).bind 'change', -> 15 $(el).bind 'change', ->
15 adapter.publish context, keypath, getInputValue(this) 16 adapter.publish context, keypath, getInputValue this
16 17
17 setAttribute = (el, attr, value, mirrored=false) -> 18 setAttribute = (el, attr, value, mirrored=false) ->
18 if value 19 if value
...@@ -47,13 +48,11 @@ window.rivets = do -> ...@@ -47,13 +48,11 @@ window.rivets = do ->
47 value: (el, value) -> 48 value: (el, value) ->
48 $(el).val value 49 $(el).val value
49 50
50 bidirectionalBindings = ['value', 'checked', 'unchecked', 'selected', 'unselected'] 51 attributeBinding = (attr) ->
51 bindableAttributes = ['id', 'class', 'name', 'src', 'href', 'alt', 'title', 'placeholder'] 52 (el, value) ->
53 setAttribute el, attr, value
52 54
53 for attr in bindableAttributes 55 bidirectionalBindings = ['value', 'checked', 'unchecked', 'selected', 'unselected']
54 do (attr) ->
55 bindings[attr] = (el, value) ->
56 setAttribute el, attr, value
57 56
58 bind: (el, adapter, contexts={}) -> 57 bind: (el, adapter, contexts={}) ->
59 $(el).add($('*', el)).each -> 58 $(el).add($('*', el)).each ->
...@@ -66,9 +65,7 @@ window.rivets = do -> ...@@ -66,9 +65,7 @@ window.rivets = do ->
66 65
67 if /^data-/.test node.name 66 if /^data-/.test node.name
68 type = node.name.replace 'data-', '' 67 type = node.name.replace 'data-', ''
69 68 path = node.value.split '.'
70 if type of bindings 69 context = path.shift()
71 path = node.value.split '.' 70 keypath = path.join '.'
72 context = path.shift() 71 registerBinding $(target), adapter, type, contexts[context], keypath
73 keypath = path.join '.'
74 registerBinding $(target), adapter, type, contexts[context], keypath
......