martes, 22 de noviembre de 2011

Javascript: Evento unload

Tomada de:
msdn Library
He pasado un mal rato tratando de descifrar por que el dichoso evento unload, y su respectivo manejador semántico onunload, no funciona como se supone que debería funcionar, y es exactamente ahí donde he errado.

Empecemos por analizar morfológicamente la palabra unload.  Como algunos podrán notar, se compone de un morfema derivativo o prefijo, muy conocido por aquellos adeptos en el lenguaje ingles, es decir el prefijo un-,el cual como se explica acá:


tiene significados de negación, cancelación o revocación de una acción o un estado. Seguidamente, tenemos la segunda parte de la palabra, es decir, load, que significa carga, por lo tanto y sin miedo a equivocarme puedo decir que unload significa descarga, en el sentido que se deshace la última acción de carga.  Se que es un poco complicado de entender, pero hay que aclarar que unload,  tiene un contexto diferente a la palabra download, la cual por falta de tiempo no explicaré ahora.

Cuando se hace referencia al evento unload, estamos hablando de una acción que ya ocurrió, por ese motivo, no puede ser cancelada ni revertida, y es ahí donde muchos nos hemos equivocado.  Y por eso, cuando tenemos un código como el siguiente, en cualquier navegador:
<html>
<head>
<title>Evento al salir de una página</title>
<script type="text/javascript">
    function advertencia () {
        alert("Has salido de mi página\nVuelve pronto.");   
    }

    window.onunload = advertencia;
</script>
</head>

<body>
 <div>
  <p>  
  Con este evento se detecta cuando
  se cierra una página.
  </p>   
 </div>
</body>
</html>


Todas las acciones de la función que llamemos, se ejecutan, pero inevitablemente el contenido de nuestra página se perderá.

En realidad, el evento unload se genera cuando:
  • Se cierra la ventana y/o pestaña
  • Se recarga el contenido de la página
  • Se cambia de página por medio de la barra de direcciones o se selecciona un favorito.
  • Se hace click en algún enlace
Aunque estos son acciones generadas por el usuario, también se pueden generar estos eventos programáticamente (con métodos como: load, close, click), y también por métodos no relacionados, ya que como dije, estos pueden provocar que el contenido de la página se descargue (se pierda), y por lo mismo activará el evento unload.

Hasta este punto, creo que ya se comprende por que el evento unload no puede ser revertido o detenido, y su manejador onunload solo nos permitirá realizar alguna acción neutra, como mostrar un mensaje, pero tampoco será posible detener el evento, por que este ya ocurrió.


Entonces, cual es el truco detrás de:



Esa advertencia que generalmente nos aparece cuando estamos redactando un correo electrónico y accidental o intencionalmente recargamos, cerramos, o nos salimos de la página.

Si, exacto, existe un truco, ya que por más que se busque en la especificación de eventos HTML DOM Level 2 en la página del W3C, no se va a encontrar una respuesta dicente.  

Aclaro que después de un tiempo de estar programando y depurando código javascript, uno aprende a distinguir cuando algo es o no standard, es decir, cuando posiblemente pertenece o no a las especificaciones del w3c, y por eso, anoche cuando me dirigía  hacia mi casa, medio dormido en el taxi, fue que deduje que había un truco.

Este tipo de trucos no estandard, suelen ser creados por alguna casa de software, y si las demás casas de software ven que  es simple, elegante y/o funcional, lo adoptan sin más protocolo, a excepción de un par de rebeldes por ahí, aunque se puede llegar a entender su punto de vista.

En este caso la autoría de este truco se la debemos a Microsoft, y si, yo sé, es raro que de crédito a una casa de software privativo en un blog de software libre, pero lamentablemente para muchos, lo que no es libre es el software, no el conocimiento  (touchè para mí), y más cuando este conocimiento genera ideas que todos podemos implementar y/o aprovechar.  Como dicen por ahí:
"There is no knowledge that is not power."
El que entendió, ¡entendió!.  Bueno, no puedo ser tan obtuso, de todos modos estoy aquí para ayudar a los demás a aprender, y lo que significa esta frase, que difícilmente creo que quienes lean este blog, no la entiendan, es:
"No hay conocimiento que no sea poder."
 o simplemente:
"Todo conocimiento es poder." 
Continuando con mi explicación, he dicho que gracias a Microsoft, se puede tener el comportamiento deseado por el evento unload, pero que semánticamente no le corresponde, y este comportamiento se logra gracias al estado de evento beforeunload, y digo que es un estado, por que en realidad beforeunload, significa antes de la descarga, y como todos sabemos por análisis gramático (léxico y semántico, y puede que morfológico), esto no puede ser clasificado como un evento, aunque en nuestro contexto de programación nos es indiferente.  !Benditas sean la abstracción  y la lógica en todas sus dimensiones!.



beforeunload - onBeforeUnload

El "evento" beforeunload, como se define en msdn:
Se activa justo antes que un documento se descargue.
 y también dice en la documentación original de Microsoft, que para invocar este evento, se llevan a cabo las siguientes acciones, las cuales también desatan el evento unload al ser ejecutadas irreversiblemente:

  • Cerrar la ventana actual
  • Navegar a alguna otra localización, ingresando una nueva dirección o seleccionando un favorito
  • Haciendo click en un enlace, que refiera otra página
  • Invocando el método anchor.click()
  • Invocando el método document.write
  • Invocando el método document.close()
  • Invocando el método window.close()
  • Invocando los eventos window.navigate o navigateAndFind (solo IE)
  • Invocar el método location.replace()
  • Invocar el método location.reload()
  • Especificar un nuevo valor para la propiedad location.href
  • Enviar un formulario a la dirección especificada en el atributo action a través del control input type="submit", o invocar el método form.submit()
  • Invocando el método window.open(), proporcionando el valor opcional _self para el nombre de la ventana.
  • Invocando el método document.open().
  • Haciendo click en los botones Atrás, Adelante, Recargar o Inicio, del navegador.


Manejador de evento: onBeforeUnload


Ejemplo:


<html>
<head>
<script type="text/javascript">
function advertencia()
{
  return "Se perderá todo el contenido de la página actual!";
}
window.onbeforeunload = advertencia;
</script>
</head>
<body>
  <a href="http://librosweb.es/">Click aquí para dirigirse a libros web</a>
</body>
</html>


Ejemplo modificado, tomado de: http://msdn.microsoft.com/en-us/library/ms536907(v=vs.85).aspx

A diferencia de firefox, el texto devuelto con la cláusula return, si se visualiza en los otros navegadores, excepto Opera, que no soporta este evento. El anterior ejemplo, lo pueden ejecutar en cualquier navegador, y se darán cuenta como aparece el mensaje en cada uno.


Espero que esto les ayude a comprender que ciertos comportamientos de los navegadores, no se encuentran documentados en las referencias oficiales, pero que debido a su utilidad es adoptado por varios desarrolladores, para mejorar y/o extender la funcionalidad de la web.


Hasta la próxima.

No hay comentarios:

Publicar un comentario