 | 
July 2nd, 2007, 11:26 PM
|  | Expert | | Join Date: Jun 2007 Location: Baltimore Age: 21
Posts: 587
| | Normalizing Event Triggers in JavaScript
For those of you who are too lazy to keep up with the standards of the current JavaScript versions, this will suffice: - elem.onmouseup = SomeFunction;
However, that method has a lot of limitations. - Only one function per event trigger
- No control over bubbling/capturing
- Dynamic addition and removal of events requires creation and deletion of objects
- It's old
The correct, modern way of handling event triggers are these methods: - addEventListener, removeEventListener
- attachEvent, detachEvent
You see that there are two different ways, right? That's because, yet again, Microsoft decided to impose their own methods on us. In concept, these pairs of functions do the exact same thing, but in reality they don't. Microsoft's way (attachEvent/detachEvent) does not allow you to control whether or not you want to capture events.
The fact that there are two different sets of methods for doing this means that we need to know which ones the browser supports in order to know which ones to use. You could do so with if statements checking whether the browser supports addEventListener or attachEvent, but you'll likely have so many event triggers that it won't be practical. So, I've written two functions do it for you: - /**
-
* Add an event listener to an object
-
* @param object
-
* @param evt event
-
* @param func function
-
* @param capture
-
* @return boolean
-
*/
-
function AddEvent(object, evt, func, capture)
-
{
-
if(typeof func != 'function')
-
{
-
return false;
-
}
-
if(object.addEventListener)
-
{
-
object.addEventListener(evt, func, capture);
-
return true;
-
}
-
else if(object.attachEvent)
-
{
-
object.attachEvent('on' + evt, func);
-
return true;
-
}
-
return false;
-
}
-
-
/**
-
* Removes an event listener
-
* @param object
-
* @param evt event
-
* @param func function
-
* @param capture
-
* @return boolean
-
*/
-
function RemoveEvent(object, evt, func, capture)
-
{
-
if(typeof func != 'function')
-
{
-
return false;
-
}
-
if(object.removeEventListener)
-
{
-
object.removeEventListener(evt, func, capture);
-
return true;
-
}
-
else if(object.detachEvent)
-
{
-
object.detachEvent('on' + evt, func);
-
return true;
-
}
-
return false;
-
}
Here's how to use them: - AddEvent(elem, 'mouseup', SomeFunction, false);
-
RemoveEvent(elem, 'mouseup', SomeFunction, false);
- The first parameter is an element to add the event listener to
- The second parameter is the name of the event (without "on")
- The third parameter is the function (the actual function object with the parentheses)
- The last parameter is a boolean asking determining whether or not to capture the event
This will simplify your code. The only thing that you have to look out for is that even if you set the last parameter to true, it will still bubble in Internet Explorer instead of capture, so you still have to code for bubbling. Those are the breaks.
These functions will return false if neither of these methods are available, but all modern browsers support at least one of these methods, so it's safe to ignore it.
You should keep both of these events in a global JavaScript file that you use in all of your scripts to simplify event handling.
Original Source: Normalizing Event Triggers in JavaScript Normalizing Event Objects in JavaScript
Just like almost everything worth using in JavaScript, Microsoft's Event object and the standard Event object are not the same. Because of this, we'll need to normalize the Event object in order to use it.
For those of you who are unfamiliar with JavaScript's Event objects, they are automatically sent to Function objects that are attached to an event trigger as the first parameter, no matter what you do.
The Event object has a lot of different properties, a lot of which are not cross-browser compatible. Differences consist of: - layerX/layerY and offsetX/offsetY
- relatedTarget and fromElement/toElement
- target and srcElement
- keyCode and charCode
So, I wrote a function to normalize all of these into this variables (respectively): - offsetX/offsetY
- relatedTarget
- src
- key
You can, of course, change the names of the variables in the follow function if you'd like to. Thiss will make it so that you can use event objects without worrying about cross-browser issues. - /**
-
* Gets an event with all needed properties
-
* @param e event
-
* @return event object
-
*/
-
function GetEvent(e)
-
{
-
if(!e)
-
{
-
e = window.event;
-
}
-
-
if(e.layerX)
-
{
-
e.offsetX = e.layerX;
-
e.offsetY = e.layerY;
-
}
-
-
if(e.type == 'mouseover' && !e.relatedTarget)
-
{
-
e.relatedTarget = e.fromElement;
-
}
-
else if(e.type == 'mouseout' && !e.relatedTarget)
-
{
-
e.relatedTarget = e.toElement;
-
}
-
-
e.src = e.srcElement || e.target;
-
e.key = e.keyCode || e.charCode;
-
-
return e;
-
}
Here's how you use it: - function HandleEvent(e)
-
{
-
// Normalize the event
-
e = GetEvent(e);
-
-
// Do stuff with the event object
-
}
And now you can simplify your event handling code by actually changing the event object to be normalized from browser to browser. You should keep this function handy in a file that you include in all of your scripts.
Original Source: Normalizing Event Objects in JavaScript |

