532ea233 by Michael Richards

Update bindings and view parsing logic so that we're working with each individua…

…l section of a keypath (path + interface).
1 parent 467630fe
...@@ -23,7 +23,12 @@ class Rivets.Binding ...@@ -23,7 +23,12 @@ class Rivets.Binding
23 # All information about the binding is passed into the constructor; the 23 # All information about the binding is passed into the constructor; the
24 # containing view, the DOM node, the type of binding, the model object and the 24 # containing view, the DOM node, the type of binding, the model object and the
25 # keypath at which to listen for changes. 25 # keypath at which to listen for changes.
26 constructor: (@view, @el, @type, @key, @keypath, @options = {}) -> 26 constructor: (@view, @el, @type, @keypath, @options = {}) ->
27 @formatters = @options.formatters || []
28 @setBinders()
29 @setModel()
30
31 setBinders: =>
27 unless @binder = @view.binders[type] 32 unless @binder = @view.binders[type]
28 for identifier, value of @view.binders 33 for identifier, value of @view.binders
29 if identifier isnt '*' and identifier.indexOf('*') isnt -1 34 if identifier isnt '*' and identifier.indexOf('*') isnt -1
...@@ -35,8 +40,17 @@ class Rivets.Binding ...@@ -35,8 +40,17 @@ class Rivets.Binding
35 40
36 @binder or= @view.binders['*'] 41 @binder or= @view.binders['*']
37 @binder = {routine: @binder} if @binder instanceof Function 42 @binder = {routine: @binder} if @binder instanceof Function
38 @formatters = @options.formatters || [] 43
39 @model = if @key then @view.models[@key] else @view.models 44 setModel: =>
45 interfaces = (k for k, v of @view.adapters)
46 tokens = Rivets.KeypathParser.parse @keypath, interfaces, '.'
47
48 @model = @view.models
49 @rootKey = tokens[0]
50 @key = tokens.pop()
51
52 for token, index in tokens
53 @model = @view.adapters[token.interface].read(@model, token.path)
40 54
41 # Applies all the current formatters to the supplied value and returns the 55 # Applies all the current formatters to the supplied value and returns the
42 # formatted value. 56 # formatted value.
...@@ -74,7 +88,7 @@ class Rivets.Binding ...@@ -74,7 +88,7 @@ class Rivets.Binding
74 88
75 # Syncs up the view binding with the model. 89 # Syncs up the view binding with the model.
76 sync: => 90 sync: =>
77 @set @view.adapters['.'].read @model, @keypath 91 @set @view.adapters[@key.interface].read @model, @key.path
78 92
79 # Publishes the value currently set on the input element back to the model. 93 # Publishes the value currently set on the input element back to the model.
80 publish: => 94 publish: =>
...@@ -87,14 +101,14 @@ class Rivets.Binding ...@@ -87,14 +101,14 @@ class Rivets.Binding
87 if @view.formatters[id]?.publish 101 if @view.formatters[id]?.publish
88 value = @view.formatters[id].publish value, args... 102 value = @view.formatters[id].publish value, args...
89 103
90 @view.adapters['.'].publish @model, @keypath, value 104 @view.adapters[@key.interface].publish @model, @key.path, value
91 105
92 # Subscribes to the model for changes at the specified keypath. Bi-directional 106 # Subscribes to the model for changes at the specified keypath. Bi-directional
93 # routines will also listen for changes on the element to propagate them back 107 # routines will also listen for changes on the element to propagate them back
94 # to the model. 108 # to the model.
95 bind: => 109 bind: =>
96 @binder.bind?.call @, @el 110 @binder.bind?.call @, @el
97 @view.adapters['.'].subscribe @model, @keypath, @sync 111 @view.adapters[@key.interface].subscribe @model, @key.path, @sync
98 @sync() if @view.config.preloadData 112 @sync() if @view.config.preloadData
99 113
100 if @options.dependencies?.length 114 if @options.dependencies?.length
...@@ -112,7 +126,7 @@ class Rivets.Binding ...@@ -112,7 +126,7 @@ class Rivets.Binding
112 # Unsubscribes from the model and the element. 126 # Unsubscribes from the model and the element.
113 unbind: => 127 unbind: =>
114 @binder.unbind?.call @, @el 128 @binder.unbind?.call @, @el
115 @view.adapters['.'].unsubscribe @model, @keypath, @sync 129 @view.adapters[@key.interface].unsubscribe @model, @key.path, @sync
116 130
117 if @options.dependencies?.length 131 if @options.dependencies?.length
118 for dependency in @options.dependencies 132 for dependency in @options.dependencies
...@@ -129,13 +143,10 @@ class Rivets.Binding ...@@ -129,13 +143,10 @@ class Rivets.Binding
129 # Updates the binding's model from what is currently set on the view. Unbinds 143 # Updates the binding's model from what is currently set on the view. Unbinds
130 # the old model first and then re-binds with the new model. 144 # the old model first and then re-binds with the new model.
131 update: (models = {}) => 145 update: (models = {}) =>
132 if @key 146 if models[@rootKey.path]
133 if models[@key] 147 @view.adapters[@key.interface].unsubscribe @model, @key.path, @sync
134 @view.adapters['.'].unsubscribe @model, @keypath, @sync 148 @setModel()
135 @model = models[@key] 149 @view.adapters[@key.interface].subscribe @model, @key.path, @sync
136 @view.adapters['.'].subscribe @model, @keypath, @sync
137 @sync() if @view.config.preloadData
138 else
139 @sync() 150 @sync()
140 151
141 @binder.update?.call @, models 152 @binder.update?.call @, models
...@@ -199,9 +210,11 @@ class Rivets.ComponentBinding extends Rivets.Binding ...@@ -199,9 +210,11 @@ class Rivets.ComponentBinding extends Rivets.Binding
199 # differences while avoiding it being overwritten. 210 # differences while avoiding it being overwritten.
200 class Rivets.TextBinding extends Rivets.Binding 211 class Rivets.TextBinding extends Rivets.Binding
201 # Initializes a text binding for the specified view and text node. 212 # Initializes a text binding for the specified view and text node.
202 constructor: (@view, @el, @type, @key, @keypath, @options = {}) -> 213 constructor: (@view, @el, @type, @keypath, @options = {}) ->
214 interfaces = (k for k, v of @view.adapters)
215 tokens = Rivets.KeypathParser.parse(@keypath, interfaces, '.')
203 @formatters = @options.formatters || [] 216 @formatters = @options.formatters || []
204 @model = if @key then @view.models[@key] else @view.models 217 @setModel()
205 218
206 # A standard routine binder used for text node bindings. 219 # A standard routine binder used for text node bindings.
207 binder: 220 binder:
...@@ -252,22 +265,14 @@ class Rivets.View ...@@ -252,22 +265,14 @@ class Rivets.View
252 265
253 pipes = (pipe.trim() for pipe in declaration.split '|') 266 pipes = (pipe.trim() for pipe in declaration.split '|')
254 context = (ctx.trim() for ctx in pipes.shift().split '<') 267 context = (ctx.trim() for ctx in pipes.shift().split '<')
255 path = context.shift() 268 keypath = context.shift()
256 splitPath = path.split '.'
257 options.formatters = pipes
258 269
259 if splitPath[0] 270 options.formatters = pipes
260 key = splitPath.shift()
261 else
262 key = null
263 splitPath.shift()
264
265 keypath = splitPath.join '.'
266 271
267 if dependencies = context.shift() 272 if dependencies = context.shift()
268 options.dependencies = dependencies.split /\s+/ 273 options.dependencies = dependencies.split /\s+/
269 274
270 @bindings.push new Rivets[binding] @, node, type, key, keypath, options 275 @bindings.push new Rivets[binding] @, node, type, keypath, options
271 276
272 parse = (node) => 277 parse = (node) =>
273 unless node in skipNodes 278 unless node in skipNodes
...@@ -553,6 +558,7 @@ Rivets.binders = ...@@ -553,6 +558,7 @@ Rivets.binders =
553 options = 558 options =
554 binders: @view.options.binders 559 binders: @view.options.binders
555 formatters: @view.options.formatters 560 formatters: @view.options.formatters
561 adapters: @view.options.adapters
556 config: @view.options.config 562 config: @view.options.config
557 563
558 (@nested = new Rivets.View(el, models, options)).bind() 564 (@nested = new Rivets.View(el, models, options)).bind()
...@@ -632,6 +638,7 @@ Rivets.binders = ...@@ -632,6 +638,7 @@ Rivets.binders =
632 options = 638 options =
633 binders: @view.options.binders 639 binders: @view.options.binders
634 formatters: @view.options.formatters 640 formatters: @view.options.formatters
641 adapters: @view.options.adapters
635 config: {} 642 config: {}
636 643
637 options.config[k] = v for k, v of @view.options.config 644 options.config[k] = v for k, v of @view.options.config
......