You are probably starting to get used to that Mozilla is the browser with the best standard support (as I write this at least). This is true when it comes to the event model as well. (Even if the standard are not good enough for the real world).
The standard way to add and remove event listeners is to use the methods
addEventListener and removeEventListener. These methods
takes 3 arguments. The first one is the type of the event. The second is a function
taking one argument and that is the Event object. The last argument tells whether to use
capture for the event. We will get back to capturing in a later article.
element.addEventListener("click", onClick, false);
element.removeEventListener("click", onClick, false);
function onClick(e) {
// ...
}
This is the IE5 proprietary way of adding event listeners. It differs in several small
ways but these will not stop us from adding support for it in Mozilla. The first difference
is that the first argument is not the type of the event but the string
"on" plus the type. The second argument is a funtion like before but with
one crucial difference. The function does not take any arguments. The event object is
instead bound to the window that the event was triggered in. This is a bad design decision
by Microsoft but we just have to live with it :-(. The attacEvent (and
detachEvent) only takes two arguments so there is no way to tell whether to
use capturing or not. All events use bubbling only.
element.attachEvent("onclick", onClick);
element.detachEvent("onclick", onClick);
function onClick() {
var e = window.event; // will not work if code and event
// reside in different frames
// ...
}
First we extend the prototype of HTMLElement with the two methods.
The thing to do for both methods is to remove the "on" at the beginning of the
type. Then we add a new function as a listener using addEventListener.
Inside that function we bind the event object to window.event and
finally we call the real function.
HTMLElement.prototype.attachEvent = function (sType, fHandler) {
var shortTypeName = sType.replace(/on/, "");
this.addEventListener(shortTypeName, function (e) {
window.event = e;
return fHandler();
}, false);
};
This code would be enough if we did not want detachEvent to work.
The problem is that to be able to remove the event listener we need the function object
to remove. Therefore we bind the new anonymous function as an expando property on
the original function object.
HTMLElement.prototype.attachEvent = function (sType, fHandler) {
var shortTypeName = sType.replace(/on/, "");
fHandler._ieEmuEventHandler = function (e) {
window.event = e;
return fHandler();
};
this.addEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
};
HTMLElement.prototype.detachEvent = function (sType, fHandler) {
var shortTypeName = sType.replace(/on/, "");
if (typeof fHandler._ieEmuEventHandler == "function")
this.removeEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
else // we can always try :-)
this.removeEventListener(shortTypeName, fHandler, true);
};
To allow Mozilla to support attachEvent and detachEvent
you need to include the ie emu file as well as call a function called
emulateAttachEvent.
<script type="text/javascript" src="ieemu.js"></script>
<script type="text/javascript">
if (moz) {
emulateAttachEvent();
}
</script>
The reason why it has been done in this way is fairly simple. It allows you to define what emulations you need in your page.
Introduction
The power of JS
Event Listeners
Classic Event Handlers
Event Object
InnerHTML Model
Element Model
Document All Model
Current Style Model
???