Actualmente podemos encontrar gran cantidad de librerías que faciliten la utilización del historial del navegador para registrar cambios en el estado de la página, pero ninguna de ellas (o al menos las que yo encontré) logran resolver esta situación.

Si estás perdido y no sabes de que estoy hablando, aquí hay un muy buen artículo (en inglés) que explica en detalle como aplicar la técnica del uso del botón atrás/adelante en aplicaciones AJAX.

Detecté el problema mientras desarrollaba el portfolio de ZedPlan. Al seleccionar un proyecto se actualiza la URL, lo cual hace que mediante una solicitud AJAX se obtengan los datos del mismo y se actualice el documento. También me pareció lógico actualizar el título, ya que sino quedará guardado en el historial del navegador el título del documento oiriginal, y sería poco intuitivo para el usuario.

En ese momento noté que en Firefox el historial no estaba sincronizado con el título del documento actual. ¿Por qué?, parece que si cambiamos el título del documento una vez que se guardó la entrada en el historial, el navegador no lo actualiza y debemos aplicar un pequeño hack, el cual consiste en actualizar el hash de la URL nuevamente de la siguiente forma:

window.location.hash = window.location.hash;

Como era de esperarse, en Internet Exporer 6 y 7 tenemos otro problema. Para ver reflejado en el historial el título del documento, debemos cambiarlo en el iframe que se usa como hack, ya que se extrae de la etiqueta <title>. Para esto, al src del iframe le enviamos como parámetro el título del documento junto con el hash. El truco acá es cambiar el título antes de actualizar el iframe, ya que si lo cambiamos con javascript no se va a ver reflejado el cambio en el historial.

Veamos un ejemplo usando la clase HistoryManager, la cual desarrollé hace unos meses y la modifiqué para agregar soporte a los títulos dinámicos. Requiere al framework Prototype, aunque con pocas modificaciones se podría adaptar a otros frameworks como jQuery.

Supongamos que tenemos una página donde tenemos contenido agrupado en tabs, según el tab seleccionado mostramos u ocultamos lo que corresponda, pero guardando en el historial cada cambio de tab para permitir bookmarking.
Al cargar la página ejecutamos la función init():

function init() {
	hm = new HistoryManager(
			update, // callback
			200, 	// intervalo en milisegundos para revisar cambios en el hash
			'/history.php', // URL del documento que se usa como hack para el IE (abajo está el codigo fuente)
			true // habilitar títulos dinámicos, asi debemos llamar manualmente al metodo setTitle() en la función update()
		);
}
/**
 * Esta función se ejecuta cuando hubo cambios en el hash.
 * @param string nuevo hash
 * @param string hash anterior
 */
function update(hash, prev) {
	 // si no hay ni hubo hash no hacemos nada en este caso.
	if (!hash && !prev) return;

	// en este caso el contenido que generamos depende de un id, el cual lo obtenemos del hash
	// por ejemplo, si queremos mostrar un contenido u otro dependiendo de un tab seleccionado
	// el formato del hash podría ser "#tab-1" o "#tab-2"
	var id = hash.split('-').last();

	// establecemos el titulo del documento segun el nuevo contenido
	// acá lo sabemos de antemano, pero sería mas común obtenerlo mediante AJAX segun el id
	if (hash) this.setTitle("Tab " + id); // debería ser mas descriptivo el título!
	else this.setTitle("Home"); // si no hay hash, reestablecemos el titulo original
}

Y el código fuente de history.php

<?
	$hash = json_encode(isset($_GET['hash']) ? $_GET['hash'] : '');
	$title = isset($_GET['title']) ? $_GET['title'] : '';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title><?=htmlspecialchars($title)?></title>
	<meta name="robots" content="noindex, nofollow" />
	<script type="text/javascript">/*<![CDATA[*/
		hash = <?=$hash?>;
		function update() {
			if (!parent) return;
			parent.location.hash = hash;
		}
	/*]]>*/</script>
</head>
<body onload="update()"></body>
</html>

Esta clase fué probada en Firefox 3, IE 6 & 7, Chrome, Safari 4 para Windows y Opera 9.64.

Share