event-mixer
Version:
another event emitter
125 lines (113 loc) • 4.78 kB
JavaScript
// helper methods
var cap = (s) => s.slice(0,1).toUpperCase() + s.slice(1);
var map = (v,f) => [].concat(v).map(f);
exports.mixer = function(target={}, emitter={})
{
var events = {}, targetFns = ['on', 'off'];
// create new event handler
var create = (name, data) =>
{
var cname = cap(name);
// add on/off functions to target for this event
targetFns.forEach(n => target[n + cname] = function(f) { return this[n](name, f); });
// add fire function to emitter for this event
emitter['fire' + cname] = function(d) { return this.fire(name, d); };
// add event handler
return events[name] = exports.handler(target, name, data);
};
// clear named event handler
var destroy = (name) =>
{
var cname = cap(name), handler = events[name];
// clear and remove event handler
events[name].clear(); delete events[name];
// remove on/off functions from target for this event
targetFns.forEach(n => delete target[n + cname]);
// remove fire function from emitter for this event
delete emitter['fire' + cname];
return handler;
};
var methods =
{
// create/register a new event for target
create(n, d) { return create(n, d); },
// destroy/unregister event for target
destroy(n) { return destroy(n); },
// return the emitter for this event manager
emitter() { return emitter; },
// return the named event
event(n) { return events[n]; },
// fire the named event
fire(n, d) { return events[n].fire(d); },
// is the named event registered?
has(n) { return events[n] ? true : false; },
// return the names of all registered events
names() { return Object.keys(events); },
// remove listener(s) for named event(s)
off(n, f) { map(n, x => events[x].remove(f)); return this; },
// add listener(s) for named event(s)
on(n, f) { map(n, x => events[x].append(f)); return this; },
// return the target of this event manager
target() { return target; }
};
// add on/off methods to target
targetFns.forEach(n => target[n] = methods[n]);
// add fire method to emitter
emitter.fire = methods.fire;
return methods;
};
exports.handler = function(target, name, hdata)
{
var listeners = [];
var fire = (idata) =>
{
// should the result of this event (if any) be allowed?
var allow = true;
// event data - invocation data overwrites handler data
var data = Object.assign({}, hdata, idata);
for (var i=0;i<listeners.length;i++)
{
// call listener with an 'event object'
var rtn = listeners[i]({ target, name, data }) || {};
// listener can indicate loss of interest in this event
if (rtn.remove) { listeners.splice(i, 1); i--; }
// listener can indicate a desire to prevent whatever comes next
if (rtn.prevent) allow = false;
// listener can end notifications
if (rtn.stop) break;
}
return allow;
};
var methods =
{
// append listener(s)
add(f) { return this.append(f); },
// add listener(s) to end of list
append(f) { map(f, this.push); return this; },
// returns the listener at the given index
at(i) { return i >= 0 && i < listeners.length ? listeners[i] : null; },
// remove all listeners
clear() { listeners = []; return this; },
// return the number of listeners for this event
count() { return listeners.length; },
// removes and returns the listener at index
cut(i) { return i >= 0 && i < listeners.length ? listeners.splice(i, 1)[0] : null; },
// filter/change the listener list
each(m) { [...listeners].reduce((a,l,i) => this.push(m(l,i)), listeners = []); return this; },
// is the given function a listener on this event?
has(f) { return listeners.indexOf(f) >= 0; },
// return the index of a given listener
indexOf(f,s) { return listeners.indexOf(f,s); },
// trigger this event (with data)
fire(d) { return fire(d); },
// add listener(s) to beginning of list
prepend(f) { [].concat(f).reverse().map(this.unshift); return this; },
// add last listener
push(f) { return typeof f === 'function' && listeners.push(f); },
// remove listener(s)
remove(f) { map(f, m => this.cut(listeners.indexOf(m))); return this; },
// add first listener
unshift(f) { return typeof f === 'function' && listeners.unshift(f); }
};
return methods;
};