Implement a portable keypath observer.
Showing
3 changed files
with
36 additions
and
26 deletions
... | @@ -20,6 +20,7 @@ module.exports = (grunt) -> | ... | @@ -20,6 +20,7 @@ module.exports = (grunt) -> |
20 | 'src/view.coffee' | 20 | 'src/view.coffee' |
21 | 'src/bindings.coffee' | 21 | 'src/bindings.coffee' |
22 | 'src/parsers.coffee' | 22 | 'src/parsers.coffee' |
23 | 'src/keypath_observer.coffee' | ||
23 | 'src/binders.coffee' | 24 | 'src/binders.coffee' |
24 | 'src/adapters.coffee' | 25 | 'src/adapters.coffee' |
25 | 'src/export.coffee' | 26 | 'src/export.coffee' | ... | ... |
... | @@ -27,35 +27,15 @@ class Rivets.Binding | ... | @@ -27,35 +27,15 @@ class Rivets.Binding |
27 | @binder = {routine: @binder} if @binder instanceof Function | 27 | @binder = {routine: @binder} if @binder instanceof Function |
28 | 28 | ||
29 | setModel: => | 29 | setModel: => |
30 | interfaces = (k for k, v of @view.adapters) | 30 | observer = new KeypathObserver @view, @view.models, @keypath, (target) => |
31 | tokens = Rivets.KeypathParser.parse @keypath, interfaces, @view.config.rootInterface | ||
32 | |||
33 | @rootKey = tokens.shift() | ||
34 | @key = tokens.pop() | ||
35 | @objectPath ?= [] | ||
36 | |||
37 | model = @view.adapters[@rootKey.interface].read @view.models, @rootKey.path | ||
38 | |||
39 | for token, index in tokens | ||
40 | current = @view.adapters[token.interface].read model, token.path | ||
41 | |||
42 | if @objectPath[index]? | ||
43 | if current isnt @objectPath[index] | ||
44 | @view.adapters[token.interface].unsubscribe model, token.path, @setModel | ||
45 | @view.adapters[token.interface].subscribe current, token.path, @setModel | ||
46 | else | ||
47 | @view.adapters[token.interface].subscribe model, token.path, @setModel | ||
48 | |||
49 | model = current | ||
50 | |||
51 | if @model | ||
52 | if @model isnt model | ||
53 | @unbind true if @key | 31 | @unbind true if @key |
54 | @model = model | 32 | @model = target |
55 | @bind true if @key | 33 | @bind true if @key |
56 | @sync() | 34 | @sync() |
57 | else | 35 | |
58 | @model = model | 36 | @rootKey = observer.root |
37 | @key = observer.key | ||
38 | @model = observer.target | ||
59 | 39 | ||
60 | # Applies all the current formatters to the supplied value and returns the | 40 | # Applies all the current formatters to the supplied value and returns the |
61 | # formatted value. | 41 | # formatted value. | ... | ... |
src/keypath_observer.coffee
0 → 100644
1 | class KeypathObserver | ||
2 | constructor: (@view, @model, @keypath, @callback) -> | ||
3 | @interfaces = (k for k, v of @view.adapters) | ||
4 | @objectPath = [] | ||
5 | @tokens = Rivets.KeypathParser.parse @keypath, @interfaces, @view.config.rootInterface | ||
6 | @root = @tokens.shift() | ||
7 | @key = @tokens.pop() | ||
8 | @target = @realize() | ||
9 | |||
10 | update: => | ||
11 | unless (next = @realize()) is @target | ||
12 | @callback @target = next | ||
13 | |||
14 | realize: => | ||
15 | current = @view.adapters[@root.interface].read @view.models, @root.path | ||
16 | |||
17 | for token, index in @tokens | ||
18 | next = @view.adapters[token.interface].read current, token.path | ||
19 | |||
20 | if @objectPath[index]? | ||
21 | if next isnt @objectPath[index] | ||
22 | @view.adapters[token.interface].unsubscribe current, token.path, @update | ||
23 | @view.adapters[token.interface].subscribe next, token.path, @update | ||
24 | else | ||
25 | @view.adapters[token.interface].subscribe current, token.path, @update | ||
26 | |||
27 | current = next | ||
28 | |||
29 | current |
-
Please register or sign in to post a comment