git ssb

1+

Matt McKegg / mutant



Tree: e9d4ab45391a98cd08092fe447f7cd7c3732779b

Files: e9d4ab45391a98cd08092fe447f7cd7c3732779b / struct.js

2631 bytesRaw
1var Value = require('./value')
2var LazyWatcher = require('./lib/lazy-watcher')
3var isSame = require('./lib/is-same')
4var extend = require('xtend')
5
6module.exports = Struct
7
8var blackList = {
9 'length': 'Clashes with `Function.prototype.length`.\n',
10 'name': 'Clashes with `Function.prototype.name`\n',
11 'set': '`set` is a reserved key of struct\n'
12}
13
14function Struct (properties, opts) {
15 var object = Object.create({})
16 var releases = []
17 var binder = LazyWatcher(update, listen, unlisten)
18 binder.value = object
19
20 if (opts && opts.nextTick) binder.nextTick = true
21 if (opts && opts.idle) binder.idle = true
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, opts) {
49 var lastValue = suspendBroadcast
50
51 suspendBroadcast = true
52 values = values || {}
53
54 if (opts && opts.merge) {
55 values = extend(object, values)
56 }
57
58 // update inner observables
59 keys.forEach(function (key) {
60 if (observable[key]() !== values[key]) {
61 observable[key].set(values[key])
62 }
63 })
64
65 // store additional keys (but don't create observables)
66 Object.keys(values).forEach(function (key) {
67 if (!(key in properties)) {
68 object[key] = values[key]
69 }
70 })
71
72 suspendBroadcast = lastValue
73 if (!suspendBroadcast) {
74 binder.broadcast()
75 }
76 }
77
78 return observable
79
80 // scoped
81
82 function listen () {
83 keys.map(function (key) {
84 var obs = observable[key]
85 releases.push(obs(function (val) {
86 if (!isSame(val, object[key], comparer)) {
87 object[key] = val
88 if (!suspendBroadcast) {
89 binder.broadcast(object)
90 }
91 }
92 }))
93 })
94 }
95
96 function unlisten () {
97 while (releases.length) {
98 releases.pop()()
99 }
100 }
101
102 function update () {
103 var changed = false
104 keys.forEach(function (key) {
105 var newValue = observable[key]()
106 if (!isSame(newValue, object[key], comparer)) {
107 object[key] = observable[key]()
108 changed = true
109 }
110 })
111 return changed
112 }
113}
114

Built with git-ssb-web