git ssb

1+

Matt McKegg / mutant



Tree: 3d65e26e909eda26a2ae0fd4157022512389dc58

Files: 3d65e26e909eda26a2ae0fd4157022512389dc58 / dict.js

3738 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')
6
7// TODO: reimplement using LazyWatcher
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 (defaultValues) {
23 Object.keys(defaultValues).forEach(function (key) {
24 put(key, defaultValues[key])
25 })
26 }
27
28 var observable = function MutantDictionary (listener) {
29 if (!listener) {
30 return binder.getValue()
31 }
32 return binder.addListener(listener)
33 }
34
35 observable.put = function (key, valueOrObs) {
36 valueOrObs = getObsValue(valueOrObs)
37 put(key, valueOrObs)
38 binder.broadcast()
39 return valueOrObs
40 }
41
42 observable.get = function (key) {
43 return sources[key]
44 }
45
46 observable.keys = function () {
47 return Object.keys(sources)
48 }
49
50 observable.clear = function () {
51 Object.keys(sources).forEach(function (key) {
52 tryInvoke(releases[key])
53 delete sources[key]
54 delete releases[key]
55 delete object[key]
56 })
57 binder.broadcast()
58 }
59
60 observable.delete = function (key) {
61 tryInvoke(releases[key])
62 delete sources[key]
63 delete releases[key]
64 delete object[key]
65 binder.broadcast()
66 }
67
68 observable.includes = function (valueOrObs) {
69 return !!~object.indexOf(valueOrObs)
70 }
71
72 observable.set = function (values) {
73 var keys = values && Object.keys(values) || []
74 if (fixedIndexing) {
75 keys.forEach(function (key) {
76 if (sources[key]) {
77 sources[key].set(values[key])
78 } else {
79 put(key, getObsValue(values[key]))
80 }
81 })
82
83 Object.keys(sources).forEach(function (key) {
84 if (!keys.includes(key)) {
85 tryInvoke(releases[key])
86 delete sources[key]
87 delete releases[key]
88 delete object[key]
89 }
90 })
91 } else {
92 Object.keys(sources).forEach(function (key) {
93 tryInvoke(releases[key])
94 delete sources[key]
95 delete releases[key]
96 delete object[key]
97 })
98
99 keys.forEach(function (key) {
100 put(key, values[key])
101 })
102
103 binder.broadcast()
104 }
105 }
106
107 return observable
108
109 // scoped
110
111 function getObsValue (valueOrObs) {
112 if (fixedIndexing && !isObservable(valueOrObs)) {
113 valueOrObs = Value(valueOrObs)
114 }
115 return valueOrObs
116 }
117
118 function put (key, valueOrObs) {
119 tryInvoke(releases[key])
120 sources[key] = valueOrObs
121 if (binder.live) {
122 releases[key] = bind(key, valueOrObs)
123 }
124 object[key] = resolve(valueOrObs)
125 }
126
127 function bind (key, valueOrObs) {
128 return typeof valueOrObs === 'function' ? valueOrObs(updateKey.bind(this, key)) : null
129 }
130
131 function updateKey (key, value) {
132 object[key] = value
133 binder.broadcast()
134 }
135
136 function listen () {
137 Object.keys(sources).forEach(function (key) {
138 releases[key] = bind(sources[key])
139 })
140 }
141
142 function unlisten () {
143 Object.keys(sources).forEach(function (key) {
144 tryInvoke(releases[key])
145 delete releases[key]
146 })
147 }
148
149 function update () {
150 var changed = false
151 Object.keys(sources).forEach(function (key) {
152 var newValue = resolve(sources[key])
153 if (!isSame(newValue, object[key], comparer)) {
154 object[key] = newValue
155 changed = true
156 }
157 })
158 return changed
159 }
160}
161
162function tryInvoke (func) {
163 if (typeof func === 'function') {
164 func()
165 }
166}
167

Built with git-ssb-web