Files: fa86f12bec35efbf6f363716b3919c8f36beb8ee / array.js
3190 bytesRaw
1 | var LazyWatcher = require('./lib/lazy-watcher') |
2 | var isReferenceType = require('./lib/is-reference-type') |
3 | var resolve = require('./resolve') |
4 | |
5 | module.exports = Array |
6 | |
7 | function Array (defaultValues) { |
8 | var object = [] |
9 | var sources = [] |
10 | var releases = [] |
11 | |
12 | var binder = LazyWatcher(update, listen, unlisten) |
13 | binder.value = object |
14 | |
15 | if (defaultValues && defaultValues.length) { |
16 | defaultValues.forEach(add) |
17 | } |
18 | |
19 | var observable = function MutantArray (listener) { |
20 | if (!listener) { |
21 | return binder.getValue() |
22 | } |
23 | return binder.addListener(listener) |
24 | } |
25 | |
26 | observable.push = function (args) { |
27 | for (var i = 0; i < arguments.length; i++) { |
28 | add(arguments[i]) |
29 | } |
30 | binder.broadcast() |
31 | } |
32 | |
33 | observable.insert = function (valueOrObs, at) { |
34 | sources.splice(at, 0, valueOrObs) |
35 | if (binder.live) releases.splice(at, 0, bind(valueOrObs)) |
36 | object.splice(at, 0, resolve(valueOrObs)) |
37 | binder.broadcast() |
38 | } |
39 | |
40 | observable.get = function (index) { |
41 | return sources[index] |
42 | } |
43 | |
44 | observable.getLength = function (index) { |
45 | return sources.length |
46 | } |
47 | |
48 | observable.includes = function (valueOrObs) { |
49 | return !!~sources.indexOf(valueOrObs) |
50 | } |
51 | |
52 | observable.indexOf = function (valueOrObs) { |
53 | return sources.indexOf(valueOrObs) |
54 | } |
55 | |
56 | observable.indexOf |
57 | |
58 | observable.pop = function () { |
59 | var result = sources.pop() |
60 | if (binder.live) tryInvoke(releases.pop()) |
61 | object.pop() |
62 | binder.broadcast() |
63 | return result |
64 | } |
65 | |
66 | observable.shift = function () { |
67 | var result = sources.shift() |
68 | if (binder.live) tryInvoke(releases.shift()) |
69 | object.shift() |
70 | binder.broadcast() |
71 | return result |
72 | } |
73 | |
74 | observable.clear = function () { |
75 | releases.forEach(tryInvoke) |
76 | sources.length = 0 |
77 | releases.length = 0 |
78 | object.length = 0 |
79 | binder.broadcast() |
80 | } |
81 | |
82 | observable.delete = function (valueOrObs) { |
83 | var index = sources.indexOf(valueOrObs) |
84 | if (~index) { |
85 | sources.splice(index, 1) |
86 | if (binder.live) releases.splice(index, 1).forEach(tryInvoke) |
87 | object.splice(index, 1) |
88 | binder.broadcast() |
89 | } |
90 | } |
91 | |
92 | observable.set = function (values) { |
93 | unlisten() |
94 | sources.length = 0 |
95 | releases.length = 0 |
96 | object.length = 0 |
97 | values.forEach(add) |
98 | if (binder.live) { |
99 | listen() |
100 | binder.broadcast() |
101 | } |
102 | } |
103 | |
104 | return observable |
105 | |
106 | // scoped |
107 | |
108 | function add (valueOrObs) { |
109 | sources.push(valueOrObs) |
110 | if (binder.live) { |
111 | releases.push(bind(valueOrObs)) |
112 | } |
113 | object.push(resolve(valueOrObs)) |
114 | } |
115 | |
116 | function bind (valueOrObs) { |
117 | return typeof valueOrObs === 'function' ? valueOrObs(binder.onUpdate) : null |
118 | } |
119 | |
120 | function listen () { |
121 | sources.forEach(function (obs, i) { |
122 | releases[i] = bind(obs) |
123 | }) |
124 | } |
125 | |
126 | function unlisten () { |
127 | releases.forEach(tryInvoke) |
128 | releases.length = 0 |
129 | } |
130 | |
131 | function update () { |
132 | var changed = false |
133 | sources.forEach(function (key, i) { |
134 | var newValue = resolve(observable[key]) |
135 | if (newValue !== object[i] || isReferenceType(newValue)) { |
136 | object[i] = newValue |
137 | changed = true |
138 | } |
139 | }) |
140 | return changed |
141 | } |
142 | } |
143 | |
144 | function tryInvoke (func) { |
145 | if (typeof func === 'function') { |
146 | func() |
147 | } |
148 | } |
149 |
Built with git-ssb-web