0b0ab448 by Michael Richards

Initial components implementation with custom attributes and scope inflections.

1 parent 3554d8f9
...@@ -178,6 +178,10 @@ class Rivets.View ...@@ -178,6 +178,10 @@ class Rivets.View
178 prefix = @config.prefix 178 prefix = @config.prefix
179 if prefix then new RegExp("^data-#{prefix}-") else /^data-/ 179 if prefix then new RegExp("^data-#{prefix}-") else /^data-/
180 180
181 # Regular expression used to match component nodes.
182 componentRegExp: =>
183 new RegExp "^#{@config.prefix?.toUpperCase() ? 'RV'}-"
184
181 # Parses the DOM tree and builds `Rivets.Binding` instances for every matched 185 # Parses the DOM tree and builds `Rivets.Binding` instances for every matched
182 # binding declaration. Subsequent calls to build will replace the previous 186 # binding declaration. Subsequent calls to build will replace the previous
183 # `Rivets.Binding` instances with new ones, so be sure to unbind them first. 187 # `Rivets.Binding` instances with new ones, so be sure to unbind them first.
...@@ -185,6 +189,8 @@ class Rivets.View ...@@ -185,6 +189,8 @@ class Rivets.View
185 @bindings = [] 189 @bindings = []
186 skipNodes = [] 190 skipNodes = []
187 bindingRegExp = @bindingRegExp() 191 bindingRegExp = @bindingRegExp()
192 componentRegExp = @componentRegExp()
193
188 194
189 buildBinding = (node, type, declaration) => 195 buildBinding = (node, type, declaration) =>
190 options = {} 196 options = {}
...@@ -227,7 +233,29 @@ class Rivets.View ...@@ -227,7 +233,29 @@ class Rivets.View
227 for token in restTokens 233 for token in restTokens
228 node.parentNode.appendChild (text = document.createTextNode token.value) 234 node.parentNode.appendChild (text = document.createTextNode token.value)
229 buildBinding text, 'textNode', token.value if token.type is 1 235 buildBinding text, 'textNode', token.value if token.type is 1
236 else if componentRegExp.test node.tagName
237 type = node.tagName.replace(componentRegExp, '').toLowerCase()
230 238
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
231 else if node.attributes? 259 else if node.attributes?
232 for attribute in node.attributes 260 for attribute in node.attributes
233 if bindingRegExp.test attribute.name 261 if bindingRegExp.test attribute.name
...@@ -591,6 +619,14 @@ Rivets.internalBinders = ...@@ -591,6 +619,14 @@ Rivets.internalBinders =
591 textNode: (node, value) -> 619 textNode: (node, value) ->
592 node.data = value ? '' 620 node.data = value ? ''
593 621
622 # Rivets.components
623 # -----------------
624
625 # Default components (there aren't any), publicly accessible on
626 # `module.components`. Can be overridden globally or local to a `Rivets.View`
627 # instance.
628 Rivets.components = {}
629
594 # Rivets.config 630 # Rivets.config
595 # ------------- 631 # -------------
596 632
...@@ -620,6 +656,9 @@ Rivets.factory = (exports) -> ...@@ -620,6 +656,9 @@ Rivets.factory = (exports) ->
620 # Exposes the core binding routines that can be extended or stripped down. 656 # Exposes the core binding routines that can be extended or stripped down.
621 exports.binders = Rivets.binders 657 exports.binders = Rivets.binders
622 658
659 # Exposes the components object to be extended.
660 exports.components = Rivets.components
661
623 # Exposes the formatters object to be extended. 662 # Exposes the formatters object to be extended.
624 exports.formatters = Rivets.formatters 663 exports.formatters = Rivets.formatters
625 664
......