Skip to content

Instantly share code, notes, and snippets.

@w3core
Last active May 13, 2017 09:43
Show Gist options
  • Save w3core/8274e90d81a2720f93db11f1bac676a3 to your computer and use it in GitHub Desktop.
Save w3core/8274e90d81a2720f93db11f1bac676a3 to your computer and use it in GitHub Desktop.
/* Lightweight ultrafast and powerful EventEmitter that built on the native JavaScript emitter.
*
* @param this (Object) An optional parameter that allows to extend any object
* @returns Object (EventBus|this)
*/
function EventBus (that) {
var that = that || this,
id = (new Date).getTime() + "" + Math.random(),
node = document.createElement("EventBus"),
recent = {};
that.on = on;
that.off = off;
that.emit = emit;
/*
* The method registers the specified listener on single or multiple space or comma separated events.
* Multiple calls passing the same combination of event and listener will not result in the listener being added.
* Any event that passed as argument can contain any combination of pseudo-prefixes `:ready` and/or `:once`.
* `:ready` - Indicates that the listener should be called even if the event has been emitted before the listener was added.
* `:once` - Indicates that the listener should be unsubscribed at once event will emitted.
*
* @param event (String) Single or multiple space or comma separated events that can contain of pseudo-prefixes `:ready` and/or `:once`
* @param listener (Function) The function that receives a notification when an event of the specified type occurs
* @returns (EventBus|this)
*/
function on (event, handler) {
var event = unify(event);
if (typeof event == "string" && typeof handler == "function") {
var event = event.replace(/(([\w._\-~\[\]$#&^]+)(:ready|:once)(:ready|:once)?)/ig, function ($0, $1, $e, $3, $4) {
var ready = /:ready/i.test($3 + $4),
once = /:once/i.test($3 + $4),
last = recent[$e],
done;
if (!once) listener("on", $e, node, handler, false);
if (ready && last) {
if (once) done = true;
setTimeout(function(){handler(last)}, 0);
}
if (once && !done) {
var fn = function (e) {
listener("off", $e, node, fn, false);
handler(e);
};
listener("on", $e, node, fn, false);
}
return "";
});
listener("on", cleanPseudo(event), node, handler, false);
}
return that;
}
/*
* The method removes single or multiple space or comma separated events listener previously registered with EventBus.on().
*
* @param event (String) Single or multiple space or comma separated events
* @param listener (Function) The function that receives a notification when an event of the specified type occurs
* @returns (EventBus|this)
*/
function off (event, handler) {
var event = unify(cleanPseudo(event));
if (!event) return that;
listener("off", event, node, handler, false);
return that;
}
/*
* Asynchronously calls each of the listeners registered for the event named eventName, passing the supplied data to each.
*
* @param event (String) Single event name
* @param data (Object) An optional data object
* @param target (Any) Event.target
* @param preventDefault (Function) Event.preventDefault handler
* @param stopPropagation (Function) Event.stopPropagation handler
* @returns (EventBus|this)
*/
function emit (event, data, target, preventDefault, stopPropagation) {
var event = unify(cleanPseudo(event));
if (!event) return that;
recent[event] = dispatch(node, event, data, target, preventDefault, stopPropagation);
return that;
}
function unify (event) {
if (event && typeof event == "string") return event.toLowerCase();
}
function cleanPseudo (events) {
return typeof events == "string" ? events.replace(/:ready|:once/ig, '') : events;
}
function eventHandlerStatus (handler, event, status) {
if (!handler[id]) handler[id] = {};
if (typeof status == "boolean") handler[id][event] = status;
return !!handler[id][event];
}
function listener (type, event, node, fn, sign) {
if (typeof type != "string" || typeof event != "string" || !event.length || !node || typeof fn != "function") return;
if (typeof node == "object" && typeof node.length == "number" && !node.nodeName && node != window) {
for (var i=0; i<node.length; i++) listener(type, event, node[i], fn, sign);
return;
}
var add = !!(type == "on");
var method = add ? "addEventListener" : "removeEventListener";
var e = event.replace(/^\s+|\s+$/img, '').split(/[ ,]+/);
if (e.length == 1) {
if (e[0].length) {
var status = eventHandlerStatus(fn, e[0]);
if ((add && !status) || !add) {
node[method](e[0], fn, !!sign);
eventHandlerStatus(fn, e[0], add);
}
}
return;
}
for(var i=0; i<e.length; i++) listener(type, e[i], node, fn, sign);
}
function dispatch (node, event, data, target, prevent, stop) {
var e = document.createEvent("HTMLEvents");
var _prevent = e.preventDefault;
var _stop = e.stopImmediatePropagation;
function stopPropagation () {
e.propagationStopped = true;
_stop.call(e);
if (typeof stop == "function") stop(e);
}
function preventDefault () {
_prevent.call(e);
if (typeof prevent == "function") prevent(e);
return false;
}
e.data = data;
if (target) {
var descriptor = {value: target};
Object.defineProperties(e, {
target: descriptor,
currentTarget: descriptor,
srcElement: descriptor
});
}
e.preventDefault = preventDefault;
e.stopPropagation = stopPropagation;
e.stopImmediatePropagation = stopPropagation;
e.initEvent(event, true, true);
node.dispatchEvent(e);
return e;
}
}
@w3core
Copy link
Author

w3core commented Oct 13, 2016

Reference API

/* Lightweight ultrafast and powerful EventEmitter that built on the native JavaScript emitter.
 *
 * @param this (Object) An optional parameter that allows to extend any object
 * @returns Object (EventBus|this)
 */
class EventBus ( [this] )

/*
 * The method registers the specified listener on single or multiple space or comma separated events.
 * Multiple calls passing the same combination of event and listener will not result in the listener being added.
 * Any event that passed as argument can contain any combination of pseudo-prefixes `:ready` and/or `:once`.
 * `:ready` - Indicates that the listener should be called even if the event has been emitted before the listener was added.
 * `:once`  - Indicates that the listener should be unsubscribed at once event will emitted.
 *
 * @param event (String) Single or multiple space or comma separated events that can contain of pseudo-prefixes `:ready` and/or `:once`
 * @param listener (Function) The function that receives a notification when an event of the specified type occurs
 * @returns (EventBus|this)
 */
function EventBus.on ( event, listener )


/*
 * The method removes single or multiple space or comma separated events listener previously registered with EventBus.on().
 *
 * @param event (String) Single or multiple space or comma separated events
 * @param listener (Function) The function that receives a notification when an event of the specified type occurs
 * @returns (EventBus|this)
 */
function EventBus.off ( event, listener )

/*
 * Asynchronously calls each of the listeners registered for the event named eventName, passing the supplied data to each.
 *
 * @param event (String) [required] Single event name
 * @param data (Object) [optional] Event.data object
 * @param target (Any) [optional] Event.target
 * @param preventDefault (Function) [optional] Event.preventDefault handler
 * @param stopPropagation (Function) [optional] Event.stopPropagation handler
 * @returns (EventBus|this)
 */
function EventBus.emit (event, data, target, preventDefault, stopPropagation)

Usage

var eventBus = new EventBus;

function handler (e) {
  console.log(e);
  e.stopPropagation();
}

function handler2 (e) {
  console.log(e);
}

eventBus.on("create:ready:once", handler);
eventBus.on("create update delete:once", handler2); // Will not work first time because previous handler has stopped event by e.stopPropagation();

eventBus.emit("create", {date: new Date});
setTimeout(function(){eventBus.emit("create", {date: new Date});}, 2000);
setTimeout(function(){eventBus.emit("update", {date: new Date});}, 4000);
setTimeout(function(){eventBus.emit("delete", {date: new Date});}, 6000);
setTimeout(function(){eventBus.emit("delete", {date: new Date});}, 8000);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment