git ssb

1+

Matt McKegg / mutant



Tree: 4f9e58ce423d145b70980a342e93dbbffbbc95f6

Files: 4f9e58ce423d145b70980a342e93dbbffbbc95f6 / set.js

3983 bytesRaw
1var LazyWatcher = require('./lib/lazy-watcher')
2
3module.exports = Set
4
5function Set (defaultValues, opts) {
6 var instance = new ProtoSet(defaultValues, opts)
7 var observable = instance.MutantSet.bind(instance)
8 observable.add = instance.add.bind(instance)
9 observable.clear = instance.clear.bind(instance)
10 observable.delete = instance.delete.bind(instance)
11 observable.has = instance.has.bind(instance)
12 observable.set = instance.set.bind(instance)
13 observable.get = instance.get.bind(instance)
14 observable.getLength = instance.getLength.bind(instance)
15 return observable
16}
17
18// optimise memory usage
19function ProtoSet (defaultValues, opts) {
20 var self = this
21 self.object = []
22 self.sources = []
23 self.releases = []
24 self.binder = LazyWatcher.call(self, self._update, self._listen, self._unlisten)
25 self.binder.value = this.object
26
27 if (opts && opts.nextTick) self.binder.nextTick = true
28 if (opts && opts.idle) self.binder.idle = true
29
30 if (defaultValues && defaultValues.length) {
31 defaultValues.forEach(function (valueOrObs) {
32 if (!~self.sources.indexOf(valueOrObs)) {
33 self.sources.push(valueOrObs)
34 }
35 })
36 this._update()
37 }
38}
39
40ProtoSet.prototype.MutantSet = function (listener) {
41 if (!listener) {
42 return this.binder.getValue()
43 }
44 return this.binder.addListener(listener)
45}
46
47ProtoSet.prototype.add = function (valueOrObs) {
48 if (!~this.sources.indexOf(valueOrObs)) {
49 this.sources.push(valueOrObs)
50 if (this.binder.live) {
51 this.releases[this.sources.length - 1] = this._bind(valueOrObs)
52 }
53 this.binder.onUpdate()
54 }
55}
56
57ProtoSet.prototype.clear = function () {
58 this.releases.forEach(tryInvoke)
59 this.sources.length = 0
60 this.releases.length = 0
61 this.binder.onUpdate()
62}
63
64ProtoSet.prototype.delete = function (valueOrObs) {
65 var index = this.sources.indexOf(valueOrObs)
66 if (~index) {
67 this.sources.splice(index, 1)
68 this.releases.splice(index, 1).forEach(tryInvoke)
69 this.binder.onUpdate()
70 }
71}
72
73ProtoSet.prototype.has = function (valueOrObs) {
74 return !!~this.object.indexOf(valueOrObs)
75}
76
77ProtoSet.prototype.set = function (values) {
78 var self = this
79 var changed = false
80
81 if (Array.isArray(values)) {
82 for (var i = this.sources.length - 1; i >= 0; i -= 1) {
83 if (!~values.indexOf(this.sources[i])) {
84 changed = true
85 self.sources.splice(i, 1)
86 }
87 }
88 values.forEach(function (value) {
89 if (!~self.sources.indexOf(value)) {
90 changed = true
91 self.sources.push(value)
92 }
93 })
94 } else {
95 if (self.sources.length > 0) {
96 self.sources.length = 0
97 changed = true
98 }
99 }
100
101 if (changed) {
102 self.binder.onUpdate()
103 }
104}
105
106ProtoSet.prototype.get = function (index) {
107 return this.sources[index]
108}
109
110ProtoSet.prototype.getLength = function () {
111 return this.sources.length
112}
113
114ProtoSet.prototype._bind = function (valueOrObs) {
115 return typeof valueOrObs === 'function' ? valueOrObs(this.binder.onUpdate) : null
116}
117
118ProtoSet.prototype._listen = function () {
119 var self = this
120 self.sources.forEach(function (obs, i) {
121 self.releases[i] = self._bind(obs)
122 })
123}
124
125ProtoSet.prototype._unlisten = function () {
126 this.releases.forEach(tryInvoke)
127 this.releases.length = 0
128}
129
130ProtoSet.prototype._update = function () {
131 var currentValues = this.object.map(get)
132 var newValues = this.sources.map(resolve)
133 currentValues.filter(notIncluded, newValues).forEach(removeFrom, this.object)
134 newValues.filter(notIncluded, currentValues).forEach(addTo, this.object)
135 return true
136}
137
138function get (value) {
139 return value
140}
141
142function resolve (source) {
143 return typeof source === 'function' ? source() : source
144}
145
146function notIncluded (value) {
147 return !~this.indexOf(value)
148}
149
150function removeFrom (item) {
151 var index = this.indexOf(item)
152 if (~index) {
153 this.splice(index, 1)
154 }
155}
156
157function addTo (item) {
158 this.push(item)
159}
160
161function tryInvoke (func) {
162 if (typeof func === 'function') {
163 func()
164 }
165}
166

Built with git-ssb-web