Skip to content

Instantly share code, notes, and snippets.

@Maxstupo
Last active February 8, 2018 13:14
Show Gist options
  • Save Maxstupo/e81ec2f35f2f303d1ee5b725ae6533a9 to your computer and use it in GitHub Desktop.
Save Maxstupo/e81ec2f35f2f303d1ee5b725ae6533a9 to your computer and use it in GitHub Desktop.
A event system to provide event handling.
/**
* The EventSystem provides basic event handling.
*
* A basic example:
* <pre><code>
* let es = new EventSystem();
*
* let listenerId = es.on('myEvent', function() { // Register a new event listener for the event 'myEvent'.
* console.log('Hello World!!');
* });
*
* es.emit('myEvent'); // Emit the 'myEvent' event.
* </code></pre>
*
* @constructor
* @param {object} [injectInto] The object to inject {@link EventSystem#on() on()}, {@link EventSystem#off() off()} methods into. If this is specified, event listeners will have this context instead of the instance of the event system.
* @param {boolean} [includeEmit=false] If true the {@link EventSystem#emit() emit()} method will also be injected into the provided object.
*/
const EventSystem = function (injectInto, includeEmit) {
let evtQueue = {};
let idSeq = 0;
const _this = this;
/**
* Fire an event. This will invoke all callbacks listening for this event.
* @param {string} eventName The name of the event. If 'falsey', undefined will be returned.
* @param {...*} [args] Parameters that will be passed to the event listeners.
* @returns {object|undefined} Undefined if <code>eventName</code> is 'falsey',
* otherwise returns the injected object provided by the {@link EventSystem constructor}, if not provided the {@link EventSystem} instance will be returned.
*
*/
this.emit = function (eventName, ...args) {
if (!eventName) return;
let queue = evtQueue[eventName];
if (queue) {
queue.events.forEach(event => {
event.remove = event.cb.apply(injectInto || _this, args);
});
queue.events = queue.events.filter(event => event.remove);
}
return injectInto || _this;
};
/**
* Add a event listener to a specific event.
* @param {string} eventName The number of the event to add this listener to.
* @param {function} callback The callback that will be invoked when the specified event occurs. Returning true in the callback will remove the listener.
* @returns {number|undefined} The id of this event listener. Useful for removing this listener via the {@link EventSystem#off() off()} method. If either specified parameter is 'falsey' undefined will be returned.
*/
this.on = function (eventName, callback) {
if (!callback || !eventName)
return;
let queue = evtQueue[eventName] || {events: []};
queue.events.push({
id: ++idSeq,
remove: false,
cb: callback
});
evtQueue[eventName] = queue;
return idSeq;
};
/**
* Removes a specific listener when using a listener id, all listeners of a event if parameter is an event name, or all listeners of all events if no parameter is provided (undefined).
* @param {string|number|undefined [eventNameOrId] Using an event name it will remove all listeners for that event. Providing an id returned by {@link EventSystem#on() on()} can be used to remove a specific listener. All event listeners can be removed by using a 'falsey' value.
* @returns {object|undefined} The injected object provided by the {@link EventSystem constructor}, if not provided the {@link EventSystem} instance will be returned.
*/
this.off = function (eventNameOrId) {
if (!eventNameOrId) {
idSeq = 0;
evtQueue = {};
} else if (typeof eventNameOrId === 'string') {
delete evtQueue[eventNameOrId];
} else if (typeof eventNameOrId === 'number') {
Object.keys(evtQueue).forEach(key => {
let queue = evtQueue[key];
queue.events.forEach(event => {
if (event.id === eventNameOrId)
event.remove = true;
});
queue.events = queue.events.filter(event => !event.remove);
if (queue.events.length === 0)
delete evtQueue[key];
});
}
return injectInto || _this;
};
if (injectInto) {
Object.keys(_this).forEach(key => {
if (!includeEmit || (includeEmit && key !== 'emit'))
injectInto[key] = _this[key];
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment