﻿/*
AddEvent Manager (c) 2005 Angus Turnbull http://www.twinhelix.com
Free usage permitted as long as this credit notice remains intact.
*/
if (!window.aeOL)
{
	// "AddEvent Object List" is our global object/function tracking array.
	var aeOL = [];
	var addEvent = function(obj, name, fn, legacy)
	{
		// Get the 'on'-prefixed event handle, and create two variables which are
		// references to all events of a particular type (typeArr), and all
		// functions run by one instance of the event manager function (arrayFns).
		var handle = 'on' + name, typeArr, arrayFns;
		// Default to the DOM Event model where supported.
		// Users can force "legacy" event model usage if they want to use this as a
		// generic DOM Event emulation facility with their own JS objects.
		if (obj.addEventListener && !legacy) return obj.addEventListener(name, fn, false);
		// Each object has an 'aE' property that's its unique index within window.aeOL.
		// That entry has a property 'o' and arrays for each type of event added to it.
		if (!obj.aE) { obj.aE = aeOL.length || 1; aeOL[obj.aE] = { o:obj } }
		// typeArr contains sub-arrays of events of the current type, with one array
		// run by each instance of the event manager. It's created now if necessary.
		typeArr = aeOL[obj.aE][name] || (aeOL[obj.aE][name] = []);
		// Quit if we have already attached this function to this type of event.
		// These next three lines are optional and can be removed if you want.
		for (var i = 0; i < typeArr.length; i++)
			for (var j = 0; j < typeArr[i].length; j++)
				if (typeArr[i][j] == fn) return;
		if (obj[handle] && obj[handle]._ae)
		{
			// If addEvent's event manager function is already handling this event,
			// append it to our list of functions to be run for this instance.
			arrayFns = typeArr[typeArr.length - 1];
			arrayFns[arrayFns.length] = fn;
		}
		else
		{
			// Create a new list of functions of this type, and populate it with any
			// pre-existing handler (if any) and the function we're adding this time.
			typeArr[typeArr.length] = obj[handle] ? [obj[handle], fn] : [fn];
			// Assign our event manager function (not a closure, so avoids memory leaks)
			// which runs all functions within its "arrayFn" instance array.
			// It gets an object reference and arrayFns from the global aeOL array,
			// loops through, runs them as a method of "obj", manages return values,
			// passes the correct event object, and clears "_f" to avoid memory leaks.
			obj[handle] = new Function('e', 'var r = true, i = 0, obj = aeOL[' + obj.aE + '].o,' +
			'arrayFns = aeOL[' + obj.aE + ']["' + name + '"][' + (typeArr.length - 1) + '];' +
			'for (; i < arrayFns.length; i++) { ' +
			'obj._f = arrayFns[i]; r = obj._f(e||window.event) != false && r; obj._f = null;' +
			'} return r');
			// Set a flag indicating that addEvent is handling this event, so future
			// calls can just add functions to the current instance of "arrayFns" above.
			obj[handle]._ae = 1;
		}
	};

	var removeEvent = function(obj, name, fn, legacy)
	{
		// Much like addEvent() in reverse. i and j are counter variables.
		var typeArr, arrayFns, i, j, splice;
		if (obj.removeEventListener && !legacy) return obj.removeEventListener(name, fn, false);
		if (!obj.aE || !aeOL[obj.aE]) return;
		typeArr = aeOL[obj.aE][name];
		i = typeArr.length;
		// Loop through all events of this type within aeOL.
		// Once we find the same function, splice it out of its array and quit.
		while (i--)
		{
			arrayFns = typeArr[i];
			j = arrayFns.length;
			splice = 0;
			while (j--)
			{
				if (arrayFns[j] == fn) splice = 1;
				if (splice) arrayFns[j] = arrayFns[j + 1];
			}
			if (splice) { arrayFns.length--; return }
		}
	};

}

// Optional cancelEvent() function you can call within your event handlers to
// stop them performing the normal browser action or kill the event entirely.
// Pass an event object, and the second "c" parameter cancels event bubbling.
function cancelEvent(e, c)
{
	e.returnValue = false;
	if (e.preventDefault) e.preventDefault();
	if (c)
	{
		e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();
	}
};

/*
END AddEvent Manager (c) 2005 Angus Turnbull http://www.twinhelix.com
*/
