Source: SoupEvents.js

/** @namespace */
SoupEvents = {
	/**
	 * Turns an object into an event emitter by giving it the methods addEventListener, removeEventListener and dispatchEvent.
	 */
	makeEventEmitter: function(obj) {
		if (Object.isExtensible(obj)) {
			var soupevent = new SoupEvents();
			obj.addEventListener = soupevent.addEventListener;
			obj.removeEventListener = soupevent.removeEventListener;
			obj.dispatchEvent = soupevent.dispatchEvent;
		} else {
			throw "Can't make this object emit events";
		}

		// Event emitter class
		function SoupEvents() {
			// All event registrations
			var registrations = {};

			// Check if a listener is registered
			function isRegistered(type, listener) {
				if (typeof registrations[type] == "undefined")
					return false;
				var i = registrations[type].indexOf(listener);
				return i >= 0;
			};
			// Add an event listener
			this.addEventListener = function(type, listener, useCapture) {
				if (isRegistered(type, listener))
					return;
				if (typeof registrations[type] == "undefined")
					registrations[type] = [];
				registrations[type].push(listener);
			};
			// Remove an event listener
			this.removeEventListener = function(type, listener, useCapture) {
				if (!isRegistered(type, listener))
					return;
				var i = registrations[type].indexOf(listener);
				registrations[type].splice(i, 1);
			};
			// Get all listeners for an event
			this.dispatchEvent = function(evt) {
				var listeners = registrations[evt.type];
				if (typeof listeners == "undefined")
					listeners = [];
				listeners.forEach(function(listener) {
					listener.call(this, evt);
				});
				return !evt.defaultPrevented;
			};
		};
	}
};