Skip to content

Instantly share code, notes, and snippets.

@scottschiller
Created September 26, 2010 18:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scottschiller/598208 to your computer and use it in GitHub Desktop.
Save scottschiller/598208 to your computer and use it in GitHub Desktop.
Somewhat-normalized event listener handling (DOM2)
<html>
<head>
<title>Somewhat-normalized event add/remove</title>
<script>
var addEvent, removeEvent;
(function() {
/*
* Somewhat-normalized event add/remove (old IE/W3C)
* --------------------------------------------------
* W3-style arguments, optional capture
* (default capture param if omitted: false, bubbling)
*
* addEvent(object, eventName, eventHandler, capture*)
* example: addEvent(window, 'load', didLoad);
*
* removeEvent(object, eventName, eventHandler, capture*)
* example: removeEvent(window, 'load', didLoad);
*
* add/remove arguments must be identical to work.
*/
var old = (window.attachEvent), slice = Array.prototype.slice;
evt = {
add: (old?'attachEvent':'addEventListener'),
remove: (old?'detachEvent':'removeEventListener')
};
function getArgs(oArgs) {
var args = slice.call(oArgs), len = args.length;
if (old) {
args[1] = 'on' + args[1]; // prefix
if (len > 3) {
args.pop(); // no capture
}
} else if (len === 3) {
args.push(false);
}
return args;
}
function apply(args, sType) {
var element = args.shift(),
method = [evt[sType]];
if (old) {
element[method](args[0], args[1]);
} else {
element[method].apply(element, args);
}
}
addEvent = function() {
apply(getArgs(arguments), 'add');
};
removeEvent = function() {
apply(getArgs(arguments), 'remove');
};
}());
// ******************************************************************
// * now, assign some example handlers and trigger a bunch of stuff *
// ******************************************************************
var isDown = false;
var counter = 0;
var obj = null;
// each mouse down/up will add and remove its opposite event.
function down() {
isDown = true;
document.getElementById('mouse').innerHTML = (counter++);
addEvent(obj, 'mouseup', up); // watch for release
removeEvent(obj, 'mousedown', down, true);
}
function up() {
isDown = false;
document.getElementById('mouse').innerHTML = (counter++);
addEvent(obj, 'mousedown', down, true); // capture, too
removeEvent(obj, 'mouseup', up);
}
function didLoad() {
obj = (navigator.userAgent.match(/msie/i)?document:window); // IE doesn't like attaching onmousedown/up to window, Safari doesn't like document - and/or I'm simply doing it wrong somehow. :D
if (typeof console != 'undefined' && typeof console.log != 'undefined') {
console.log('window load fired.');
}
up(); // watch for first mousedown() event
}
function cleanup() {
removeEvent(window, 'load', didLoad);
removeEvent(window, 'unload', cleanup);
if (isDown) {
removeEvent(obj, 'mouseup', up);
} else {
removeEvent(obj, 'mousedown', down, true);
}
if (typeof console != 'undefined' && typeof console.log != 'undefined') {
console.log('window unload: events removed');
}
}
addEvent(window, 'load', didLoad); // lazy/convenient: no bubble param, default = false
addEvent(window, 'unload', cleanup);
</script>
</head>
<body>
<div>
<p>Mousedown/mouseup events: <span id="mouse">0</span></p>
</div>
</body>
</html>
@scottschiller
Copy link
Author

My attempt (among countless others, I'm sure) at a compact wrapper for adding and removing event handlers between "old IE" (attach/detachEvent as found in IE 6-8) and everybody else, who uses the proper W3 addEventListener / removeEventListener syntax.

Interestingly, I forgot that you can't call attachEvent.apply() because IE implements the DOM as wacky COM objects, which are not JS native objects.

@TooTallNate
Copy link

Did you try:

Function.prototype.apply.call(attachEvent, thisArg, ["load", function() { //handler }] );

Funky I know, but strangely the same problem applies to apply working with console.log. This workaround works:

Function.prototype.apply.call(console.log, console, ['obj to log']);

@scottschiller
Copy link
Author

Hm! I hadn't thought to try that; interesting. I'll probably just keep it as-is, given it's legacy IE and only takes two arguments.

@scottschiller
Copy link
Author

Interestingly, I found that the apply(this, args) call did not get along with some browsers (IE 9, Safari and Firefox) in certain cases - the change of scope to "this" really seemed to bugger things up and create type errors. Perhaps that breaks assignment of the handler, which expects the scope to be the element the event is assigned from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment