git ssb

1+

Matt McKegg / mutant



Tree: d21f00b20866259a0cc392aac18a581d68aa23be

Files: d21f00b20866259a0cc392aac18a581d68aa23be / set.js

4134 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.transaction = instance.transaction.bind(instance)
15 observable.getLength = instance.getLength.bind(instance)
16 return observable
17}
18
19// optimise memory usage
20function ProtoSet (defaultValues, opts) {
21 var self = this
22 self.object = []
23 self.sources = []
24 self.releases = []
25 self.binder = LazyWatcher.call(self, self._update, self._listen, self._unlisten)
26 self.binder.value = this.object
27
28 if (opts && opts.nextTick) self.binder.nextTick = true
29 if (opts && opts.idle) self.binder.idle = true
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.transaction = function (fn) {
120 this.binder.transaction(this, fn)
121}
122
123ProtoSet.prototype._listen = function () {
124 var self = this
125 self.sources.forEach(function (obs, i) {
126 self.releases[i] = self._bind(obs)
127 })
128}
129
130ProtoSet.prototype._unlisten = function () {
131 this.releases.forEach(tryInvoke)
132 this.releases.length = 0
133}
134
135ProtoSet.prototype._update = function () {
136 var currentValues = this.object.map(get)
137 var newValues = this.sources.map(resolve)
138 currentValues.filter(notIncluded, newValues).forEach(removeFrom, this.object)
139 newValues.filter(notIncluded, currentValues).forEach(addTo, this.object)
140 return true
141}
142
143function get (value) {
144 return value
145}
146
147function resolve (source) {
148 return typeof source === 'function' ? source() : source
149}
150
151function notIncluded (value) {
152 return !~this.indexOf(value)
153}
154
155function removeFrom (item) {
156 var index = this.indexOf(item)
157 if (~index) {
158 this.splice(index, 1)
159 }
160}
161
162function addTo (item) {
163 this.push(item)
164}
165
166function tryInvoke (func) {
167 if (typeof func === 'function') {
168 func()
169 }
170}
171

Built with git-ssb-web