// Base event registration object
// by Lost Boys - www.lostboys.nl

var EventListener = {
	listeners:[],
	bSafari:/safari/i.test(navigator.userAgent),
	addEvents:function(els, type, func, scope) {
		for(var i=0; i<els.length; i++) {
			this.addEvent(els[i], type, func, scope);
		}
	},

	addEvent:function(el, type, func, scope) {
		var handler = this.delegate(func, scope || el);
		try {
			el.addEventListener(type, handler, false); 
		} catch (e) { 
			el.attachEvent('on' + type, handler); 
		}

		var event = { element:el, type:type, handler:handler };
		this.listeners.push(event);
		return event;
	},

	removeEvents:function(el, type) {
		var events = el? this.getEvents(el, type) : this.listeners;
		for (var i=0; i<events.length; i++) {
			this.removeEvent(events[i]);
		}
	},

	removeEvent:function(event) {
		try {
			event.element.removeEventListener(event.type, event.handler, false);
		} catch (e) {
			event.element.detachEvent('on' + event.type, event.handler);
		}

		for(var i=0; i<this.listeners.length; i++) {
			if(this.listeners[i] == event) {
				this.listeners.splice(i, 1);
				break;
			}
		}
	},

	getTarget:function(e, nodeName) {
		var target = e.target || e.srcElement;
		
		if(nodeName) {
			// 23/10/16, NS reisplanner
			var reg = new RegExp('^'+nodeName+'$', 'i');
			while(target && !reg.test(target.nodeName)) {
				target = target.parentNode;
			}	return target;
		} else {
			return (target.nodeType > 1)? target.parentNode:target;
		}
	},

	getEvents:function(el, type) {
		var result = [];
		for(var item,i=0; (item = this.listeners[i++]);) {
			if(item.element == el && (!type || type == item.type)) {
				result.push(item);
			}
		}

		return result;
	},

	cancelEvent:function(e) {
		this.preventDefault(e);
		this.stopPropagation(e);		
		return false;
	},
	
	preventDefault:function(e) {
		try {
			e.preventDefault();
		} catch (exception) {
			e.returnValue = false;
		}	
		
		if(this.bSafari) {
			var target = this.getTarget(e);
		 	if (/^a$/i.test(target.nodeName)) {
				target.onclick = function() { return false; };
			}
		}
		return false;
	},
	
	stopPropagation:function(e) {
		try {
			e.stopPropagation();
		} catch (exception) {
			e.cancelBubble = true;
		}
		return false;
	},

	delegate:function(func, scope) {
		return function() {
			func.apply(scope, arguments);
		}
	}
}























<!--
function getElementsByAttributeValue(attribute, value, root) {
	var output = new Array;
	var attributeName = (document.all && attribute.toLowerCase() == "class") ? "className" : attribute;
	var rootElement = root ? root : document;
	var els = (rootElement.all ? rootElement.all : rootElement.getElementsByTagName("*"));
	
	var attributeReg = new RegExp(value);
	var attributeValue;

	for(var i = els.length-1; i >= 0; i--) {
		attributeValue = els[i].getAttribute(attributeName);
		if(attributeValue  && (!value || attributeReg.test(attributeValue))) output[output.length] = els[i];	
	}
	return output.reverse();
}


var ClassName = {
	add:function(node, name) {
		if(!this.contains(node, name))
			node.className += node.className? (' ' + name) : name;
	},

	remove:function(node, name) {
		if(node.className)
			node.className = node.className.replace(new RegExp('(^|\\s)'+name+'(\\s|$)','g'), ' ');
	},

	contains:function(node, name) {
		return new RegExp('(^|\\s)'+name+'(\\s|$)').test(node.className);
	},

	swap:function(node, old, name) {
		node.className = this.contains(node, old)?
			node.className.replace(new RegExp('(^|\\s)'+old+'(\\s|$)','g'), '$1'+name+'$2') : 
			node.className.replace(new RegExp('(^|\\s)'+name+'(\\s|$)','g'), '$1'+old+'$2');
	},

	toggle:function(node, name) {
		if(!this.contains(node, name)) {
			this.add(node, name);
		} else {
			this.remove(node, name);
		}
	}
}

var Class = {
	extend:function(Base, constructor, prototype) {
		var Extended = function() {
			Base.apply(this, arguments);
			constructor.apply(this, arguments);
		}

		this.implement(Extended, Base.prototype);
		if(prototype) this.implement(Extended, prototype);
		return Extended;
	},

	implement:function(Class, protoface) {
		for(var i in protoface) {
			Class.prototype[i] = protoface[i];
		}
	}
}

var LinkListener = {
	init:function() {
		this.relations = [];
		EventListener.addEvent(document, 'click', this.scope(this.handleClicks));
	},
	
	addRelation:function(rel, handler) {
		if(!this.relations) this.init(); //jit init

		// register link relation handler, as regular expression
		this.relations.push({type:rel, handler:handler});
	},

	handleClicks:function(e) {
		if(e.shiftKey || e.ctrlKey || e.altKey) return;

		var target = EventListener.getTarget(e, 'a');
		var rel = target? target.getAttribute('rel') : null;
		var handler = rel? this.searchHandler(rel) : null;
		if(handler && handler(target, rel)) {
			// if handler returns true, cancel default event
			EventListener.cancelEvent(e);
		}
	},

	searchHandler:function(rel) {
		for(var relation,i=0; i<this.relations.length; i++) {
			relation = this.relations[i];
			if(relation.type.test(rel)) {
				return relation.handler;
			}
		}
	},
	
	scope:function(method) {
		var scope = this;
		return function() {
			return method.apply(scope, arguments);
		}
	}
}
//-->