createPackage('nl.grip.cms.event', 'EventUtils');

/**
 * EventCache Version 1.0
 * Copyright 2005 Mark Wubben
 *
 * Provides a way for automagically removing events from nodes and thus preventing memory leakage.
 * See <http://novemberborn.net/javascript/event-cache> for more information.
 *
 * Event Cache uses an anonymous function to create a hidden scope chain.
 * This is to prevent scoping issues.
 *
 * This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
 */
EventUtils.EventCache = function()
{
    var listEvents = [];

    return {
        listEvents : listEvents,

        add : function(node, sEventName, fHandler, bCapture)
        {
            listEvents.push(arguments);
        },

        flush : function()
        {
            var i, item;
            for(i = listEvents.length - 1; i >= 0; i = i - 1){

                item = listEvents[i];
                EventUtils.removeEvent(item[0], item[1], item[2], item[3]);
            }
        }
    }
}();

/**
 * The Delegate object provides a wrapper method to create a anonymous function.
 * These functions are typically used in situations where the object's scope is lost, such as events.
 */
EventUtils.Delegate = function()
{
    return {
        create : function(obj, eventName, func, args)
        {
            var f = function(e)
            {
                args = args || [];

                // fix event using jQuery, if passed argument is in fact an event
                if (e && (e['bubbles'] !== null) && (!e instanceof $.Event)) {
                    e = $.event.fix(e);
                }

                // create a new anonymous array with the event prepended to it
                return func.apply(obj, [e].concat(args));
            };

            EventUtils.EventCache.add(obj, eventName, f, false);

            return f;
        }
    }
}();

EventUtils.applyEvent = function(node, eventName, func, data)
{
    node = $(node);
    if (node.size()) {
        node.bind(eventName, data, func);
    }
}

EventUtils.removeEvent = function(node, eventName, func)
{
    node = $(node);
    if (node.size()) {
        node.unbind(eventName, func);
    }
}

/**
 * Common event functions below.
 *
 * There are generally two ways to apply an event to a DOM node:
 * 1. Using prepareEvent: use this when setting events for nodes during page load.
 *    All prepared events are stacked and processed when the document has loaded.
 * 2. Using applyEvent: use this to set an event at runtime.
 *    It assumes the document is loaded, and DOM is accessible.
 *
 * All events are stored internally, and using these features ensures you that all functions are unloaded properly.
 * This way, you can be sure memory leaks are avoided.
 *
 * @author Peter Kruithof
 */

/**
 * Cancels event by stopping propagation and preventing default action (ie: return false).
 * Function respects Internet Explorer's proprietary methods.
 *
 * @param   event e The event
 * @return  void
 */
EventUtils.cancelEvent = function(e)
{
    if (e) {
        e.preventDefault();
        e.stopPropagation();
    }
}

EventUtils.EventPreparer = function()
{
    var events = [];

    return {
        events : events,

        add : function(e)
        {
            events.push(e);
        },

        /**
         * Applies all stacked events. This should be executed using the body's onload event.
         *
         * @return  void
         */
        applyEvents : function()
        {
            for (var i = 0; i < events.length; i++) {
                var event = events[i];
                $('#' + event.id).bind(event.eventName, event.data, event.callback);
            }
        }
    }
}();

/**
 * Adds event to stack. The stack will be processed in the body's onload event
 *
 * @param   string    id          The element's id
 * @param   string    eventname   The name of the event
 * @param   function  callback    Function to callback to
 * @param   array     data        Object containing arguments to apply to element
 * @return  void
 */
EventUtils.prepareEvent = function(id, eventName, callback, data)
{
    var e = {};
    e.id = id;
    e.eventName = eventName;
    e.callback = callback;
    e.data = data || {};

    EventUtils.EventPreparer.add(e);
}


/**
 * Cancels event by stopping propagation and preventing default action (ie: return false).
 * Function respects Internet Explorer's proprietary methods.
 *
 * @param   event e The event
 * @return  void
 */
EventUtils.cancelEvent = function(e)
{
    if (e) {
        if (!(e instanceof $.Event)) e = $.event.fix(e);

        e.preventDefault();
        e.stopPropagation();
    }
}

EventUtils.addLoadEvent = function(func)
{
    $(func);
}

EventUtils.addUnloadEvent = function(func)
{
    $(window).unload(func);
}

/**
 * Apply 'onload' events
 */

EventUtils.addLoadEvent(EventUtils.Delegate.create(EventUtils.EventPreparer, 'load', EventUtils.EventPreparer.applyEvents));
EventUtils.addUnloadEvent(EventUtils.EventCache.flush);
