Skip to main content

At the moment, it satisfies very basic needs. You can register an event listener, you can trigger custom events, and you can remove an event listener if needed. The full system will feature live debugging features that can be built in to any page --- basically, you'll be able to watch as events fire, modify which listeners are registered, and modify page behavior on the fly in real time. Not there yet, but here's the basic skeleton.

/*!
* JDM EventBus Library
*
* Copyright 2010, Eric Mann
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

/**
 * Registers the Namespace
 *
 * @param {Object} root The Context.
 * @param {String} ns The namespace.
 *
 * @return {Void}
 */
var parseNamespace = parseNamespace || function (root, ns) {
    var nsParts = ns.split(".");
    for (var i = 0; i < nsParts.length; i += 1) {
        if (typeof root[nsParts[i]] == "undefined") {
            root[nsParts[i]] = {};
        }
        root = root[nsParts[i]];
    }
};
parseNamespace(window, "JDM.EventBus");

/**
 * Main namespace and class
 *
 * This JavaScript class will allow you to create a custom event listener tied
 * directly to a named custom event.
 *
 * @type {Object}
 */
JDM.EventBus = {

    /**
     * Listener object, contains actual listener references and methods for
     * adding/removing listeners as well as binding the listeners to their
     * appropriate triggers at run-time.
     *
     * @type {Object}
     */
    Listeners: {

        /**
         * Instantiates the listener object - every event handler is registered
         * and listed in this object.
         *
         * @type {Object}
         */
        List: {},

        /**
         * Adds a function with an associated handler nickName and execution
         * priority to the list of listeners.
         *
         * @param {String} eventName
         * @param {String} funcName
         * @param {Function} fn
         * @param {String} priority
         */
        Add: function (eventName, funcName, fn, priority) {
            parseNamespace(this.List, eventName + "." + priority + "." + funcName);
            this.List[eventName][priority][funcName] = fn;
        },

        /**
         * Removes the function associated with a particular event listener
         * nickName. The event listener will still be registered with the
         * system, but the trigger function will be triggering a null function,
         * so it won't do anything.
         *
         * @param {String} eventName
         * @param {String} nickName
         */
        Remove: function (eventName, nickName) {
            for (var priority in this.List[eventName]) {
                this.List[eventName][priority][nickName] = null;
            }
        }
    },

    /**
     * Checks for priority settings, if none given, add a listener to the list
     * with a very low priority.
     *
     * @param {String} eventName
     * @param {String} functionName
     * @param {Function} fn
     * @param {Number} priority
     */
    Subscribe: function (eventName, functionName, fn, priority) {
        if (!priority) {
            priority = 10;
        }
        this.Listeners.Add(eventName, functionName, fn, priority);
    },

    /**
     * Trigger an event
     *
     * @param {String} eventName
     * @param {Object} args
     */
    Broadcast: function (eventName, args) {
        if (!this.Listeners.List[eventName]) {
            return;
        }
        for (var i = 0; i <= 10; i += 1) {
            var funcHolder = this.Listeners.List[eventName][i];
            if (funcHolder) {
                for (var fn in funcHolder) {
                    if (funcHolder[fn]) {
                        if (args) {
                            funcHolder[fn](args.eventArgs);
                        } else {
                            funcHolder[fn]();
                        }
                    }
                }
            }
        }
    },
    /**
     * Remove an event listener
     *
     * @param {String} eventName
     * @param {String} nickName
     */
    Unsubscribe: function (eventName, nickName) {
        this.Listeners.Remove(eventName, nickName);
    }
};

// Usage:
// ------

// For example, you can set the page to display an alert every time an image
// loads on the page. First, specify your listener:

JDM.EventBus.Subscribe('customEvent', 'functionNickName', function () {
    console.log('image loaded');
});

// Simple enough. This creates an anonymous function that the EventBus names as
// "functionNickName" and will call whenever the "customEvent" event is
// triggered. You can use a system like jQuery to fire the new event whenever an
// image loads like so:

$('img').load(function () {
    JDM.EventBus.Broadcast('customEvent');
});

// This code snipped adds the custom event trigger to the load() event of every
// <img> tag on the page. Now, you'll see a custom alert whenever an image
// finishes loading ... and if you're using AJAX to dynamically load images
// you'll see the event then as well.