Implement basic array mutation observing in the default adapter.
Showing
1 changed file
with
48 additions
and
14 deletions
... | @@ -6,22 +6,53 @@ Rivets.adapters['.'] = | ... | @@ -6,22 +6,53 @@ Rivets.adapters['.'] = |
6 | counter: 0 | 6 | counter: 0 |
7 | weakmap: {} | 7 | weakmap: {} |
8 | 8 | ||
9 | subscribe: (obj, keypath, callback) -> | 9 | weakReference: (obj) -> |
10 | unless obj[@id]? | 10 | unless obj[@id]? |
11 | id = @counter++ | 11 | id = @counter++ |
12 | 12 | ||
13 | Object.defineProperty obj, @id, | 13 | @weakmap[id] = |
14 | enumerable: false | 14 | callbacks: {} |
15 | configurable: false | 15 | |
16 | writable: false | 16 | Object.defineProperty obj, @id, value: id |
17 | value: id | 17 | |
18 | @weakmap[obj[@id]] | ||
19 | |||
20 | stubFunction: (obj, fn) -> | ||
21 | original = obj[fn] | ||
22 | map = @weakReference obj | ||
23 | weakmap = @weakmap | ||
24 | |||
25 | obj[fn] = -> | ||
26 | response = original.apply obj, arguments | ||
27 | |||
28 | for r, k of map.pointers | ||
29 | callback() for callback in weakmap[r]?.callbacks[k] ? [] | ||
30 | |||
31 | response | ||
18 | 32 | ||
19 | @weakmap[id] = {} | 33 | observeMutations: (obj, ref, keypath) -> |
34 | if Object.prototype.toString.call(obj) is '[object Array]' | ||
35 | map = @weakReference obj | ||
20 | 36 | ||
21 | map = @weakmap[obj[@id]] | 37 | unless map.pointers? |
38 | map.pointers = {} | ||
39 | functions = ['push', 'pop', 'shift', 'unshift', 'sort', 'reverse', 'splice'] | ||
40 | @stubFunction obj, fn for fn in functions | ||
22 | 41 | ||
23 | unless map[keypath]? | 42 | map.pointers[ref] ?= [] |
24 | map[keypath] = [] | 43 | |
44 | unless keypath in map.pointers[ref] | ||
45 | map.pointers[ref].push keypath | ||
46 | |||
47 | unobserveMutations: (obj, ref, keypath) -> | ||
48 | if keyapths = @weakReference(obj).pointers?[ref] | ||
49 | keypaths.splice keypaths.indexOf(keypath), 1 | ||
50 | |||
51 | subscribe: (obj, keypath, callback) -> | ||
52 | callbacks = @weakReference(obj).callbacks | ||
53 | |||
54 | unless callbacks[keypath]? | ||
55 | callbacks[keypath] = [] | ||
25 | value = obj[keypath] | 56 | value = obj[keypath] |
26 | 57 | ||
27 | Object.defineProperty obj, keypath, | 58 | Object.defineProperty obj, keypath, |
... | @@ -29,14 +60,17 @@ Rivets.adapters['.'] = | ... | @@ -29,14 +60,17 @@ Rivets.adapters['.'] = |
29 | set: (newValue) -> | 60 | set: (newValue) -> |
30 | if newValue isnt value | 61 | if newValue isnt value |
31 | value = newValue | 62 | value = newValue |
32 | callback() for callback in map[keypath] | 63 | callback() for callback in callbacks[keypath] |
64 | |||
65 | unless callback in callbacks[keypath] | ||
66 | callbacks[keypath].push callback | ||
33 | 67 | ||
34 | unless callback in map[keypath] | 68 | @observeMutations obj[keypath], obj[@id], keypath |
35 | map[keypath].push callback | ||
36 | 69 | ||
37 | unsubscribe: (obj, keypath, callback) -> | 70 | unsubscribe: (obj, keypath, callback) -> |
38 | callbacks = @weakmap[obj[@id]][keypath] | 71 | callbacks = @weakmap[obj[@id]].callbacks[keypath] |
39 | callbacks.splice callbacks.indexOf(callback), 1 | 72 | callbacks.splice callbacks.indexOf(callback), 1 |
73 | @observeMutations obj[keypath], obj[@id], keypath | ||
40 | 74 | ||
41 | read: (obj, keypath) -> | 75 | read: (obj, keypath) -> |
42 | obj[keypath] | 76 | obj[keypath] | ... | ... |
-
Please register or sign in to post a comment