|
13 | 13 | // limitations under the License.
|
14 | 14 |
|
15 | 15 | function ArrayReduction(array, path, reduceFn, initial) {
|
16 |
| - var values = []; |
17 |
| - var observers = []; |
18 |
| - var self = this; |
19 |
| - var hasInitial = arguments.length == 4; |
20 |
| - |
21 |
| - function reduce() { |
22 |
| - self.value = hasInitial ? |
23 |
| - values.reduce(reduceFn, initial) : values.reduce(reduceFn); |
24 |
| - } |
25 |
| - |
26 |
| - function newCallback(index) { |
27 |
| - return function(value) { |
28 |
| - values[index] = value; |
29 |
| - reduce(); |
30 |
| - } |
31 |
| - } |
32 |
| - |
33 |
| - function handleSplice(splice) { |
34 |
| - var valueArgs = [splice.index, splice.removed.length]; |
35 |
| - var observerArgs = [splice.index, splice.removed.length]; |
| 16 | + this.array = array; |
| 17 | + this.path = path ? path.trim() : undefined; |
| 18 | + this.reduceFn = reduceFn; |
| 19 | + this.initial = initial; |
| 20 | + this.arrayObserver = new ArrayObserver(array, this.handleSplices, this); |
| 21 | + this.observers = this.path ? [] : undefined; |
| 22 | + |
| 23 | + this.handleSplices([{ |
| 24 | + index: 0, |
| 25 | + removed: [], |
| 26 | + addedCount: array.length |
| 27 | + }]); |
| 28 | +} |
36 | 29 |
|
37 |
| - var removeIndex = splice.index; |
38 |
| - while (removeIndex < splice.index + splice.removed.length) { |
39 |
| - observers[removeIndex].close(); |
40 |
| - observers[removeIndex] = undefined; |
41 |
| - removeIndex++; |
42 |
| - } |
| 30 | +ArrayReduction.prototype = { |
| 31 | + updateObservers: function(splices) { |
| 32 | + for (var i = 0; i < splices.length; i++) { |
| 33 | + var splice = splices[i]; |
| 34 | + var added = []; |
| 35 | + for (var j = 0; j < splice.addedCount; j++) { |
| 36 | + added.push(new PathObserver(this.array[splice.index + j], this.path, |
| 37 | + this.reduce, this)); |
| 38 | + } |
43 | 39 |
|
44 |
| - var addIndex = splice.index; |
45 |
| - while (addIndex < splice.index + splice.addedCount) { |
46 |
| - var itemPath = String(addIndex); |
47 |
| - if (path) |
48 |
| - itemPath += '.' + path; |
| 40 | + var spliceArgs = [splice.index, splice.removed.length].concat(added); |
| 41 | + var removed = Array.prototype.splice.apply(this.observers, spliceArgs); |
49 | 42 |
|
50 |
| - valueArgs.push(PathObserver.getValueAtPath(array, itemPath)); |
51 |
| - observerArgs.push(new PathObserver(array, itemPath, newCallback(addIndex))); |
52 |
| - addIndex++; |
| 43 | + for (var j = 0; j < removed.length; j++) { |
| 44 | + removed[j].close(); |
| 45 | + } |
53 | 46 | }
|
| 47 | + }, |
54 | 48 |
|
55 |
| - Array.prototype.splice.apply(values, valueArgs); |
56 |
| - Array.prototype.splice.apply(observers, observerArgs); |
57 |
| - |
58 |
| - // Correct the index/path being watched by the observers that watched indices |
59 |
| - // after the splice. |
60 |
| - var curIndex = splice.index + splice.addedCount; |
61 |
| - while(curIndex < values.length) { |
62 |
| - var expectedItemPath = (path ? (curIndex + '.' + path) : String(curIndex)); |
63 |
| - |
64 |
| - observers[curIndex].close(); |
65 |
| - observers[curIndex] = new PathObserver(array, expectedItemPath, newCallback(curIndex)); |
66 |
| - curIndex++; |
67 |
| - } |
68 |
| - } |
| 49 | + handleSplices: function(splices) { |
| 50 | + if (this.observers) |
| 51 | + this.updateObservers(splices); |
69 | 52 |
|
70 |
| - var arrayObserver = new ArrayObserver(array, function(splices) { |
71 |
| - splices.forEach(handleSplice); |
72 |
| - reduce(); |
73 |
| - }); |
| 53 | + this.reduce(); |
| 54 | + }, |
74 | 55 |
|
75 |
| - handleSplice({ |
76 |
| - index: 0, |
77 |
| - removed: [], |
78 |
| - addedCount: array.length |
79 |
| - }); |
| 56 | + reduce: function() { |
| 57 | + this.value = this.array.reduce(this.reduceFn, this.initial); |
| 58 | + }, |
80 | 59 |
|
81 |
| - this.close = function() { |
82 |
| - observers.forEach(function(observer) { |
| 60 | + close: function() { |
| 61 | + this.observers.forEach(function(observer) { |
83 | 62 | observer.close();
|
84 | 63 | });
|
85 |
| - arrayObserver.close(); |
86 |
| - }; |
87 |
| - |
88 |
| - this.unobserved = function() { |
89 |
| - self.close(); |
90 |
| - }; |
| 64 | + this.arrayObserver.close(); |
| 65 | + }, |
91 | 66 |
|
92 |
| - this.deliver = function() { |
93 |
| - arrayObserver.deliver(); |
94 |
| - observers.forEach(function(observer) { |
| 67 | + deliver: function() { |
| 68 | + this.arrayObserver.deliver(); |
| 69 | + this.observers.forEach(function(observer) { |
95 | 70 | observer.deliver();
|
96 | 71 | });
|
97 | 72 | }
|
98 |
| - |
99 |
| - reduce(); |
100 | 73 | }
|
101 | 74 |
|
102 | 75 | ArrayReduction.defineProperty = function(object, name, descriptor) {
|
103 |
| - var observer; |
104 |
| - if (descriptor.hasOwnProperty('initial')) |
105 |
| - observer = new ArrayReduction(descriptor.array, descriptor.path, descriptor.reduce, descriptor.initial); |
106 |
| - else |
107 |
| - observer = new ArrayReduction(descriptor.array, descriptor.path, descriptor.reduce); |
| 76 | + var observer = new ArrayReduction(descriptor.array, descriptor.path, |
| 77 | + descriptor.reduce, |
| 78 | + descriptor.initial); |
108 | 79 |
|
109 | 80 | Object.defineProperty(object, name, {
|
110 | 81 | get: function() {
|
|
0 commit comments