Created
September 26, 2010 18:55
-
-
Save scottschiller/598208 to your computer and use it in GitHub Desktop.
Somewhat-normalized event listener handling (DOM2)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
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']);
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.
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
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.