Skip to content

Instantly share code, notes, and snippets.

@jeremyckahn
Created September 29, 2010 21:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyckahn/603614 to your computer and use it in GitHub Desktop.
Save jeremyckahn/603614 to your computer and use it in GitHub Desktop.
// Specify an event handler for a given event and phase
HTMLNode.prototype.addEventListener = function(eventName, handler, phase){
// Make a __handlers object on this element if there is none already
if(!this.__handlers){
this.__handlers = {};
}
// If there are no event handler lists for this event, add them
if(!this.__handlers[eventName]){
this.__handlers[eventName] = {capture : [], bubble: []};
}
// Add the new handler function to the specified phase list
this.__handlers[eventName][phase ? 'capture' : 'bubble'].push(handler);
}
// Gets called whenever an en event is fired
Handle = function(ev){
// Step 1: Initialization and setup
var elements = [];
target = ev.target;
isPropagationStopped = false,
isDefaultPrevented = false;
// We are on the Capture Phase to start with
ev.eventPhase = 0;
ev.stopPropagation = function(){
isPropagationStopped = true;
}
ev.preventDefault = function(){
isDefaultPrevented = true;
}
// Step 2: Collect the DOM nodes
// Loop up through the DOM and collect all of the parent nodes into the 'elements' array
do{
elements.push(target);
}while((target = target.parentNode));
// Reverse the list so it's a bit easier to read in the following for loop
arr.reverse();
// Step 3: Loop through the nodes, and execute the Capture Phase DOM Level 2 event handlers
// For all of the elements in the list...
for(var i = 0 ; i < elements.length; i++){
// If stopPropagation() was called, end the loop - we're done.
if(isPropagationStopped){
break;
}
var currentElement = elements[i],
// If there are any event handlers set for this element, event type and phase,
// set that array to 'handlers'. Otherwise, set 'handlers' to an empty array.
handlers = currentElement.__handlers
&& currentElement.__handlers[ev.type]
&& currentElement.__handlers[ev.type].capture
|| [];
ev.currentTarget = currentElement;
// Loop through the handlers we've collected and execute them
// in the context of the current element
for(var h = 0; i < handlers.length; h++){
handlers[h].call(currentElement, ev);
}
}
// Step 4: Execute the DOM Level 1 event handler and reverse the array
// If propagation was not stopped, execute the DOM level 1 event handler
if(!isPropagationStopped){
ev.target["on" + ev.type].call(ev.target, ev);
}
arr.reverse();
ev.eventPhase = 1;
// Step 5: Loop through the node collection again and execute the Bubble Phase DOM Level 2 event handlers
// Basically, do the same thing as before, but with the 'elements' list reversed...
for(var i = 0 ; i < elements.length; i++){
if(isPropagationStopped){
break;
}
// ... Also, we are working with the 'bubble' phase this time, not 'capture'
var currentElement = elements[i],
handlers = currentElement.__handler
&& currentElement.__handlers[ev.type]
&& currentElement.__handlers[ev.type].bubble
|| [];
ev.currentTarget = currentElement;
for(var h = 0 ; i < handlers.length; h++){
handlers[h].call(currentElement,ev);
}
}
// Step 6: Execute the default browser event handler
// Default behaviors for HTML elements
if(!isDefaultPrevented){
// anchor tag (a link)
if(ev.type == "click" && ev.target.nodeName.toLowerCase() == "a"){
window.location = ev.target.href;
}
// default cases for the rest of the elements go here...
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment