HTML5 localStorage y JSON para dotar de persistencia a una Extensión de Chrome

Uno de los problemas a la hora de trabajar con Javascript+HTML que se ha tenido siempre es cómo almacenar información persistente de la aplicación que hemos creado en el navegador. Javascript fue concebido principalmente para manejar el árbol DOM y hacer modificaciones en la interfaz de usuario para hacerla más atractiva, de donde surgió aquel término llamado DHTML (Dynamic HTML). La tendencia actual es a crear aplicaciones autónomas en el navegador, tan potentes como las tradicionales aplicaciones ejecutables en un sistema operativo pero dentro del navegador, gracias a la aparición de nuevas funcionalidades, como las llamadas asíncrontas y sobre todo a la optimización de los motores de ejecución de Javascript en los navegadores, que se convierten en máquinas virtuales potentes sobre las que ejecutar scripts, con los benficios de la interfaz de HTML.

Como decía, uno de los problemas es dotar de más autonomía a la aplicación escrita en Javascript+HTML, y esto suele pasar por disponer de algún mecanismo de persistencia que permita almacenar la información del usuario para que la próxima vez disponga de la misma configuración o datos históricos. Antes de HTML5 se empleaban algunas técnicas como el uso de cookies para estas labores; o el método más correcto de tener un servidor de aplicaciones con un perfil de usuario en el que se almacena la información en remoto, pero esto requiere de conexión a Internet y de una infraestructura de servidor que realice esta tarea, con el coste que ello tiene.

Sin embargo, desde la aparición de HTML5 y de los navegadores que implementan esta especificación, podemos usar una de sus muchas ventajas: el almacenamiento local o localStorage.

Mediante localStorage podremos almacenar en el espacio que nos proporciona el navegador pares de atributos “string”,”string” hasta un máximo de 5 megas de espacio (las limitaciones a cadenas de texto y almacenamiento corresponden a la implementación que hacen los navegadores actuales de HTML5). De este modo podremos almacenar y recuperar estos valores en cualquier momento en nuestro código Javascript.

Para almacenar una cadena de texto en una variable procederemos esta forma:

localStorage.setItem("mivariable","mivalor");
//o lo que es lo mismo:
localStorage.mivariable = "mivalor";

La lectura del valor sigue el procedimiento esperado:

var valor = localStorage.getItem("mivariable");
//o lo que es lo mismo:
var valor = localStorage.mivariable;

La información permanecerá en localStorage de manera persistente y fiable, de modo que podemos apoyarnos en ella para almacenar datos como la configuración de la aplicación o información histórica el usuario.

A continuación se va a emplear localStorage de Chrome para ampliar la extensión básica que se creó en el post https://mysticalpotato.wordpress.com/2011/01/15/extension-sencilla-para-google-chrome/, de modo que se almacena el histórico del tiempo de uso. El resultado de esta modificación se corresponde con la versión 0.3 de la extensión, que puede descargarse en https://chrome.google.com/extensions/detail/lkhahcnmgjhbbdkieijbndecclgcibjp?hl=en#

Para almacenar el histórico de tiempo necesitamos conocer qué valores tenemos que almacenar y cuando. Necesitamos conocer el tiempo de inicio y el de final en cada sesión, que se encuentran en formato de milisegundos en la página background.html, que si se revisa el post anterior de la extensión, se verá que se carga cuando la extensión comienza la ejecución. De este modo el par de datos (inicio, fin), nos dará el tiempo de inicio y el tiempo que ha durado la sesión (fin-inicio). Están en formato Date, que se transforma a milisegundos desde el 1 de enero de 1970, para poder localizarlo con precisión en el tiempo. El resultado del almacenamiento es por lo tanto un array de pares de tiempo.

En primer lugar debemos crear un objeto en Javascript que modele este tiempo:

//Time object
function tiempo (inicio, fin)
{
	this.inicio = inicio;
	this.fin = fin;
}

Lo que queremos almacenar por lo tanto será un array de objetos tiempo. El problema radica ahora en encontrar la forma de transformar el array de tiempo a una cadena de texto y viceversa. El mejor método es hacer uso de JSON. En post anteriores se ha podido ver cómo emplear JQuery y algunas librerías especiales para manejar este tipo de objetos. En esta ocasión usaremos métodos nativos del navegador Chrome. La explicación es que la extensión es específica de Chrome, y tenemos la certeza absoluta de que el usuario dispone de este requisito para correr la app.

Almacenaremos una String de este tipo, que contiene un array de objetos tiempo en formato JSON:

