git ssb

1+

Matt McKegg / mutant



Tree: a86cbf4be984227b8ca313252ed4b61f4e66eb04

Files: a86cbf4be984227b8ca313252ed4b61f4e66eb04 / dict.js

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

Built with git-ssb-web