/**
 * Events, helper class to work with events.
 * Code largely based on Peter Nederlof's work, mainly cause he first
 * showed me how to do this and our coding styles are almost identical.
 *
 * v1.0.060628.080701
 * @author Martin Reurings - http://www.windgazer.nl/
 * @credits Peter Nederlof - http://www.xs4all.nl/~pnederlof/
 * @class
 */

var Events = {
	safRE:/safari/i,
	aRE:/^a$/i,
	/**
	 * Attaches an event to an element. Uses DOM methods when available, but
	 * falls back to onXXXX handlers when needed.
	 *
	 * @param {Element} element The element to which to attach the event
	 * @param {String} type The type of event to handle, without the 'on' i.e. mouseover.
	 * @param {Function} handler The event-handler method.
	 * @return EventWrapper
	 */
	attach:function(element, type, handler) {	
		if(!element) return null;
		var result = null;
		if (element.addEventListener) result = element.addEventListener(type, handler, false);
		else if(element.attachEvent) result = element.attachEvent('on' + type, handler);
		else element['on' + type] = handler;
		return {type:type, handler:handler, element:element, result:result}; //return JSON object which contains all the relevant bits
	},
	/**
	 * Detaches an event that has been attached using Events.attach. Makes
	 * use of DOM methods with a fallback to onXXX handlers.
	 * If you didn't store the EventWrapper but have the correct set of data
	 * just pass the data on with the following syntax:
	 * Events.detach({type:String, handler:function, element:Element});
	 * @param {EventWrapper} eventWrapper An object containing all related data to an eventhandler.
	 */
	detach:function(eventWrapper) {
		var element = eventWrapper.element;
		if (element.removeEventListener) element.removeEventListener(eventWrapper.type, eventWrapper.handler, false);
		else if(element.detachEvent) element.detachEvent('on' + eventWrapper.type, eventWrapper.handler);
		else element['on' + eventWrapper.type] = null;
	},
	/**
	 * Cancels an event using DOM methods, returns false. Preferable when
	 * you want to cancel events return the result of this function from your
	 * handler, this will encertain to some degree that onXXX handlers will
	 * also cancel the default action.
	 * On Safari this method will overwrite the onClick method of a link to
	 * return false before setting back it's original onClick method. This
	 * is because the DOM methods do not work on Safari even though they
	 * exist.
	 *
	 * @param {Event} event The event you want to cancel.
	 * @return false
	 */
	cancel:function(event) {
		try {
			event.preventDefault();
		} catch (e) {
			event.returnValue = false;
		}
		try {
			event.stopPropagation();
		} catch (e) {
			event.cancelBubble = true;
		}
		if (Events.safRE.test(navigator.userAgent)) {
			var target = event.target;
			if (target.nodeName == "#text") target = target.parentNode;
		 	if (Events.aRE.test(target.nodeName)) {
		 		target.onclick = function() {
					return false;
				};
			}
		} return false;
	}
};

/**
 * ClickHandler
 * This is a generic click-handler that inspects clicks on links
 *
 * depends: events.js
 * v1.0.070719
 * author: Martin Reurings
 */

var ClickHandler = {
	aRE:/^a$/i,
	hRE:/^(h[0-9])|(fieldset)|(th)$/i,
	buttonRE:/\bbutton\b/i,
	/**
	 * Registration of the ClickHandler object with the document. All it's event-handlers
	 * will be cleaned up internally upon leaving the page.
	 */
	init:Events.attach(window, "load", function() {
		//Initialize
		ClickHandler.onclick = Events.attach(document.body||document.documentElement, "click", function(e) {
			ClickHandler.clickHandler(e);
		});
		//Cleanup
		Events.detach(ClickHandler.init);
		ClickHandler.onunload = Events.attach(window, "unload", function() {
			Events.detach(ClickHandler.onclick);
			Events.detach(ClickHandler.onunload);
		});
	}),
	/**
	 * A 'hashmap' containing the methods link to certain rel-values.
	 * If a rel-value is found within this hashmap it's method will
	 * be called with the link supplied as an argument.
	 */
	handlers:{
	},
	/**
	 * This method is the clickhandler logic which will determine whether or not
	 * to act upon a click-event which is passed to it.
	 */
	clickHandler:function(e){
		var e = e||event;
		var target = e.target||e.srcElement;
		//In case an element is clicked that might have a link in it, or an element inside a link...
		if (!this.aRE.test(target.nodeName)) {
			if (this.hRE.test(target.nodeName) || this.buttonRE.test(target.className)) {
				if (target.getElementsByTagName("a").length > 0)
					target = target.getElementsByTagName("a")[0];
				else
					target = null;
			} else {
				target = target.parentNode;
			}
		}
		/*Check if a link is clicked and rel is known*/
		if (target.nodeName && this.aRE.test(target.nodeName) && target.rel && !target.dblFire) {
			target.dblFire = true;
			window.setTimeout(function() {target.dblFire = false;}, 0);
			if (this.handlers[target.rel] && this.handlers[target.rel](target))
				return Events.cancel(e);
			else
				return true;
		}
	},
	/**
	 * Using this method you can add handlers to the ClickHandler.
	 * The ident identifier should be a string matching the rel-attribute
	 * of the links you want to target. The method should be a function
	 * taking one parameter, the link, and return false when the normal
	 * event-flow should be followed or true when you need to cancel
	 * the normal flow of events.
	 */
	addHandler:function(ident, method) {
		this.handlers[ident] = method;
	}
};