git ssb

1+

Matt McKegg / mutant



Tree: 073f2ca837054c3b04113dd573e1a9e8b0c6ed29

Files: 073f2ca837054c3b04113dd573e1a9e8b0c6ed29 / dict.js

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

Built with git-ssb-web