Las diferencias existentes entre los navegadores disponibles en la actualidad complican en exceso el desarrollo de aplicaciones compatibles con todos los navegadores, llamadas aplicaciones "cross browser" en inglés.
Por ese motivo, se va a diseñar una utilidad que permit unificar la asociación/desasociación de manejadores de eventos, la obtención del objeto event y todas sus propiedades. La utilidad que se muestra se ha obtenido del excelente libro "Professional JavaScript for Web Developers", escrito por Nicholas C. Zakas y publicado por la editorial Wrox.
En primer lugar, se crea el objeto que va a englobar todas las propiedades y métodos relacionados con los eventos:
var EventUtil = new Object();
El primer método relacionado con los eventos que es necesario estandarizar es el de la asignación y eliminación de manejadores de eventos:
EventUtil.addEventHandler = function(elemento, tipoEvento, funcion) { if(elemento.addEventListener) { // navegadores DOM elemento.addEventListener(tipoEvento, funcion, false); } else if(elemento.attachEvent) { // Internet Explorer elemento.attachEvent("on"+tipoEvento, funcion); } else { // resto de navegadores elemento["on"+tipoEvento] = funcion; } }; EventUtil.removeEventHandler = function(elemento, tipoEvento, funcion) { if(elemento.removeEventListener) { // navegadores DOM elemento.removeEventListener(tipoEvento, funcion, false); } else if(elemento.detachEvent) { // Internet Explorer elemento.detachEvent("on"+tipoEvento, funcion); } else { // resto de navegadores elemento["on"+tipoEvento] = null; } };
Para obtener el objeto event
, se crea un nuevo método en la utilidad llamado getEvent()
:
EventUtil.getEvent = function() { if(window.event) { // Internet Explorer return this.formatEvent(window.event); } else { // navegadores DOM return EventUtil.getEvent.caller.arguments[0]; } };
El método getEvent()
es un método que no acepta parámetros y que devuelve el objeto event
convenientemente adaptado para permitir un comportamiento homogéneo entre diferentes navegadores.
En el caso de Internet Explorer, el objeto event
se obtiene directamente a partir del objeto window
. Sin embargo, antes de devolver el objeto, se modifica añadiendo las propiedades que no dispone en comparación con el objeto event
de los navegadores DOM.
En el caso de los navegadores DOM, el objeto event
se obtiene como el primer argumento de la función que actúa como manejador del evento. Como ya se vio en el capítulo de JavaScript básico, la propiedad caller
de una función siempre almacena una referencia a la función que la invocó.
Así, si en el interior de un manejador de eventos se hace la llamada al método EventUtil.getEvent()
, la propiedad caller
será el propio manejador de eventos y su primer argumento será el objeto event
. Parece muy abstracto, pero si se piensa detenidamente se comprende fácilmente la solución tan concisa y elegante que se ha utilizado.
El objeto event
presenta unas propiedades y métodos muy diferentes en función del tipo de navegador en el que se ejecuta la aplicación JavaScript. Para estandarizar el objeto event
, se crea un método que añade al objeto event
de Internet Explorer todas las propiedades que le faltan.
El código completo de este método se muestra a continuación:
EventUtil.formatEvent = function(elEvento) { // Detectar si el navegador actual es Internet Explorer var esIE = navigator.userAgent.toLowerCase().indexOf('msie')!=-1; if(esIE) { elEvento.charCode = (elEvento.type=="keypress") ? elEvento.keyCode : 0; elEvento.eventPhase = 2; elEvento.isChar = (elEvento.charCode > 0); elEvento.pageX = elEvento.clientX + document.body.scrollLeft; elEvento.pageY = elEvento.clientY + document.body.scrollTop; elEvento.preventDefault = function() { this.returnValue = false; }; if(elEvento.type == "mouseout") { elEvento.relatedTarget = elEvento.toElement; } else if(elEvento.type == "mouseover") { elEvento.relatedTarget = elEvento.fromElement } elEvento.stopPropagation = function() { this.cancelBubble = true; }; elEvento.target = elEvento.srcElement; elEvento.time = (new Date).getTime(); } return elEvento; }