git ssb

1+

Matt McKegg / mutant



Tree: bc685ac97855accf26bcdf7168da942ffcdccd1a

Files: bc685ac97855accf26bcdf7168da942ffcdccd1a / struct.js

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

Built with git-ssb-web