git ssb

1+

Matt McKegg / mutant



Tree: f69a37d1862b7bc2b9590d1514f049129243de67

Files: f69a37d1862b7bc2b9590d1514f049129243de67 / array.js

3353 bytesRaw
1var LazyWatcher = require('./lib/lazy-watcher')
2var isReferenceType = require('./lib/is-reference-type')
3var resolve = require('./resolve')
4
5module.exports = Array
6
7function 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.forEach = function (fn, context) {
57 sources.slice().forEach(fn, context)
58 }
59
60 observable.find = function (fn) {
61 return sources.find(fn)
62 }
63
64 observable.indexOf
65
66 observable.pop = function () {
67 var result = sources.pop()
68 if (binder.live) tryInvoke(releases.pop())
69 object.pop()
70 binder.broadcast()
71 return result
72 }
73
74 observable.shift = function () {
75 var result = sources.shift()
76 if (binder.live) tryInvoke(releases.shift())
77 object.shift()
78 binder.broadcast()
79 return result
80 }
81
82 observable.clear = function () {
83 releases.forEach(tryInvoke)
84 sources.length = 0
85 releases.length = 0
86 object.length = 0
87 binder.broadcast()
88 }
89
90 observable.delete = function (valueOrObs) {
91 var index = sources.indexOf(valueOrObs)
92 if (~index) {
93 sources.splice(index, 1)
94 if (binder.live) releases.splice(index, 1).forEach(tryInvoke)
95 object.splice(index, 1)
96 binder.broadcast()
97 }
98 }
99
100 observable.set = function (values) {
101 unlisten()
102 sources.length = 0
103 releases.length = 0
104 object.length = 0
105 values.forEach(add)
106 if (binder.live) {
107 listen()
108 binder.broadcast()
109 }
110 }
111
112 return observable
113
114 // scoped
115
116 function add (valueOrObs) {
117 sources.push(valueOrObs)
118 if (binder.live) {
119 releases.push(bind(valueOrObs))
120 }
121 object.push(resolve(valueOrObs))
122 }
123
124 function bind (valueOrObs) {
125 return typeof valueOrObs === 'function' ? valueOrObs(binder.onUpdate) : null
126 }
127
128 function listen () {
129 sources.forEach(function (obs, i) {
130 releases[i] = bind(obs)
131 })
132 }
133
134 function unlisten () {
135 releases.forEach(tryInvoke)
136 releases.length = 0
137 }
138
139 function update () {
140 var changed = false
141 sources.forEach(function (key, i) {
142 var newValue = resolve(observable[key])
143 if (newValue !== object[i] || isReferenceType(newValue)) {
144 object[i] = newValue
145 changed = true
146 }
147 })
148 return changed
149 }
150}
151
152function tryInvoke (func) {
153 if (typeof func === 'function') {
154 func()
155 }
156}
157

Built with git-ssb-web