var log = require('hlogger').createLogger('xevents'); class XPrefix { constructor(ctx,event,prefix) { this.ctx = ctx; this.event = event; this.prefix = prefix || ""; } on(name,cb) { this.event.on(this.ctx,this.prefix + ":" + name,cb); return this; } } class XEvent { constructor(donecb,args) { this.count = 0; this.dowait = 0; this.done= donecb; // Callback this.errors = []; this.params = args; } wait() { this.dowait = 1; } } class XEventListener { constructor(ctx,name,cb,order) { this.ctx = ctx; this.name = name; this.callback = cb; this.order = order || 0; // Late call } } // Smarter event system? class XEventEmitter { constructor() { // Prepare this in a single context //this.listeners = new Map(); this.listeners = []; this.auto = {}; this.stat = { emitted:0, tried:0, called:0 } } addListener(...args) { var ctx = this,evtName,cb,order; if(typeof(args[0]) == "string") { [evtName,cb,order] = args; } else { [ctx,evtName,cb,order] = args; } // Manipulate the evtName as in: // /*var re = /[^\\]{(.*?)}/; var paramMap = []; do { var res = evtName.match(re) if(res != null) { paramMap.push(res[1]); // The match + first char of the match evtName = evtName.replace(re,res[0][0]+"(.*)"); } }while(res != null); console.log("Resulting evtName: " + evtName);*/ var listener = new XEventListener(ctx,evtName,cb,order); //listener.paramMap = paramMap; this.listeners.push(listener); //this.listeners.push(entry); // Process the autos var re = new RegExp(evtName); Object.keys(this.auto).map((v) => { var match = v.match(re); if(v.match(re)) { this.process([{match:match,listener:listener}],this.auto[v]); } }); /* try { cb(this.auto[v], new XEvent()); } catch(e) { console.log(e); } } });*/ } // Remove listeners by ctx removeListener(ctx,name) { this.listeners = this.listeners.filter((v) => { if(v == ctx || v.ctx == ctx) { } else { return v; } }); } // 1 arg only toggleOn(name,arg) { this.auto[name]= arg; this.emit(name,arg); } toggleOff(name) { delete this.auto[name]; } process(tocall,args,cb) { var self=this; var evt = new XEvent(next,args); this.stat.emitted++; // Sort tocall = tocall.sort((a,b) => { return (a.listener.order - b.listener.order) }); // Get iter and setup evt var iter = tocall[Symbol.iterator](); function next() { process.nextTick(() => chain(iter)); } // Internal thing function chain(iter) { // Stack overflow risk? maybe put this in process.tick(); var v = iter.next(); if(v.done) { if(cb != undefined) cb(evt); return; } // Create evt here with some global event chaining iteraction try { var entry = v.value; evt.match = entry.match; evt.args = args; self.stat.called++; entry.listener.callback(args,evt); evt.count++; }catch(e) { console.log(e); evt.errors.push(e); // Should we stop?? } if(!evt.dowait) next(); evt.dowait=0; // reset wait? } next(); } search(name,ctx) { var ret = []; this.listeners.forEach((v) => { var re = new RegExp( "^" + v.name+ "$" ); var matchres = name.match(re); if(matchres && (ctx == undefined || ctx == v.ctx) ) { ret.push({ match: matchres, listener:v }); } }); return ret; } emit(name,args) { this.stat.tried++; var tocall = this.search(name); // Mem leak??? var ret = { param: null, callback: null, // Setup callback trigger: function(args,evt) { this.param = [args,evt]; this.dotrigger = 1; if(this.callback) {this.callback(args,evt);} }, done: function(cb) { if(this.dotrigger) { cb(...param); } this.callback = cb; } } // Test this.process(tocall,args,(evt) => { ret.trigger(args,evt) }); return ret ; } // Why? emitTo(ctx,name,args) { var tocall = this.search(name,ctx) this.process(tocall,arg,cb); } // Alias on(ctx,match,cb) { this.addListener(ctx,match,cb); return this; } after(ctx,match,cb) { this.addListener(ctx,match,cb,1000); return this; } prefix(ctx,prefix) { return new XPrefix(ctx,this,prefix); } /*when(ctx,match,cb) { this.addListener(ctx,match,cb); }*/ } module.exports=XEventEmitter;