git ssb

1+

Matt McKegg / mutant



Tree: 073f2ca837054c3b04113dd573e1a9e8b0c6ed29

Files: 073f2ca837054c3b04113dd573e1a9e8b0c6ed29 / set.js

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

Built with git-ssb-web