git ssb

1+

Matt McKegg / mutant



Tree: a86cbf4be984227b8ca313252ed4b61f4e66eb04

Files: a86cbf4be984227b8ca313252ed4b61f4e66eb04 / struct.js

2430 bytesRaw
1var Value = require('./value')
2var LazyWatcher = require('./lib/lazy-watcher')
3var isSame = require('./lib/is-same')
4
5module.exports = Struct
6
7var blackList = {
8 'length': 'Clashes with `Function.prototype.length`.\n',
9 'name': 'Clashes with `Function.prototype.name`\n',
10 'destroy': '`destroy` is a reserved key of struct\n'
11}
12
13function Struct (properties, opts) {
14 var object = Object.create({})
15 var releases = []
16 var binder = LazyWatcher(update, listen, unlisten)
17 binder.value = object
18
19 var comparer = opts && opts.comparer || null
20
21 var observable = function MutantStruct (listener) {
22 if (!listener) {
23 return binder.getValue()
24 }
25 return binder.addListener(listener)
26 }
27
28 var keys = Object.keys(properties)
29 var suspendBroadcast = false
30
31 keys.forEach(function (key) {
32 if (blackList.hasOwnProperty(key)) {
33 throw new Error("Cannot create a struct with a key named '" + key + "'.\n" + blackList[key])
34 }
35
36 var obs = typeof properties[key] === 'function'
37 ? properties[key]
38 : Value(properties[key])
39
40 object[key] = obs()
41 observable[key] = obs
42 })
43
44 observable.set = function (values) {
45 var lastValue = suspendBroadcast
46 suspendBroadcast = true
47 values = values || {}
48
49 // update inner observables
50 keys.forEach(function (key) {
51 if (observable[key]() !== values[key]) {
52 observable[key].set(values[key])
53 }
54 })
55
56 // store additional keys (but don't create observables)
57 Object.keys(values).forEach(function (key) {
58 if (!(key in properties)) {
59 object[key] = values[key]
60 }
61 })
62
63 suspendBroadcast = lastValue
64 if (!suspendBroadcast) {
65 binder.broadcast()
66 }
67 }
68
69 return observable
70
71 // scoped
72
73 function listen () {
74 keys.map(function (key) {
75 var obs = observable[key]
76 releases.push(obs(function (val) {
77 if (!isSame(val, object[key], comparer)) {
78 object[key] = val
79 if (!suspendBroadcast) {
80 binder.broadcast(object)
81 }
82 }
83 }))
84 })
85 }
86
87 function unlisten () {
88 while (releases.length) {
89 releases.pop()()
90 }
91 }
92
93 function update () {
94 var changed = false
95 keys.forEach(function (key) {
96 var newValue = observable[key]()
97 if (!isSame(newValue, object[key], comparer)) {
98 object[key] = observable[key]()
99 changed = true
100 }
101 })
102 return changed
103 }
104}
105

Built with git-ssb-web