git ssb

1+

Matt McKegg / mutant



Tree: 9ddfe1a36b770dd913a4f5649543b64785ffd4cc

Files: 9ddfe1a36b770dd913a4f5649543b64785ffd4cc / struct.js

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

Built with git-ssb-web