Make the keypath observer handle the full spectrum of the keypath and unresolvab…
…le targets without error. [#233]
Showing
1 changed file
with
43 additions
and
15 deletions
1 | # Rivets.KeypathObserver | 1 | # Rivets.Observer |
2 | # ---------------------- | 2 | # ---------------------- |
3 | 3 | ||
4 | # Parses and observes a full keypath with the appropriate adapters. Also | 4 | # Parses and observes a full keypath with the appropriate adapters. Also |
5 | # intelligently re-realizes the keypath when intermediary keys change. | 5 | # intelligently re-realizes the keypath when intermediary keys change. |
6 | class Rivets.KeypathObserver | 6 | class Rivets.Observer |
7 | # Performs the initial parse, variable instantiation and keypath realization. | 7 | # Performs the initial parse, variable instantiation and keypath realization. |
8 | constructor: (@view, @model, @keypath, @callback) -> | 8 | constructor: (@view, @model, @keypath, @callback) -> |
9 | @parse() | 9 | @parse() |
10 | @objectPath = [] | 10 | @initialize() |
11 | @target = @realize() | ||
12 | 11 | ||
13 | # Parses the keypath using the interfaces defined on the view. Sets variables | 12 | # Parses the keypath using the interfaces defined on the view. Sets variables |
14 | # for the tokenized keypath, as well as the end key. | 13 | # for the tokenized keypath, as well as the end key. |
... | @@ -25,34 +24,63 @@ class Rivets.KeypathObserver | ... | @@ -25,34 +24,63 @@ class Rivets.KeypathObserver |
25 | @tokens = Rivets.KeypathParser.parse path, interfaces, root | 24 | @tokens = Rivets.KeypathParser.parse path, interfaces, root |
26 | @key = @tokens.pop() | 25 | @key = @tokens.pop() |
27 | 26 | ||
28 | # Updates the keypath. This is called when any intermediate key is changed. | 27 | initialize: => |
28 | @objectPath = [] | ||
29 | @target = @realize() | ||
30 | @set true, @key, @target, @callback if @target? | ||
31 | |||
32 | # Updates the keypath. This is called when any intermediary key is changed. | ||
29 | update: => | 33 | update: => |
30 | unless (next = @realize()) is @target | 34 | unless (next = @realize()) is @target |
31 | prev = @target | 35 | @set false, @key, @target, @callback if @target? |
36 | @set true, @key, next, @callback if next? | ||
37 | |||
38 | oldValue = @value() | ||
32 | @target = next | 39 | @target = next |
33 | @callback @, prev | 40 | @callback() unless @value() is oldValue |
41 | |||
42 | adapter: (key) => | ||
43 | @view.adapters[key.interface] | ||
44 | |||
45 | set: (active, key, obj, callback) => | ||
46 | action = if active then 'subscribe' else 'unsubscribe' | ||
47 | @adapter(key)[action] obj, key.path, callback | ||
48 | |||
49 | read: (key, obj) => | ||
50 | @adapter(key).read obj, key.path | ||
51 | |||
52 | value: => | ||
53 | @read @key, @target if @target? | ||
34 | 54 | ||
35 | # Realizes the full keypath, attaching observers for every key and correcting | 55 | # Realizes the full keypath, attaching observers for every key and correcting |
36 | # old observers to any changed objects in the keypath. | 56 | # old observers to any changed objects in the keypath. |
37 | realize: => | 57 | realize: => |
38 | current = @model | 58 | current = @model |
59 | unreached = null | ||
39 | 60 | ||
40 | for token, index in @tokens | 61 | for token, index in @tokens |
41 | if @objectPath[index]? | 62 | if current? |
42 | if current isnt prev = @objectPath[index] | 63 | if @objectPath[index]? |
43 | @view.adapters[token.interface].unsubscribe prev, token.path, @update | 64 | if current isnt prev = @objectPath[index] |
44 | @view.adapters[token.interface].subscribe current, token.path, @update | 65 | @set false, token, prev, @update |
66 | @set true, token, current, @update | ||
67 | @objectPath[index] = current | ||
68 | else | ||
69 | @set true, token, current, @update | ||
45 | @objectPath[index] = current | 70 | @objectPath[index] = current |
71 | |||
72 | current = @read token, current | ||
46 | else | 73 | else |
47 | @view.adapters[token.interface].subscribe current, token.path, @update | 74 | unreached ?= index |
48 | @objectPath[index] = current | ||
49 | 75 | ||
50 | current = @view.adapters[token.interface].read current, token.path | 76 | if prev = @objectPath[index] |
77 | @set false, token, prev, @update | ||
51 | 78 | ||
79 | @objectPath.splice unreached if unreached? | ||
52 | current | 80 | current |
53 | 81 | ||
54 | # Unobserves any current observers set up on the keys. | 82 | # Unobserves any current observers set up on the keys. |
55 | unobserve: => | 83 | unobserve: => |
56 | for token, index in @tokens | 84 | for token, index in @tokens |
57 | if obj = @objectPath[index] | 85 | if obj = @objectPath[index] |
58 | @view.adapters[token.interface].unsubscribe obj, token.path, @update | 86 | @set false, token, obj, @update | ... | ... |
-
Please register or sign in to post a comment