Files: 2ab2a391ff3ab284d348e34d95999560bad360fd / set.js
3438 bytesRaw
1 | var LazyWatcher = require('./lib/lazy-watcher') |
2 | |
3 | module.exports = Set |
4 | |
5 | function Set (defaultValues) { |
6 | var instance = new ProtoSet(defaultValues) |
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 |
19 | function ProtoSet (defaultValues) { |
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 (defaultValues && defaultValues.length) { |
28 | defaultValues.forEach(function (valueOrObs) { |
29 | if (!~self.sources.indexOf(valueOrObs)) { |
30 | self.sources.push(valueOrObs) |
31 | } |
32 | }) |
33 | this.update() |
34 | } |
35 | } |
36 | |
37 | ProtoSet.prototype.MutantSet = function (listener) { |
38 | if (!listener) { |
39 | return this.binder.getValue() |
40 | } |
41 | return this.binder.addListener(listener) |
42 | } |
43 | |
44 | ProtoSet.prototype.add = function (valueOrObs) { |
45 | if (!~this.sources.indexOf(valueOrObs)) { |
46 | this.sources.push(valueOrObs) |
47 | if (this.binder.live) { |
48 | this.releases[this.sources.length - 1] = this._bind(valueOrObs) |
49 | } |
50 | this.binder.onUpdate() |
51 | } |
52 | } |
53 | |
54 | ProtoSet.prototype.clear = function () { |
55 | this.releases.forEach(tryInvoke) |
56 | this.sources.length = 0 |
57 | this.releases.length = 0 |
58 | this.binder.onUpdate() |
59 | } |
60 | |
61 | ProtoSet.prototype.delete = function (valueOrObs) { |
62 | var index = this.sources.indexOf(valueOrObs) |
63 | if (~index) { |
64 | this.sources.splice(index, 1) |
65 | this.releases.splice(index, 1).forEach(tryInvoke) |
66 | this.binder.onUpdate() |
67 | } |
68 | } |
69 | |
70 | ProtoSet.prototype.has = function (valueOrObs) { |
71 | return !!~this.object.indexOf(valueOrObs) |
72 | } |
73 | |
74 | ProtoSet.prototype.set = function (values) { |
75 | var self = this |
76 | self.sources.length = 0 |
77 | values.forEach(function (value) { |
78 | self.sources.push(value) |
79 | }) |
80 | self.binder.onUpdate() |
81 | } |
82 | |
83 | ProtoSet.prototype.get = function (index) { |
84 | return this.sources[index] |
85 | } |
86 | |
87 | ProtoSet.prototype.getLength = function () { |
88 | return this.sources.length |
89 | } |
90 | |
91 | ProtoSet.prototype._bind = function (valueOrObs) { |
92 | return typeof valueOrObs === 'function' ? valueOrObs(this.binder.onUpdate) : null |
93 | } |
94 | |
95 | ProtoSet.prototype._listen = function () { |
96 | var self = this |
97 | self.sources.forEach(function (obs, i) { |
98 | self.releases[i] = self._bind(obs) |
99 | }) |
100 | } |
101 | |
102 | ProtoSet.prototype._unlisten = function () { |
103 | this.releases.forEach(tryInvoke) |
104 | this.releases.length = 0 |
105 | } |
106 | |
107 | ProtoSet.prototype._update = function () { |
108 | var currentValues = this.object.map(get) |
109 | var newValues = this.sources.map(resolve) |
110 | currentValues.filter(notIncluded, newValues).forEach(removeFrom, this.object) |
111 | newValues.filter(notIncluded, currentValues).forEach(addTo, this.object) |
112 | return true |
113 | } |
114 | |
115 | function get (value) { |
116 | return value |
117 | } |
118 | |
119 | function resolve (source) { |
120 | return typeof source === 'function' ? source() : source |
121 | } |
122 | |
123 | function notIncluded (value) { |
124 | return !~this.indexOf(value) |
125 | } |
126 | |
127 | function removeFrom (item) { |
128 | var index = this.indexOf(item) |
129 | if (~index) { |
130 | this.splice(index, 1) |
131 | } |
132 | } |
133 | |
134 | function addTo (item) { |
135 | this.push(item) |
136 | } |
137 | |
138 | function tryInvoke (func) { |
139 | if (typeof func === 'function') { |
140 | func() |
141 | } |
142 | } |
143 |
Built with git-ssb-web