February 4th, 2008, 10:56 PM
|  | Member | | Join Date: Feb 2008 Age: 35
Posts: 60
| |
Why not combine the two?
I have added a table of events so that when the event is fired we can convert event data to "uniform" event format, before the event is fired.
If multiple handlers are attached to a single event for a single object then they are called in the order they were added, and a single instance of the event return data exists for all methods. -
var globalthunkingindex = new Array();
-
-
function ThunkingHandlerIndexObject(object, evt, func, capture)
-
{
-
this.object = object;
-
this.event = evt;
-
this.func = new Array();
-
this.func.push(func);
-
-
this.capture = capture;
-
}
-
-
function FindGlobalThunkingEntry(obj, eventtype)
-
{
-
for( var i = 0; i < globalthunkingindex.length; i++)
-
{
-
if( obj == globalthunkingindex[i].object)
-
{
-
// found same object is this event?
-
if( eventtype == globalthunkingindex[i].event)
-
{
-
return i;
-
}
-
}
-
}
-
return -1;
-
}
-
function AddHandlerToGlobalThunkingIndex(object, eventtype, func, capture)
-
{
-
// DH added feb 08
-
var index = FindGlobalThunkingEntry(object, eventtype);
-
if( index < 0 )
-
{ // doesn't exist
-
globalthunkingindex.push( new ThunkingHandlerIndexObject(object, eventtype, func, capture));
-
}
-
else
-
{
-
// does exist, add this function to list
-
globalthunkingindex[index].func.push(func);
-
}
-
/////////////DH
-
}
-
function RemoveHandlerFromGlobalThunkIndex(obj, eventtype, func)
-
{
-
// DH added feb 08
-
var lindex = FindGlobalThunkingEntry(obj, eventtype);
-
if( lindex < 0) return false;
-
-
var lobj = globalthunkingindex[lindex];
-
if( lobj.func.length > 0)
-
{
-
for( var findex = 0; findex < lobj.func.length; findex++)
-
{
-
if( lobj.func[findex] = func)
-
{
-
// this is our func to remove
-
break;
-
}
-
}
-
lobj.func.splice(findex,1);
-
}
-
if( lobj.func.length == 0 )
-
{
-
// list is empty we can remove this node
-
globalthunkingindex.splice(lindex,1);
-
}
-
} /////////////DH
-
-
The previous code was modified to use our event lookup and data normalization. -
/**
-
* Add an event listener to an object
-
* @param object
-
* @param evt event
-
* @param func function
-
* @param capture
-
* @return boolean
-
*/
-
-
-
function AddEvent(object, evt, func, capture)
-
{
-
if(typeof func != 'function')
-
{
-
return false;
-
}
-
// DH added this line
-
AddHandlerToGlobalThunkingIndex(object, evt, func, capture);
-
-
if(object.addEventListener)
-
{
-
/// DH modified from
-
// object.addEventListener(evt, func, capture);
-
// to
-
object.addEventListener(evt, GlobalThunkHandleEvent, capture);
-
-
return true;
-
}
-
else if(object.attachEvent)
-
{
-
/// DH modified from
-
// object.attachEvent('on' + evt, func);
-
// to
-
object.attachEvent('on' + evt, GlobalThunkHandleEvent);
-
-
return true;
-
}
-
return false;
-
}
-
-
/**
-
* Removes an event listener
-
* @param object
-
* @param evt event
-
* @param func function
-
* @param capture
-
* @return boolean
-
*/
-
function RemoveEvent(object, evt, func, capture)
-
{
-
if(typeof func != 'function')
-
{
-
return false;
-
}
-
-
if(object.removeEventListener)
-
{
-
object.removeEventListener(evt, func, capture);
-
-
// DH added this line, must occur after event is unattached
-
RemoveHandlerFromGlobalThunkIndex( object, evt, func);
-
-
return true;
-
}
-
else if(object.detachEvent)
-
{
-
object.detachEvent('on' + evt, func);
-
-
// DH added this line, must occur after event is unattached
-
RemoveHandlerFromGlobalThunkIndex( object, evt, func);
-
-
return true;
-
}
-
return false;
-
}
-
/**
-
* Gets an event with all needed properties
-
* @param e event
-
* @return event object
-
*/
-
function GetEvent(e)
-
{
-
if(!e)
-
{
-
e = window.event;
-
}
-
-
if(e.layerX)
-
{
-
e.offsetX = e.layerX;
-
e.offsetY = e.layerY;
-
}
-
-
if(e.type == 'mouseover' && !e.relatedTarget)
-
{
-
e.relatedTarget = e.fromElement;
-
}
-
else if(e.type == 'mouseout' && !e.relatedTarget)
-
{
-
e.relatedTarget = e.toElement;
-
}
-
-
e.src = e.srcElement || e.target;
-
e.key = e.keyCode || e.charCode;
-
-
return e;
-
}
-
And finally the code that gets it all done: -
function GlobalThunkHandleEvent(e)
-
{
-
// Normalize the event
-
e = GetEvent(e);
-
// locate redirection
-
var index = FindGlobalThunkingEntry(e.src, e.type);
-
// Do stuff with the event object
-
var handlerlist = globalthunkingindex[index].func;
-
-
var IsNotMasked = true;
-
for( var i =0; i < handlerlist.length; i++)
-
{
-
if( handlerlist[i](e) == false )
-
{
-
IsNotMasked = false;
-
}
-
}// note a single instance of event data exists
-
// care must be taken when attempting to mask events
-
//
-
-
// is this IE only?
-
// e.returnValue = IsNotMasked;
-
-
return IsNotMasked;
-
}
-
-
This is by no means optimized. It should be elementary to modify the 2 search algorithms to cut down on the time spent looking. Or add a quick hash.
Happy coding.
Dan -
Last edited by hdanw; February 4th, 2008 at 11:27 PM.
Reason: added masking capabilities
| 
February 4th, 2008, 11:03 PM
|  | Member | | Join Date: Feb 2008 Age: 35
Posts: 60
| | Quote: |
Originally Posted by hdanw Why not combine the two?
I[code]
function GlobalThunkHandleEvent(e)
{
// Normalize the event
e = GetEvent(e);
// locate redirection
var index = FindGlobalThunkingEntry(e.src, e.type); | Sorry I haven't tested this on any other browsers. I am using IE.
My concern would be that the "e.type" in function GlobalThunkHandleEvent(e)
may not be as plain as IE? I don't know. Does any KNow if this becomes something like "on"+"mousemove" as apposed to "mousemove"? If so it can be corrected in "GetEvent".
Thanks.
Dan -
| 
February 7th, 2008, 10:22 AM
|  | Site Moderator | | Join Date: Nov 2006 Location: UK
Posts: 12,980
| | Quote: |
Originally Posted by hdanw My concern would be that the "e.type" in function GlobalThunkHandleEvent(e)
may not be as plain as IE? I don't know. Does any KNow if this becomes something like "on"+"mousemove" as apposed to "mousemove"? If so it can be corrected in "GetEvent". | It would be "mousemove". See this example.
|  | | Thread Tools | Search this Thread | | | |
Posting Rules
| You may not post new threads You may not post replies You may not post attachments You may not edit your posts HTML code is Off | | | | | | What is Bytes?
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 205,414 network members.
|