9302110a by Michael Richards

Move the component view initialization into it's own binding so that we can have…

… it bind, unbind and update with it's parent view.
1 parent 0b0ab448
...@@ -155,6 +155,56 @@ class Rivets.Binding ...@@ -155,6 +155,56 @@ class Rivets.Binding
155 155
156 @binder.update?.call @, models 156 @binder.update?.call @, models
157 157
158 # Rivets.ComponentBinding
159 # -----------------------
160
161 # A component view encapsulated in a binding within it's parent view.
162 class Rivets.ComponentBinding extends Rivets.Binding
163 # Initializes a component binding for the specified view. The raw component
164 # element is passed in along with the component type. Attributes and scope
165 # inflections are determined based on the components defined attributes.
166 constructor: (@view, @el, @type) ->
167 @component = Rivets.components[@type]
168 @attributes = {}
169 @inflections = {}
170
171 for attribute in @el.attributes or []
172 if attribute.name in @component.attributes
173 @attributes[attribute.name] = attribute.value
174 else
175 @inflections[attribute.name] = attribute.value
176
177 # Intercepts `Rivets.View::sync` since component bindings are not bound to a
178 # particular model to update it's value.
179 sync: ->
180
181 # Returns an object map using the component's scope inflections.
182 locals: (models = @view.models) =>
183 result = {}
184 result[key] = models[inverse] for key, inverse of @inflections
185 result[key] ?= model for key, model of models
186
187 result
188
189 # Intercepts `Rivets.View::update` to be called on `@componentView` with a
190 # localized map of the models.
191 update: (models) =>
192 @componentView?.update @locals models
193
194 # Intercepts `Rivets.View::bind` to build `@componentView` with a localized
195 # map of models from the root view. Bind `@componentView` on subsequent calls.
196 bind: =>
197 if @componentView?
198 @componentView?.bind()
199 else
200 el = @component.build.call @attributes
201 (@componentView = new Rivets.View(el, @locals(), @view.options)).bind()
202 @el.parentNode.replaceChild el, @el
203
204 # Intercept `Rivets.View::unbind` to be called on `@componentView`.
205 unbind: =>
206 @componentView?.unbind()
207
158 # Rivets.View 208 # Rivets.View
159 # ----------- 209 # -----------
160 210
...@@ -183,8 +233,7 @@ class Rivets.View ...@@ -183,8 +233,7 @@ class Rivets.View
183 new RegExp "^#{@config.prefix?.toUpperCase() ? 'RV'}-" 233 new RegExp "^#{@config.prefix?.toUpperCase() ? 'RV'}-"
184 234
185 # Parses the DOM tree and builds `Rivets.Binding` instances for every matched 235 # Parses the DOM tree and builds `Rivets.Binding` instances for every matched
186 # binding declaration. Subsequent calls to build will replace the previous 236 # binding declaration.
187 # `Rivets.Binding` instances with new ones, so be sure to unbind them first.
188 build: => 237 build: =>
189 @bindings = [] 238 @bindings = []
190 skipNodes = [] 239 skipNodes = []
...@@ -235,27 +284,8 @@ class Rivets.View ...@@ -235,27 +284,8 @@ class Rivets.View
235 buildBinding text, 'textNode', token.value if token.type is 1 284 buildBinding text, 'textNode', token.value if token.type is 1
236 else if componentRegExp.test node.tagName 285 else if componentRegExp.test node.tagName
237 type = node.tagName.replace(componentRegExp, '').toLowerCase() 286 type = node.tagName.replace(componentRegExp, '').toLowerCase()
287 @bindings.push new Rivets.ComponentBinding @, node, type
238 288
239 if component = Rivets.components[type]
240 attributes = {}
241 inflections = {}
242
243 for attribute in node.attributes or []
244 if attribute.name in component.attributes
245 attributes[attribute.name] = attribute.value
246 else
247 model = @models
248 model = model[key] for key in attribute.value.split('.')
249 inflections[attribute.name] = model
250
251 el = component.build.call(attributes)
252
253 models = {}
254 models[key] = model for key, model of inflections
255 models[key] ?= model for key, model of @models
256
257 (view = new Rivets.View(el, models, @options)).bind()
258 node.parentNode.replaceChild el, node
259 else if node.attributes? 289 else if node.attributes?
260 for attribute in node.attributes 290 for attribute in node.attributes
261 if bindingRegExp.test attribute.name 291 if bindingRegExp.test attribute.name
......