Event Package

For this article, I will be using the attachFunc and detachFunc methods outlined in my X-Browser Event Handling article.

Again, sorry about this late post. I am still working 14 hour days this week.

Today I will be introducing a simple event handler package. First, we will discuss the methods you might want to have in an Event Package and whether they are: required, frequently used, or nice to have.

Necessary Functions:

  • Event.add - same as "attachFunc"
  • Event.remove - same as "detachFunc"

Those two functions will allow you to add and remove any event from any element. This is all you need for event management, however, you may frequently wish to know about or change an event (such as triggering element or key code, and preventing default behavior). Here is a list of methods and variables that I frequently use:

Frequently Used Functions and Static Variables:

  • Hash map of key codes - such as {KEY_BACKSPACE: 8}
  • Hash map of event names - such as {CLICK: click}
  • getEl - returns the element that owns this event
  • getCode - returns the key code of the event
  • stopDefault - stops the capture phase of the event
  • stopProgation - stops the bubbling phase of an event
  • stop - stops both the bubbling and capture phase of an event

Having static key codes is helpful, as you wont need to look them up everytime you are listening for an enter key. I map the event Names because if you try to attach a click event, instead of a click event, the browser does not throw an exception. However, your code is not going to work, but if you instead mispell your variable name, then the browser will throw an exception. Here are the function mentioned so far:

var Event = function() {

	//	Private namespace

	var _this = null;
	
	//	Public namespace
	
	return {
	
		/**
		 *	Event name constants
		 */
		BLUR: blur,
		CLICK: click,
		DOUBLE_CLICK: dblclick,
		KEY_DOWN: keydown,
		KEY_PRESS: keypress,
		KEY_UP: keyup,
		LOAD: load,
		MOUSE_DOWN: mousedown,
		MOUSE_MOVE: mousemove,
		MOUSE_OVER: mouseover,
		MOUSE_OUT: mouseout,
		MOUSE_UP: mouseup,
		SUBMIT: submit,
		UNLOAD: unload,
		
		/**
		 *	Common event keycodes
		 */
		KEY_BACKSPACE: 	8,
		KEY_TAB: 		9,
		KEY_RETURN: 	13,
		KEY_ESC: 		27,
		KEY_LEFT:      	37,
		KEY_UP:        	38,
		KEY_RIGHT:     	39,
		KEY_DOWN:      	40,
		KEY_DELETE:    	46,
		KEY_HOME:      	36,
		KEY_END:       	35,
		KEY_PAGEUP:    	33,
		KEY_PAGEDOWN:  	34,
		KEY_SPACE: 		32,

		/**
		 * Attach a listener from an element; uses lazy loading to setup the add and remove functions
		 *
		 * @method add
		 * @param el {HTMLElement} the element to bind the handler to
		 * @param sType {string} the type of event handler
		 * @param fn {function} the callback to invoke
		 * @param fl {boolean} OPTIONAL: capture or bubble phase
		 * @static
		 */
		add: function(el, eType, fn, capture) {
			_this = Event;
			
			if (window.addEventListener) {
				_this.add = function(el, eType, fn, capture) {
					el.addEventListener(eType, fn, capture);
				};
				_this.remove = function (el, eType, fn, capture) {
					el.removeEventListener(eType, fn, capture);
				};
			}
			else if (window.attachEvent) {
				_this.add = function(el, eType, fn, capture) {
					el.attachEvent(on + eType, fn, capture);
				};
				_this.remove = function (el, eType, fn, capture) {
					el.detachEvent(on + eType, fn, capture);
				};
			}
			else {
				_this.add = function() {};
			}
		},

		/**
		 * Extend the Event Object with x-browser retrieval of keycode from event
		 *
		 * @method getCode
		 * @param e {event} The triggering event
		 * @static
		 */
		getCode: function(e) {
			var code = null;
			if (! e) {e = window.event;}
			if (e.keyCode) {code = e.keyCode;}
			else if (e.which) {code = e.which;}
			return code;
		},
		
		/**
		 * X-browser event target retrieval
		 *
		 * @param e {event} The triggering event
		 * @param tagName {string} OPTIONAL: HTML tag name
		 * @param className {string} OPTIONAL: HTML tag attribute class name
		 * @static
		 */
		getEl: function(e, tagName, className) {
			if (! e) {e = window.event;}
			var targ = e.target || e.srcElement;
			if ($D.TEXT_NODE == targ.nodeType) {targ = targ.parentNode;} // defeat Safari bug
			if (tagName || className) {targ = Dom.getParent(targ, tagName, className);}
			return targ;
		},

		/**
		 * Remove a listener from an element
		 *
		 * @method remove
		 * @param el {HTMLElement} the element to bind the handler to
		 * @param sType {string} the type of event handler
		 * @param fn {function} the callback to invoke
		 * @param fl {boolean} OPTIONAL: capture or bubble phase
		 * @static
		 */
		remove: function(el, eType, func, fl) {},

		/**
		 * Convenience method for stopPropagation + stopDefault
		 *
		 * @method stop
		 * @param e {event} The triggering event
		 * @static
		 */
		stop: function(e) {
			_this.stopPropagation(e);
			_this.preventDefault(e);
		},

		/**
		 * Prevents the default behavior of the event
		 *
		 * @method stopDefault
		 * @param e {event} The triggering event
		 * @static
		 */
		stopDefault: function(e) {
			if (e.preventDefault) {
				e.preventDefault();
			}
			else {
				e.returnValue = false;
			}
		},

		/**
		 * Stops event propagation
		 *
		 * @method stopPropagation
		 * @param e {event} The triggering event
		 * @static
		 */
		stopPropagation: function(e) {
			if (e.stopPropagation) {
				e.stopPropagation();
			}
			else {
				e.cancelBubble = true;
			}
		}
	};
}();

There is an endless amount of other stuff&rsquot; that could be added to an Event package. However, most of it is not necessary. Here are a few that I use often enough to include in my package:

Bells and Whistles:

  • getEvents - returns a collection of events on an element
  • getRelatedElem - some mouse events have a related element other than the triggering element
  • getTime - the time the event was triggered
  • getX - the x position of the event
  • getY - the y position of the event
  • getXY - the x and y position of the event
  • removeAll - removing all events from the page
  • removeEventsFromEl - removes all events or a single event type from an element
  • control scope of the callback Function

On Friday, I will look at these features and explain how they can be implemented.