[{"inicio":1295726332072,"fin":1295726339310},{"inicio":1295726339311,"fin":1295726527498},{"inicio":1295726527501,"fin":1295727082467}]

Suponiendo que en tiempo_instancia tenemos un objeto “tiempo” correctamente formado, su transformación a JSON es sencilla:

JSON.stringify( tiempo_instancia );

El problema está en cuándo realizar el almacenamiento de la información: cuando se cierra el navegador o se desactiva la extensión. Estos dos eventos tienen en común que el cierre de background.html, de manera que se puede capturar el evento y llamar a una función:

 //Event when extension closes.
window.onunload =
	function () {
	guardaEstadisticas();
};

Efectivamente, cuando se cierra la extensión o se cierra el navegador se llama a la función guardaEstadisticas(). Ésta se encarga de almacenar el objeto tiempo de la sesión actual, lo que significa encontrarse frente a dos situaciones: que no exista ningún valor anterior o que ya haya un array con uno o varios valores previos. En el primer caso habrá que añadir los corchetes “[]” para indicar que es un array de un sólo elemento. En el segundo caso habrá que recuperar el array , transformándolo desde JSON a array de objetos de Javascript, hacer un push para añadir el último objeto al array y volver a pasarlo a cadena de texto en formato JSON:

function guardaEstadisticas()
{
	//When extension ends, adds the time it's been used
	var tiempo_instancia= new tiempo(tiempo_inicio.valueOf(), (new Date()).valueOf());
	if(!localStorage.COT_history) //first time 
	{
		localStorage.COT_history = "[" + JSON.stringify( tiempo_instancia ) + "]";
	}
	else  //there was some data before
	{
		var historia = JSON.parse(localStorage.COT_history);
		historia.push(tiempo_instancia);
		localStorage.COT_history = JSON.stringify(historia);
		console.log("Añadido:" + JSON.stringify(historia));
	}
}

Como se puede comprobar, pasar de String en formato JSON a array de objetos se puede hacer a través del método JSON.parse que provee Javascript de Chrome. La comprobación de si existe registro anterior es sencilla: if(!localStorage.COT_history) . Como se puede ver, se ha elegido la clave COT_history para llamar a esa variable en el almacenamiento del navegador.

Otro aspecto es cómo se muestran las estadísticas. En este caso he empleado una página nueva llamada history.html enlazara con un enlace normal desde popup.html. Se encarga de recuperar la información del localStorage, pasarla de JSON a array de objetos tiempo y mostrarla mediante un bucle en una tabla, con la particularidad que muestra los tiempos en modo descendiente hasta un máximo de 15 tiempos.

function pintaEstadisticas()
{
	var tiempos = JSON.parse(localStorage.COT_history);
	var salida = "<table><thead><tr><td>Start Time</td><td>Opened for</td></tr></thead><tbody>";
	var limite = Math.max (tiempos.length-15, 0 );
	for (i = tiempos.length-1;i>=limite;i--)
	{
		salida = salida + "<tr><td>";
		salida = salida + (new Date(Number(tiempos[i].inicio))).toString().substr(0,24);
		salida = salida +"</td><td>" + formatTime(Number(tiempos[i].fin)-Number(tiempos[i].inicio));
		salida = salida + "</td></tr>";
	}
	salida = salida + "</tbody></table>";

	document.write(salida);
}

El resultado es:

Finalmente existe la posibilidad de borrar las estadísticas, que no es otra cosa que borrar la información que corresponde a la clave local “COT_history”. Para ello se ha incluido un enlace en history.html que lanza una función que realiza el reset del almacenamiento:

function clear_stats()
{
	localStorage.COT_uses = 1;
	localStorage.removeItem("COT_history");
	window.location.reload()

	return null;
}

Para concluir, podemos ir a la ventana de extensiones pulsando en la llave de opciones de Chrome -> tools -> extensions y activar el “developer modo”, ir a la extensión y pulsar sobre el enlace background.html. Aparecerá la ventaja de inspección (en cualquier página pulsando Ctrl+Shift+j). Pulsando sobre el icono Storage (3º por la derecha) podremos ver los datos del localStorage.

El resultado de este post y otras modificaciones más dieron lugar a la version 0.3 de la aplicación, que puede verse aquí: https://chrome.google.com/extensions/detail/lkhahcnmgjhbbdkieijbndecclgcibjp?hl=en#

Adjunto el zip de la extensión. OJO: RENOMBRAR A .ZIP

Anuncios

2 comments

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s