Set local options on the Rivets.View instance by merging the global with the pas…
…sed-in options in the constructor. Access config, binders and formatters from the view inside of Rivets.Binding so that we get the local options to take precedence over globally set options. [Closes #81, #134]
Showing
1 changed file
with
33 additions
and
33 deletions
... | @@ -11,12 +11,12 @@ unless String::trim then String::trim = -> @replace /^\s+|\s+$/g, '' | ... | @@ -11,12 +11,12 @@ unless String::trim then String::trim = -> @replace /^\s+|\s+$/g, '' |
11 | 11 | ||
12 | # A single binding between a model attribute and a DOM element. | 12 | # A single binding between a model attribute and a DOM element. |
13 | class Rivets.Binding | 13 | class Rivets.Binding |
14 | # All information about the binding is passed into the constructor; the DOM | 14 | # All information about the binding is passed into the constructor; the |
15 | # element, the type of binding, the model object and the keypath at which | 15 | # containing view, the DOM node, the type of binding, the model object and the |
16 | # to listen for changes. | 16 | # keypath at which to listen for changes. |
17 | constructor: (@el, @type, @model, @keypath, @options = {}) -> | 17 | constructor: (@view, @el, @type, @model, @keypath, @options = {}) -> |
18 | unless @binder = Rivets.binders[type] | 18 | unless @binder = @view.binders[type] |
19 | for identifier, value of Rivets.binders | 19 | for identifier, value of @view.binders |
20 | if identifier isnt '*' and identifier.indexOf('*') isnt -1 | 20 | if identifier isnt '*' and identifier.indexOf('*') isnt -1 |
21 | regexp = new RegExp "^#{identifier.replace('*', '.+')}$" | 21 | regexp = new RegExp "^#{identifier.replace('*', '.+')}$" |
22 | if regexp.test type | 22 | if regexp.test type |
... | @@ -24,7 +24,7 @@ class Rivets.Binding | ... | @@ -24,7 +24,7 @@ class Rivets.Binding |
24 | @args = new RegExp("^#{identifier.replace('*', '(.+)')}$").exec type | 24 | @args = new RegExp("^#{identifier.replace('*', '(.+)')}$").exec type |
25 | @args.shift() | 25 | @args.shift() |
26 | 26 | ||
27 | @binder or= Rivets.binders['*'] | 27 | @binder or= @view.binders['*'] |
28 | 28 | ||
29 | if @binder instanceof Function | 29 | if @binder instanceof Function |
30 | @binder = {routine: @binder} | 30 | @binder = {routine: @binder} |
... | @@ -43,7 +43,7 @@ class Rivets.Binding | ... | @@ -43,7 +43,7 @@ class Rivets.Binding |
43 | else if @options?.bindingOptions?.formatters?[id] instanceof Function | 43 | else if @options?.bindingOptions?.formatters?[id] instanceof Function |
44 | @options.bindingOptions.formatters[id] | 44 | @options.bindingOptions.formatters[id] |
45 | else | 45 | else |
46 | Rivets.formatters[id] | 46 | @view.formatters[id] |
47 | 47 | ||
48 | if formatter?.read instanceof Function | 48 | if formatter?.read instanceof Function |
49 | value = formatter.read value, args... | 49 | value = formatter.read value, args... |
... | @@ -67,7 +67,7 @@ class Rivets.Binding | ... | @@ -67,7 +67,7 @@ class Rivets.Binding |
67 | @set if @options.bypass | 67 | @set if @options.bypass |
68 | @model[@keypath] | 68 | @model[@keypath] |
69 | else | 69 | else |
70 | Rivets.config.adapter.read @model, @keypath | 70 | @view.config.adapter.read @model, @keypath |
71 | 71 | ||
72 | # Publishes the value currently set on the input element back to the model. | 72 | # Publishes the value currently set on the input element back to the model. |
73 | publish: => | 73 | publish: => |
... | @@ -77,10 +77,10 @@ class Rivets.Binding | ... | @@ -77,10 +77,10 @@ class Rivets.Binding |
77 | args = formatter.split /\s+/ | 77 | args = formatter.split /\s+/ |
78 | id = args.shift() | 78 | id = args.shift() |
79 | 79 | ||
80 | if Rivets.formatters[id]?.publish | 80 | if @view.formatters[id]?.publish |
81 | value = Rivets.formatters[id].publish value, args... | 81 | value = @view.formatters[id].publish value, args... |
82 | 82 | ||
83 | Rivets.config.adapter.publish @model, @keypath, value | 83 | @view.config.adapter.publish @model, @keypath, value |
84 | 84 | ||
85 | # Subscribes to the model for changes at the specified keypath. Bi-directional | 85 | # Subscribes to the model for changes at the specified keypath. Bi-directional |
86 | # routines will also listen for changes on the element to propagate them back | 86 | # routines will also listen for changes on the element to propagate them back |
... | @@ -91,8 +91,8 @@ class Rivets.Binding | ... | @@ -91,8 +91,8 @@ class Rivets.Binding |
91 | if @options.bypass | 91 | if @options.bypass |
92 | @sync() | 92 | @sync() |
93 | else | 93 | else |
94 | Rivets.config.adapter.subscribe @model, @keypath, @sync | 94 | @view.config.adapter.subscribe @model, @keypath, @sync |
95 | @sync() if Rivets.config.preloadData | 95 | @sync() if @view.config.preloadData |
96 | 96 | ||
97 | if @options.dependencies?.length | 97 | if @options.dependencies?.length |
98 | for dependency in @options.dependencies | 98 | for dependency in @options.dependencies |
... | @@ -104,14 +104,14 @@ class Rivets.Binding | ... | @@ -104,14 +104,14 @@ class Rivets.Binding |
104 | model = @view.models[dependency.shift()] | 104 | model = @view.models[dependency.shift()] |
105 | keypath = dependency.join '.' | 105 | keypath = dependency.join '.' |
106 | 106 | ||
107 | Rivets.config.adapter.subscribe model, keypath, @sync | 107 | @view.config.adapter.subscribe model, keypath, @sync |
108 | 108 | ||
109 | # Unsubscribes from the model and the element. | 109 | # Unsubscribes from the model and the element. |
110 | unbind: => | 110 | unbind: => |
111 | @binder.unbind?.call @, @el | 111 | @binder.unbind?.call @, @el |
112 | 112 | ||
113 | unless @options.bypass | 113 | unless @options.bypass |
114 | Rivets.config.adapter.unsubscribe @model, @keypath, @sync | 114 | @view.config.adapter.unsubscribe @model, @keypath, @sync |
115 | 115 | ||
116 | if @options.dependencies?.length | 116 | if @options.dependencies?.length |
117 | for dependency in @options.dependencies | 117 | for dependency in @options.dependencies |
... | @@ -123,19 +123,26 @@ class Rivets.Binding | ... | @@ -123,19 +123,26 @@ class Rivets.Binding |
123 | model = @view.models[dependency.shift()] | 123 | model = @view.models[dependency.shift()] |
124 | keypath = dependency.join '.' | 124 | keypath = dependency.join '.' |
125 | 125 | ||
126 | Rivets.config.adapter.unsubscribe model, keypath, @sync | 126 | @view.config.adapter.unsubscribe model, keypath, @sync |
127 | 127 | ||
128 | # A collection of bindings built from a set of parent elements. | 128 | # A collection of bindings built from a set of parent elements. |
129 | class Rivets.View | 129 | class Rivets.View |
130 | # The DOM elements and the model objects for binding are passed into the | 130 | # The DOM elements and the model objects for binding are passed into the |
131 | # constructor. | 131 | # constructor along with any local options that should be used throughout the |
132 | constructor: (@els, @models, @options) -> | 132 | # context of the view and it's bindings. |
133 | constructor: (@els, @models, @options = {}) -> | ||
133 | @els = [@els] unless (@els.jquery || @els instanceof Array) | 134 | @els = [@els] unless (@els.jquery || @els instanceof Array) |
135 | |||
136 | for option in ['config', 'binders', 'formatters'] | ||
137 | @[option] = {} | ||
138 | @[option][k] = v for k, v of @options[option] if @options[option] | ||
139 | @[option][k] ?= v for k, v of Rivets[option] | ||
140 | |||
134 | @build() | 141 | @build() |
135 | 142 | ||
136 | # Regular expression used to match binding attributes. | 143 | # Regular expression used to match binding attributes. |
137 | bindingRegExp: => | 144 | bindingRegExp: => |
138 | prefix = Rivets.config.prefix | 145 | prefix = @config.prefix |
139 | if prefix then new RegExp("^data-#{prefix}-") else /^data-/ | 146 | if prefix then new RegExp("^data-#{prefix}-") else /^data-/ |
140 | 147 | ||
141 | # Parses the DOM tree and builds Rivets.Binding instances for every matched | 148 | # Parses the DOM tree and builds Rivets.Binding instances for every matched |
... | @@ -151,14 +158,14 @@ class Rivets.View | ... | @@ -151,14 +158,14 @@ class Rivets.View |
151 | for attribute in node.attributes | 158 | for attribute in node.attributes |
152 | if bindingRegExp.test attribute.name | 159 | if bindingRegExp.test attribute.name |
153 | type = attribute.name.replace bindingRegExp, '' | 160 | type = attribute.name.replace bindingRegExp, '' |
154 | unless binder = Rivets.binders[type] | 161 | unless binder = @binders[type] |
155 | for identifier, value of Rivets.binders | 162 | for identifier, value of @binders |
156 | if identifier isnt '*' and identifier.indexOf('*') isnt -1 | 163 | if identifier isnt '*' and identifier.indexOf('*') isnt -1 |
157 | regexp = new RegExp "^#{identifier.replace('*', '.+')}$" | 164 | regexp = new RegExp "^#{identifier.replace('*', '.+')}$" |
158 | if regexp.test type | 165 | if regexp.test type |
159 | binder = value | 166 | binder = value |
160 | 167 | ||
161 | binder or= Rivets.binders['*'] | 168 | binder or= @binders['*'] |
162 | 169 | ||
163 | if binder.block | 170 | if binder.block |
164 | skipNodes.push n for n in node.getElementsByTagName '*' | 171 | skipNodes.push n for n in node.getElementsByTagName '*' |
... | @@ -167,10 +174,6 @@ class Rivets.View | ... | @@ -167,10 +174,6 @@ class Rivets.View |
167 | for attribute in attributes or node.attributes | 174 | for attribute in attributes or node.attributes |
168 | if bindingRegExp.test attribute.name | 175 | if bindingRegExp.test attribute.name |
169 | options = {} | 176 | options = {} |
170 | |||
171 | if @options? and typeof @options is 'object' | ||
172 | options.bindingOptions = @options | ||
173 | |||
174 | type = attribute.name.replace bindingRegExp, '' | 177 | type = attribute.name.replace bindingRegExp, '' |
175 | pipes = (pipe.trim() for pipe in attribute.value.split '|') | 178 | pipes = (pipe.trim() for pipe in attribute.value.split '|') |
176 | context = (ctx.trim() for ctx in pipes.shift().split '<') | 179 | context = (ctx.trim() for ctx in pipes.shift().split '<') |
... | @@ -189,10 +192,7 @@ class Rivets.View | ... | @@ -189,10 +192,7 @@ class Rivets.View |
189 | if dependencies = context.shift() | 192 | if dependencies = context.shift() |
190 | options.dependencies = dependencies.split /\s+/ | 193 | options.dependencies = dependencies.split /\s+/ |
191 | 194 | ||
192 | binding = new Rivets.Binding node, type, model, keypath, options | 195 | @bindings.push new Rivets.Binding @, node, type, model, keypath, options |
193 | binding.view = @ | ||
194 | |||
195 | @bindings.push binding | ||
196 | 196 | ||
197 | attributes = null if attributes | 197 | attributes = null if attributes |
198 | 198 | ||
... | @@ -344,7 +344,7 @@ Rivets.binders = | ... | @@ -344,7 +344,7 @@ Rivets.binders = |
344 | "each-*": | 344 | "each-*": |
345 | block: true | 345 | block: true |
346 | bind: (el, collection) -> | 346 | bind: (el, collection) -> |
347 | el.removeAttribute ['data', Rivets.config.prefix, @type].join('-').replace '--', '-' | 347 | el.removeAttribute ['data', @view.config.prefix, @type].join('-').replace '--', '-' |
348 | routine: (el, collection) -> | 348 | routine: (el, collection) -> |
349 | if @iterated? | 349 | if @iterated? |
350 | for view in @iterated | 350 | for view in @iterated |
... | @@ -370,7 +370,7 @@ Rivets.binders = | ... | @@ -370,7 +370,7 @@ Rivets.binders = |
370 | @marker | 370 | @marker |
371 | 371 | ||
372 | @marker.parentNode.insertBefore itemEl, previous.nextSibling ? null | 372 | @marker.parentNode.insertBefore itemEl, previous.nextSibling ? null |
373 | view = new Rivets.View(itemEl, data) | 373 | view = new Rivets.View(itemEl, data, @view.options) |
374 | view.bind() | 374 | view.bind() |
375 | @iterated.push view | 375 | @iterated.push view |
376 | 376 | ... | ... |
-
Please register or sign in to post a comment