-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathgun-synclist.js
100 lines (93 loc) · 3.54 KB
/
gun-synclist.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* gun-synclist
* @author S.J.J. de Vries ( [email protected])
* @gitter @Stefdv
* @purpose
* - on init it will return your full set as an Array, including a 'lookup' Object.
* - on every change after initial run it reurns the full changed node, its soul and
* its index in the initial Array. eg: {soul:"AbCd123....", idx: 121, {<your full node>}}
* - even on nested property changes it will still return the node soul ( not the soul of the nested object);
*
* @why
* - No need to rebuild the whole list in DOM when one property changes...just use the index to splice the item.
*
* ( i used .open() from Gun/lib/open.js as a base, tx those developers.)
*/
;(function(){
if(typeof window !== "undefined"){
var Gun = window.Gun;
} else {
var Gun = require('gun/gun');
}
Gun.chain.synclist = function(cb, opt, at){
opt = opt || {};
opt.doc = opt.doc || {}; // used to build the full set
opt.ids = opt.ids || {}; // keep track of processed ids
opt.init = opt.init || true; // if we have opt.init...init is finished ;p
opt.any = opt.any || cb; // users callback function
opt.list = opt.list || []; // Array build from opt.doc
opt.lookup = opt.lookup || {}; // lookup soul/index in opt.list
opt.owner = opt.owner || null; // soul of the node the change happened on
opt.ev = opt.ev || {off: function(){
Gun.obj.map(opt.ev.s, function(e){
if(e){ e.off() }
});
opt.ev.s = {};
}, s:{}}
this.on(function(data, key, ctx,ev){
delete ((data = Gun.obj.copy(data))||{})._;
if(this.back(1)._.get) {
opt.root = this.back(1)._.get;
opt.prop = this._.get ;
if(opt.doc[opt.root]){ opt.owner = opt.root; }
else if(opt.doc[opt.prop]) { opt.owner = opt.prop; }
}
clearTimeout(opt.to);
opt.to = setTimeout(function(){
if(!opt.any){ return };
if(opt.init) {
let list =Object.keys(opt.doc).map( (soul,idx) => {
opt.lookup[soul] = idx;
if(opt.doc[soul]) {
opt.doc[soul]._soul = soul;
}
return opt.doc[soul]
});
let lookup = Gun.obj.copy(opt.lookup)
opt.any.call(opt.at.gun,{list:list,lookup:lookup});
if(opt.off){
opt.ev.off();
opt.any = null;
}
} else {
opt.any.call(opt.at.gun,{soul:opt.owner,
idx:opt.lookup[opt.owner],
node:opt.doc[opt.owner]}
);
}
opt.init = false;
}, opt.wait || 1);
opt.at = opt.at || ctx;
opt.key = opt.key || key;
opt.ev.s[this._.id] = ev;
var tmp = this, id,idx;
Gun.obj.map(data, function(val, key){
id = Gun.val.rel.is(val);
if(!id) {
(at || opt.doc)[key] = val;
return;
}
if(opt.ids[id]){
(at || opt.doc)[key] = opt.ids[id];
return;
}
opt.ids[id] = ( at || opt.doc )[key] = {};
tmp.get(key).synclist(opt.any, opt, opt.ids[id]);
});
},true)
};
Gun.chain.listonce = function(cb, opt, at){
(opt = opt || {}).off = !0;
return this.synclist(cb, opt, at);
}
}());