Namespace everything under Rivets and rewrite the registerBinding function as a new class.
Showing
2 changed files
with
105 additions
and
61 deletions
1 | // Generated by CoffeeScript 1.3.1 | 1 | // Generated by CoffeeScript 1.3.1 |
2 | (function() { | 2 | (function() { |
3 | var attributeBinding, bidirectionals, bindings, getInputValue, registerBinding, rivets, stateBinding, | 3 | var Rivets, |
4 | __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ||
4 | __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; }; | 5 | __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; }; |
5 | 6 | ||
6 | registerBinding = function(el, adapter, type, context, keypath) { | 7 | Rivets = { |
7 | var bind; | 8 | Helpers: {} |
8 | bind = bindings[type] || attributeBinding(type); | ||
9 | bind(el, adapter.read(context, keypath)); | ||
10 | adapter.subscribe(context, keypath, function(value) { | ||
11 | return bind(el, value); | ||
12 | }); | ||
13 | if (__indexOf.call(bidirectionals, type) >= 0) { | ||
14 | return el.addEventListener('change', function() { | ||
15 | return adapter.publish(context, keypath, getInputValue(this)); | ||
16 | }); | ||
17 | } | ||
18 | }; | 9 | }; |
19 | 10 | ||
20 | getInputValue = function(el) { | 11 | Rivets.Binding = (function() { |
12 | |||
13 | Binding.name = 'Binding'; | ||
14 | |||
15 | function Binding(el, adapter, type, context, keypath) { | ||
16 | this.el = el; | ||
17 | this.adapter = adapter; | ||
18 | this.type = type; | ||
19 | this.context = context; | ||
20 | this.keypath = keypath; | ||
21 | this.bind = __bind(this.bind, this); | ||
22 | |||
23 | this.set = __bind(this.set, this); | ||
24 | |||
25 | this.routine = Rivets.bindings[this.type] || Rivets.Helpers.attributeBinding(this.type); | ||
26 | } | ||
27 | |||
28 | Binding.prototype.set = function(value) { | ||
29 | if (value == null) { | ||
30 | value = null; | ||
31 | } | ||
32 | return this.routine(this.el, value || this.adapter.read(this.context, this.keypath)); | ||
33 | }; | ||
34 | |||
35 | Binding.prototype.bind = function() { | ||
36 | var _ref, | ||
37 | _this = this; | ||
38 | this.adapter.subscribe(this.context, this.keypath, function(value) { | ||
39 | return _this.set(value); | ||
40 | }); | ||
41 | if (_ref = this.type, __indexOf.call(Rivets.bidirectionals, _ref) >= 0) { | ||
42 | return this.el.addEventListener('change', function(el) { | ||
43 | return _this.adapter.publish(_this.context, _this.keypath, Rivets.Helpers.getInputValue(el)); | ||
44 | }); | ||
45 | } | ||
46 | }; | ||
47 | |||
48 | return Binding; | ||
49 | |||
50 | })(); | ||
51 | |||
52 | Rivets.Helpers.getInputValue = function(el) { | ||
21 | switch (el.type) { | 53 | switch (el.type) { |
22 | case 'text': | 54 | case 'text': |
23 | case 'textarea': | 55 | case 'textarea': |
... | @@ -30,7 +62,7 @@ | ... | @@ -30,7 +62,7 @@ |
30 | } | 62 | } |
31 | }; | 63 | }; |
32 | 64 | ||
33 | attributeBinding = function(attr) { | 65 | Rivets.Helpers.attributeBinding = function(attr) { |
34 | return function(el, value) { | 66 | return function(el, value) { |
35 | if (value) { | 67 | if (value) { |
36 | return el.setAttribute(attr, value); | 68 | return el.setAttribute(attr, value); |
... | @@ -40,22 +72,24 @@ | ... | @@ -40,22 +72,24 @@ |
40 | }; | 72 | }; |
41 | }; | 73 | }; |
42 | 74 | ||
43 | stateBinding = function(attr, inverse) { | 75 | Rivets.Helpers.stateBinding = function(attr, inverse) { |
44 | if (inverse == null) { | 76 | if (inverse == null) { |
45 | inverse = false; | 77 | inverse = false; |
46 | } | 78 | } |
47 | return function(el, value) { | 79 | return function(el, value) { |
48 | return attributeBinding(attr)(el, inverse === !value ? attr : false); | 80 | var binding; |
81 | binding = Rivets.Helpers.attributeBinding(attr); | ||
82 | return binding(el, inverse === !value ? attr : false); | ||
49 | }; | 83 | }; |
50 | }; | 84 | }; |
51 | 85 | ||
52 | bindings = { | 86 | Rivets.bindings = { |
53 | checked: stateBinding('checked'), | 87 | checked: Rivets.Helpers.stateBinding('checked'), |
54 | selected: stateBinding('selected'), | 88 | selected: Rivets.Helpers.stateBinding('selected'), |
55 | disabled: stateBinding('disabled'), | 89 | disabled: Rivets.Helpers.stateBinding('disabled'), |
56 | unchecked: stateBinding('checked', true), | 90 | unchecked: Rivets.Helpers.stateBinding('checked', true), |
57 | unselected: stateBinding('selected', true), | 91 | unselected: Rivets.Helpers.stateBinding('selected', true), |
58 | enabled: stateBinding('disabled', true), | 92 | enabled: Rivets.Helpers.stateBinding('disabled', true), |
59 | text: function(el, value) { | 93 | text: function(el, value) { |
60 | return el.innerText = value || ''; | 94 | return el.innerText = value || ''; |
61 | }, | 95 | }, |
... | @@ -73,14 +107,14 @@ | ... | @@ -73,14 +107,14 @@ |
73 | } | 107 | } |
74 | }; | 108 | }; |
75 | 109 | ||
76 | bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected']; | 110 | Rivets.bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected']; |
77 | 111 | ||
78 | rivets = { | 112 | Rivets["interface"] = { |
79 | register: function(routine, routineFunction) { | 113 | register: function(routine, routineFunction) { |
80 | return bindings[routine] = routineFunction; | 114 | return Rivets.bindings[routine] = routineFunction; |
81 | }, | 115 | }, |
82 | bind: function(el, adapter, contexts) { | 116 | bind: function(el, adapter, contexts) { |
83 | var attribute, context, keypath, node, path, type, _i, _len, _ref, _results; | 117 | var attribute, binding, context, keypath, node, path, type, _i, _len, _ref, _results; |
84 | if (contexts == null) { | 118 | if (contexts == null) { |
85 | contexts = {}; | 119 | contexts = {}; |
86 | } | 120 | } |
... | @@ -99,7 +133,8 @@ | ... | @@ -99,7 +133,8 @@ |
99 | path = attribute.value.split('.'); | 133 | path = attribute.value.split('.'); |
100 | context = path.shift(); | 134 | context = path.shift(); |
101 | keypath = path.join('.'); | 135 | keypath = path.join('.'); |
102 | _results1.push(registerBinding(node, adapter, type, contexts[context], keypath)); | 136 | binding = new Rivets.Binding(node, adapter, type, contexts[context], keypath); |
137 | _results1.push(binding.bind()); | ||
103 | } else { | 138 | } else { |
104 | _results1.push(void 0); | 139 | _results1.push(void 0); |
105 | } | 140 | } |
... | @@ -112,9 +147,9 @@ | ... | @@ -112,9 +147,9 @@ |
112 | }; | 147 | }; |
113 | 148 | ||
114 | if (typeof module !== "undefined" && module !== null) { | 149 | if (typeof module !== "undefined" && module !== null) { |
115 | module.exports = rivets; | 150 | module.exports = Rivets["interface"]; |
116 | } else { | 151 | } else { |
117 | this.rivets = rivets; | 152 | this.rivets = Rivets["interface"]; |
118 | } | 153 | } |
119 | 154 | ||
120 | }).call(this); | 155 | }).call(this); | ... | ... |
... | @@ -3,53 +3,60 @@ | ... | @@ -3,53 +3,60 @@ |
3 | # author : Michael Richards | 3 | # author : Michael Richards |
4 | # license : MIT | 4 | # license : MIT |
5 | 5 | ||
6 | # Registers a specific binding routine between a model object and a DOM element. | 6 | Rivets = |
7 | # All information for that routine is passed in when calling this function; the | 7 | Helpers: {} |
8 | # specific element to bind to, an adapter interface for the model object, the | ||
9 | # type of binding, the context object and the keypath at which to subscribe to | ||
10 | # on the model object. | ||
11 | registerBinding = (el, adapter, type, context, keypath) -> | ||
12 | bind = bindings[type] || attributeBinding type | ||
13 | bind el, adapter.read context, keypath | ||
14 | 8 | ||
15 | adapter.subscribe context, keypath, (value) -> | 9 | class Rivets.Binding |
16 | bind el, value | 10 | constructor: (@el, @adapter, @type, @context, @keypath) -> |
11 | @routine = Rivets.bindings[@type] || Rivets.Helpers.attributeBinding @type | ||
17 | 12 | ||
18 | if type in bidirectionals | 13 | # Sets a value for this binding. Basically just runs the routine on the |
19 | el.addEventListener 'change', -> | 14 | # element with a suplied value. |
20 | adapter.publish context, keypath, getInputValue this | 15 | set: (value = null) => |
16 | @routine @el, value || @adapter.read @context, @keypath | ||
17 | |||
18 | # Subscribes to the context object for changes on the specific keypath. | ||
19 | # Conditionally also does the inverse and listens to the element for changes | ||
20 | # to propogate back to the context object. | ||
21 | bind: => | ||
22 | @adapter.subscribe @context, @keypath, (value) => @set value | ||
23 | |||
24 | if @type in Rivets.bidirectionals | ||
25 | @el.addEventListener 'change', (el) => | ||
26 | @adapter.publish @context, @keypath, Rivets.Helpers.getInputValue el | ||
21 | 27 | ||
22 | # Returns the current input value for the specified element. | 28 | # Returns the current input value for the specified element. |
23 | getInputValue = (el) -> | 29 | Rivets.Helpers.getInputValue = (el) -> |
24 | switch el.type | 30 | switch el.type |
25 | when 'text', 'textarea', 'password', 'select-one' then el.value | 31 | when 'text', 'textarea', 'password', 'select-one' then el.value |
26 | when 'checkbox', 'radio' then el.checked | 32 | when 'checkbox', 'radio' then el.checked |
27 | 33 | ||
28 | # Returns an attribute binding routine for the specified attribute. This is what | 34 | # Returns an attribute binding routine for the specified attribute. This is what |
29 | # `registerBinding` falls back to when there is no routine for the binding type. | 35 | # `registerBinding` falls back to when there is no routine for the binding type. |
30 | attributeBinding = (attr) -> (el, value) -> | 36 | Rivets.Helpers.attributeBinding = (attr) -> (el, value) -> |
31 | if value then el.setAttribute attr, value else el.removeAttribute attr | 37 | if value then el.setAttribute attr, value else el.removeAttribute attr |
32 | 38 | ||
33 | # Returns a state binding routine for the specified attribute. Can optionally be | 39 | # Returns a state binding routine for the specified attribute. Can optionally be |
34 | # negatively evaluated. This is used to build a lot of the core state binding | 40 | # negatively evaluated. This is used to build a lot of the core state binding |
35 | # routines. | 41 | # routines. |
36 | stateBinding = (attr, inverse = false) -> (el, value) -> | 42 | Rivets.Helpers.stateBinding = (attr, inverse = false) -> (el, value) -> |
37 | attributeBinding(attr) el, if inverse is !value then attr else false | 43 | binding = Rivets.Helpers.attributeBinding(attr) |
44 | binding el, if inverse is !value then attr else false | ||
38 | 45 | ||
39 | # Core binding routines. | 46 | # Core binding routines. |
40 | bindings = | 47 | Rivets.bindings = |
41 | checked: | 48 | checked: |
42 | stateBinding 'checked' | 49 | Rivets.Helpers.stateBinding 'checked' |
43 | selected: | 50 | selected: |
44 | stateBinding 'selected' | 51 | Rivets.Helpers.stateBinding 'selected' |
45 | disabled: | 52 | disabled: |
46 | stateBinding 'disabled' | 53 | Rivets.Helpers.stateBinding 'disabled' |
47 | unchecked: | 54 | unchecked: |
48 | stateBinding 'checked', true | 55 | Rivets.Helpers.stateBinding 'checked', true |
49 | unselected: | 56 | unselected: |
50 | stateBinding 'selected', true | 57 | Rivets.Helpers.stateBinding 'selected', true |
51 | enabled: | 58 | enabled: |
52 | stateBinding 'disabled', true | 59 | Rivets.Helpers.stateBinding 'disabled', true |
53 | text: (el, value) -> | 60 | text: (el, value) -> |
54 | el.innerText = value or '' | 61 | el.innerText = value or '' |
55 | html: (el, value) -> | 62 | html: (el, value) -> |
... | @@ -63,13 +70,13 @@ bindings = | ... | @@ -63,13 +70,13 @@ bindings = |
63 | 70 | ||
64 | # Bindings that should also be observed for changes on the DOM element in order | 71 | # Bindings that should also be observed for changes on the DOM element in order |
65 | # to propogate those changes back to the model object. | 72 | # to propogate those changes back to the model object. |
66 | bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected'] | 73 | Rivets.bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected'] |
67 | 74 | ||
68 | # The rivets module exposes `register` and `bind` functions to register new | 75 | # The rivets module exposes `register` and `bind` functions to register new |
69 | # binding routines and bind contexts to DOM elements. | 76 | # binding routines and bind contexts to DOM elements. |
70 | rivets = | 77 | Rivets.interface = |
71 | register: (routine, routineFunction) -> | 78 | register: (routine, routineFunction) -> |
72 | bindings[routine] = routineFunction | 79 | Rivets.bindings[routine] = routineFunction |
73 | 80 | ||
74 | bind: (el, adapter, contexts = {}) -> | 81 | bind: (el, adapter, contexts = {}) -> |
75 | for node in el.getElementsByTagName '*' | 82 | for node in el.getElementsByTagName '*' |
... | @@ -79,10 +86,12 @@ rivets = | ... | @@ -79,10 +86,12 @@ rivets = |
79 | path = attribute.value.split '.' | 86 | path = attribute.value.split '.' |
80 | context = path.shift() | 87 | context = path.shift() |
81 | keypath = path.join '.' | 88 | keypath = path.join '.' |
82 | registerBinding node, adapter, type, contexts[context], keypath | 89 | |
90 | binding = new Rivets.Binding node, adapter, type, contexts[context], keypath | ||
91 | binding.bind() | ||
83 | 92 | ||
84 | # Exports rivets for both CommonJS and the browser. | 93 | # Exports rivets for both CommonJS and the browser. |
85 | if module? | 94 | if module? |
86 | module.exports = rivets | 95 | module.exports = Rivets.interface |
87 | else | 96 | else |
88 | @rivets = rivets | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
97 | @rivets = Rivets.interface | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or sign in to post a comment