Archive for the 'Dedos de acero' Category

Botón ‘atrás’ y hashes de dirección con AJAX

Páginas como Gmail, Facebook o Tuenti usan el modelo ‘hash’ en las URL. Por ejemplo, la siguiente URL:

http://www.tuenti.com/#m=Search&func=view_friends_page&job=243354

Lleva a una búsqueda en Tuenti. Sin embargo, el contenido después de # en la URL no se envía al servidor, puesto que se trata de un ‘hash’ de URL. Este contenido sí que es accesible mediante JavaScript, usando la variable window.location.hash.

Tiene dos grandes ventajas al usarlo junto con AJAX: por una parte, funciona el botón de retroceso (“atrás”) aunque la aplicación esté basada en AJAX (esto depende la implementación, claro). Por otra parte, se puede ‘compartir’ el enlace, de tal forma que aunque sea una consulta inicialmente lanzada por AJAX, se pueda reproducir al entrar en el mismo enlace (con el mismo hash).

He programado un pequeño ejemplo, disponible aquí. Es muy sencillo, aunque todo está bien explicado en el propio código (sólo que en inglés). El archivo de funciones JavaScript (igual de importante que el la serie de capas que contiene la página) está aquí.

El principio “simplificado es el siguiente”:

  1. El usuario accede a la página
  2. Se incluye la función ‘launch()’ mediante jQuery a los eventos a ejecutar una vez se haya cargado el DOM
  3. Esta función simplemente ‘lanza’ la carga de la primera página, según tenga o no hash.
  4. La función ‘load_page()’ se ejecuta y carga el contenido. Al mismo tiempo crea un ‘timeout’ con la función ‘verify_hash()’, que ‘vigila’ el hash para detectar cambios.
  5. La función ‘verify_hash()’ crea a su vez otro timeout que llama a la misma función. En caso de que el hash haya cambiado, lanza ‘load_page()’, de la misma forma que hace ‘launch()’.

El ejemplo dado también incluye un timer de ‘timeout’ (en caso de que se ‘cuelgue’ la petición AJAX), una serie de capas de ‘Loading’ y comprueba que el usuario tenga JavaScript activado (en el caso contrario, sólo ve un mensaje alertando de la necesidad de tener JavaScript activado, sin dejar trazas de la aplicación).

Si se carga el hash #m=1&abc=2, la consulta AJAX (siempre GET) será a ./pageloader?m=1&abc=2, incluyendo siempre como GET el contenido del hash. De la misma forma, se pueden incluir enlaces con hashes (se lanza la consulta AJAX al clickearlos) y el botón de retroceso funciona sin problemas.

Intenté poner una función que lanzase automáticamente el cambio de página sin esperar al intervalo de comprobación (al hacer click en un enlace), sin embargo generaba conflictos con los timers. De cualquier manera, la diferencia de tiempo entre el click y la petición AJAX no es muy grande.

El ejemplo aquí y el script aquí. No olvidarse de mirar los comentarios del código ;-) .

PHP: estirar el objeto

No, nada. Es un maldito título no-creativo. En realidad yo venía a hablar de mi libro a hablar del tema de extensión infinita de objetos clases. En algunos lenguajes de programación se pueden crear objetos e ir extendiéndolos hasta el infinito y más allá, no es el caso de PHP.

Por poner un ejemplo: si tenemos una clase que es AllTheApplication, es posible que queramos que herede las clases ApplicationRenderPage y ApplicationDatabase, algo como:

class ApplicationRenderPage {}
class ApplicationDatabase {}
class AllTheApplication extends ApplicationRenderPage, ApplicationDatabase {}

Sin embargo, esto no está (todavía) disponible en PHP por lo que nos dará un error. Eso no significa que no se puedan hereder cualidades de un objeto en tercer grado:

class ApplicationRenderPage {}
class ApplicationDatabase extends ApplicationRenderPage {}
class AllTheApplication extends ApplicationDatabase {}

En este último caso, AllTheAplication podría manejar también funciones y variables no protegidas tanto de ApplicationRenderPage como de ApplicationDatabase. Voilà!

Y una pequeña nota: aunque esto sea de cierta forma una solución posible, estoy casi seguro de que hay formas más consistentes de hacerlo, puesto que en este caso las clases se van extendiendo una a otra, de cierta forma ‘en anillo’ con lo que conlleva al hacer cambios en la estructura. Recomendaría algo parecido a:

class ApplicationRenderPage {}
class ApplicationDatabase {}
class AllTheApplication { function __construct() { $this->ApplicationDatabase = new ApplicationDatabase; $this->ApplicationRenderPage = new ApplicationRenderPage; } }

Así, basta con inicializar el objeto ($Application = new AllTheApplication) y de ahí acceder a los subobjetos (echo $Application->ApplicationDatabase->QueryCount si tenemos una variable que se llame QueryCount dentro del objeto ApplicationDatabase inicializado desde el construct de AllTheApplication). Ojo, no es oro todo lo que reluce y en este caso no se pueden acceder a las variables entre los distintos objetos (quizás usando parent::ApplicationDatabase, aunque no sé demasiado como se comportaría).

Y esto, señores, es una chuleta.

Light Framework

Con Linkloo empecé un desarrollo de una “plataforma” sobre la cual desarrollar. Es necesario, puesto que es una aplicación muy grande y compleja, y la desorganización del código me llevó a reprogramarlo desde cero. Cuando re-hice Fileclick también le hice una “plataforma” y junto con Rubén en Jisko hicimos lo mismo – adaptado al proyecto, claro.

Esta estructura de la que hablo se basa sobre varios ejes de necesidades (al desarrollar):

  • URLs limpias, “tipo Rails”
  • MySQL sencillo y extendido
  • Templating sencillo: además se introduce al final del renderizado, en Jisko fue muy útil para establecer el titulo de la página desde cualquier parte del código.
  • Organización (por librerías, que puedan ser propias e importarlas al vuelo)

Obviamente hay más detalles, pero eso es lo básico y que toca desarrollar a cada nuevo proyecto (y la experiencia hace que cada vez sea algo más refinado).

He escrito un PDF (en un Inglés muy cutre, por cierto) en el cual resumo esto. Podéis descargarlo aquí.

El código está completamente desarrollado, queda escribir toda la documentación (y seguramente retocar algo).