UNPKG

7.39 kBJavaScriptView Raw
1
2var Gun = require('./root');
3Gun.chain.chain = function(){
4 var at = this._, chain = new this.constructor(this), cat = chain._;
5 cat.root = root = at.root;
6 cat.id = ++root._.once;
7 cat.back = this;
8 cat.on = Gun.on;
9 Gun.on('chain', cat);
10 cat.on('in', input, cat); // For 'in' if I add my own listeners to each then I MUST do it before in gets called. If I listen globally for all incoming data instead though, regardless of individual listeners, I can transform the data there and then as well.
11 cat.on('out', output, cat); // However for output, there isn't really the global option. I must listen by adding my own listener individually BEFORE this one is ever called.
12 return chain;
13}
14function output(at){
15 var cat = this.as, gun = cat.gun, root = gun.back(-1), put, get, now, tmp;
16 if(!at.gun){
17 at.gun = gun;
18 }
19 if(get = at.get){
20 if(!get[_soul]){
21 if(obj_has(get, _field)){
22 get = get[_field];
23 var next = get? (gun.get(get)._) : cat;
24 // TODO: BUG! Handle plural chains by iterating over them.
25 if(obj_has(next, 'put')){ // potentially incorrect? Maybe?
26 //if(u !== next.put){ // potentially incorrect? Maybe?
27 //next.tag['in'].last.next(next);
28 next.on('in', next);
29 return;
30 }
31 if(obj_has(cat, 'put')){
32 //if(u !== cat.put){
33 var val = cat.put, rel;
34 if(rel = Gun.node.soul(val)){
35 val = Gun.val.rel.ify(rel);
36 }
37 if(rel = Gun.val.rel.is(val)){
38 if(!at.gun._){ return }
39 (at.gun._).on('out', {
40 get: {'#': rel, '.': get},
41 '#': Gun.on.ask(Gun.HAM.synth, at.gun),
42 gun: at.gun
43 });
44 return;
45 }
46 if(u === val || Gun.val.is(val)){
47 if(!at.gun._){ return }
48 (at.gun._).on('in', {
49 get: get,
50 gun: at.gun
51 });
52 return;
53 }
54 } else
55 if(cat.map){
56 obj_map(cat.map, function(proxy){
57 proxy.at.on('in', proxy.at);
58 });
59 }
60 if(cat.soul){
61 if(!at.gun._){ return }
62 (at.gun._).on('out', {
63 get: {'#': cat.soul, '.': get},
64 '#': Gun.on.ask(Gun.HAM.synth, at.gun),
65 gun: at.gun
66 });
67 return;
68 }
69 if(cat.get){
70 if(!cat.back._){ return }
71 (cat.back._).on('out', {
72 get: obj_put({}, _field, cat.get),
73 gun: gun
74 });
75 return;
76 }
77 at = obj_to(at, {get: {}});
78 } else {
79 if(obj_has(cat, 'put')){
80 //if(u !== cat.put){
81 cat.on('in', cat);
82 } else
83 if(cat.map){
84 obj_map(cat.map, function(proxy){
85 proxy.at.on('in', proxy.at);
86 });
87 }
88 if(cat.ack){
89 if(!obj_has(cat, 'put')){
90 return;
91 }
92 }
93 cat.ack = -1;
94 if(cat.soul){
95 cat.on('out', {
96 get: {'#': cat.soul},
97 '#': Gun.on.ask(Gun.HAM.synth, cat.gun),
98 });
99 return;
100 }
101 if(cat.get){
102 if(!cat.back._){ return }
103 (cat.back._).on('out', {
104 get: obj_put({}, _field, cat.get),
105 gun: cat.gun
106 });
107 return;
108 }
109 }
110 }
111 }
112 (cat.back._).on('out', at);
113}
114function input(at){
115 at = at._ || at;
116 var ev = this, cat = this.as, gun = at.gun, coat = gun._, change = at.put, back = cat.back._ || empty, rel, tmp;
117 if(0 > cat.ack && at.via && !Gun.val.rel.is(change)){ // for better behavior?
118 cat.ack = 1;
119 }
120 if(cat.get && at.get !== cat.get){
121 at = obj_to(at, {get: cat.get});
122 }
123 if(cat.field && coat !== cat){
124 at = obj_to(at, {gun: cat.gun});
125 if(coat.ack){
126 cat.ack = cat.ack || coat.ack;
127 }
128 }
129 if(u === change){
130 ev.to.next(at);
131 if(cat.soul){ return }
132 echo(cat, at, ev);
133 if(cat.field){
134 not(cat, at);
135 }
136 obj_del(coat.echo, cat.id);
137 obj_del(cat.map, coat.id);
138 return;
139 }
140 if(cat.soul){
141 ev.to.next(at);
142 echo(cat, at, ev);
143 obj_map(change, map, {at: at, cat: cat});
144 return;
145 }
146 if(!(rel = Gun.val.rel.is(change))){
147 if(Gun.val.is(change)){
148 if(cat.field || cat.soul){
149 not(cat, at);
150 } else
151 if(coat.field || coat.soul){
152 (coat.echo || (coat.echo = {}))[cat.id] = cat;
153 (cat.map || (cat.map = {}))[coat.id] = cat.map[coat.id] || {at: coat};
154 //if(u === coat.put){ return } // Not necessary but improves performance. If we have it but coat does not, that means we got things out of order and coat will get it. Once coat gets it, it will tell us again.
155 }
156 ev.to.next(at);
157 echo(cat, at, ev);
158 return;
159 }
160 if(cat.field && coat !== cat && obj_has(coat, 'put')){
161 cat.put = coat.put;
162 };
163 if((rel = Gun.node.soul(change)) && coat.field){
164 coat.put = (cat.root.get(rel)._).put;
165 }
166 ev.to.next(at);
167 echo(cat, at, ev);
168 relate(cat, at, coat, rel);
169 obj_map(change, map, {at: at, cat: cat});
170 return;
171 }
172 relate(cat, at, coat, rel);
173 ev.to.next(at);
174 echo(cat, at, ev);
175}
176Gun.chain.chain.input = input;
177function relate(cat, at, coat, rel){
178 if(!rel || node_ === cat.get){ return }
179 var tmp = (cat.root.get(rel)._);
180 if(cat.field){
181 coat = tmp;
182 } else
183 if(coat.field){
184 relate(coat, at, coat, rel);
185 }
186 if(coat === cat){ return }
187 (coat.echo || (coat.echo = {}))[cat.id] = cat;
188 if(cat.field && !(cat.map||empty)[coat.id]){
189 not(cat, at);
190 }
191 tmp = (cat.map || (cat.map = {}))[coat.id] = cat.map[coat.id] || {at: coat};
192 if(rel !== tmp.rel){
193 ask(cat, tmp.rel = rel);
194 }
195}
196function echo(cat, at, ev){
197 if(!cat.echo){ return } // || node_ === at.get ????
198 if(cat.field){ at = obj_to(at, {event: ev}) }
199 obj_map(cat.echo, reverb, at);
200}
201function reverb(cat){
202 cat.on('in', this);
203}
204function map(data, key){ // Map over only the changes on every update.
205 var cat = this.cat, next = cat.next || empty, via = this.at, gun, chain, at, tmp;
206 if(node_ === key && !next[key]){ return }
207 if(!(gun = next[key])){
208 return;
209 }
210 at = (gun._);
211 //if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.get(tmp)._)) && obj_has(tmp, 'put')){
212 // data = tmp.put;
213 //}
214 if(at.field){
215 if(!(data && data[_soul] && Gun.val.rel.is(data) === Gun.node.soul(at.put))){
216 at.put = data;
217 }
218 chain = gun;
219 } else {
220 chain = via.gun.get(key);
221 }
222 at.on('in', {
223 put: data,
224 get: key,
225 gun: chain,
226 via: via
227 });
228}
229function not(cat, at){
230 if(!(cat.field || cat.soul)){ return }
231 var tmp = cat.map;
232 cat.map = null;
233 if(null === tmp){ return }
234 if(u === tmp && cat.put !== u){ return } // TODO: Bug? Threw second condition in for a particular test, not sure if a counter example is tested though.
235 obj_map(tmp, function(proxy){
236 if(!(proxy = proxy.at)){ return }
237 obj_del(proxy.echo, cat.id);
238 });
239 obj_map(cat.next, function(gun, key){
240 var coat = (gun._);
241 coat.put = u;
242 if(coat.ack){
243 coat.ack = -1;
244 }
245 coat.on('in', {
246 get: key,
247 gun: gun,
248 put: u
249 });
250 });
251}
252function ask(cat, soul){
253 var tmp = (cat.root.get(soul)._);
254 if(cat.ack){
255 tmp.ack = tmp.ack || -1;
256 tmp.on('out', {
257 get: {'#': soul},
258 '#': Gun.on.ask(Gun.HAM.synth, tmp.gun),
259 gun: tmp.gun
260 });
261 return;
262 }
263 obj_map(cat.next, function(gun, key){
264 (gun._).on('out', {
265 get: {'#': soul, '.': key},
266 '#': Gun.on.ask(Gun.HAM.synth, tmp.gun),
267 gun: gun
268 });
269 });
270}
271var empty = {}, u;
272var obj = Gun.obj, obj_has = obj.has, obj_put = obj.put, obj_del = obj.del, obj_to = obj.to, obj_map = obj.map;
273var _soul = Gun._.soul, _field = Gun._.field, node_ = Gun.node._;
274
\No newline at end of file