git ssb

1+

Matt McKegg / mutant



Tree: ee6233e21fbc30daa9c23e3a3fdf43734c522096

Files: ee6233e21fbc30daa9c23e3a3fdf43734c522096 / dict.js

3916 bytesRaw
1var Value = require('./value')
2var LazyWatcher = require('./lib/lazy-watcher')
3var isSame = require('./lib/is-same')
4var resolve = require('./resolve')
5var isObservable = require('./is-observable')
6var forEachPair = require('./for-each-pair')
7var addLookupMethods = require('./lib/add-lookup-methods')
8
9module.exports = Dict
10
11function Dict (defaultValues, opts) {
12 var object = Object.create({})
13 var sources = {}
14 var releases = {}
15 var fixedIndexing = opts && opts.fixedIndexing || false
16
17 var comparer = opts && opts.comparer || null
18
19 var binder = LazyWatcher(update, listen, unlisten)
20 binder.value = object
21
22 if (opts && opts.nextTick) binder.nextTick = true
23 if (opts && opts.idle) binder.idle = true
24
25 if (defaultValues) {
26 forEachPair(defaultValues, put)
27 }
28
29 var observable = function MutantDictionary (listener) {
30 if (!listener) {
31 return binder.getValue()
32 }
33 return binder.addListener(listener)
34 }
35
36 addLookupMethods(observable, sources)
37
38 observable.put = function (key, valueOrObs) {
39 valueOrObs = getObsValue(valueOrObs)
40 put(key, valueOrObs)
41 binder.broadcast()
42 return valueOrObs
43 }
44
45 observable.clear = function () {
46 Object.keys(sources).forEach(function (key) {
47 tryInvoke(releases[key])
48 delete sources[key]
49 delete releases[key]
50 delete object[key]
51 })
52 binder.broadcast()
53 }
54
55 observable.delete = function (key) {
56 tryInvoke(releases[key])
57 delete sources[key]
58 delete releases[key]
59 delete object[key]
60 binder.broadcast()
61 }
62
63 observable.includes = function (valueOrObs) {
64 return !!~object.indexOf(valueOrObs)
65 }
66
67 observable.set = function (values) {
68 if (fixedIndexing) {
69 var keys = []
70
71 forEachPair(values, function (key, value) {
72 keys.push(key)
73 if (sources[key]) {
74 sources[key].set(value)
75 } else {
76 put(key, getObsValue(value))
77 }
78 })
79
80 Object.keys(sources).forEach(function (key) {
81 if (!keys.includes(key)) {
82 tryInvoke(releases[key])
83 delete sources[key]
84 delete releases[key]
85 delete object[key]
86 }
87 })
88 } else {
89 Object.keys(sources).forEach(function (key) {
90 tryInvoke(releases[key])
91 delete sources[key]
92 delete releases[key]
93 delete object[key]
94 })
95
96 forEachPair(values, put)
97 binder.broadcast()
98 }
99 }
100
101 return observable
102
103 // scoped
104
105 function getObsValue (valueOrObs) {
106 if (fixedIndexing && !isObservable(valueOrObs)) {
107 valueOrObs = Value(valueOrObs)
108 }
109 return valueOrObs
110 }
111
112 function put (key, valueOrObs) {
113 tryInvoke(releases[key])
114 sources[key] = valueOrObs
115 if (binder.live) {
116 releases[key] = bind(key, valueOrObs)
117 }
118 object[key] = resolve(valueOrObs)
119 }
120
121 function bind (key, valueOrObs) {
122 return typeof valueOrObs === 'function' ? valueOrObs(updateKey.bind(this, key)) : null
123 }
124
125 function updateKey (key, value) {
126 object[key] = value
127 binder.broadcast()
128 }
129
130 function listen () {
131 Object.keys(sources).forEach(function (key) {
132 releases[key] = bind(sources[key])
133 })
134
135 if (opts && opts.onListen) {
136 var release = opts.onListen()
137 if (typeof release === 'function') {
138 releases.push(release)
139 }
140 }
141 }
142
143 function unlisten () {
144 Object.keys(sources).forEach(function (key) {
145 tryInvoke(releases[key])
146 delete releases[key]
147 })
148
149 if (opts && opts.onUnlisten) {
150 opts.onUnlisten()
151 }
152 }
153
154 function update () {
155 var changed = false
156 Object.keys(sources).forEach(function (key) {
157 var newValue = resolve(sources[key])
158 if (!isSame(newValue, object[key], comparer)) {
159 object[key] = newValue
160 changed = true
161 }
162 })
163 return changed
164 }
165}
166
167function tryInvoke (func) {
168 if (typeof func === 'function') {
169 func()
170 }
171}
172

Built with git-ssb-web