2015

Esta vez toca un post personal porque voy a empezar una tradición (quizás la más corta jamás vista): escribir los propósitos de año nuevo, valorando los del año anterior y definiendo los del siguiente de manera pública para que haya un poco más de presión para conseguirlos.

Como resumen, en lo personal ha sido un buen año: ha empezado la época de creación de familias a mi alrededor con bodas de amiguetes y los primeros niños, … He podido viajar, sobre todo por España y un buen viaje por París. En el otro lado de la balanza, sigue la fuga de gente a otros países (aunque este año ya ha sido más leve) y no he estado todo lo que me gustaría con la familia y amigos.

En lo profesional, lo de los últimos años, pero con nuevos retos y empezando con Node y Meteor. He pasado casi un año entero sin tener un proyecto paralelo (impresionante!!) aunque por supuesto, han habido muchas proposiciones, uno que sí he aceptado y que espero lanzar pronto.

Como es la primera vez y no hay propósitos del año anterior, toca hacer memoria y diría que este año había 3 propósitos principales:

  • bajar de los 100Kg: (fracaso) simplemente no he hecho nada y ahora mismo peso 113Kg
  • mejorar en inglés: (en proceso) desde septiembre y estoy dando clases por Skype con un John, un profesor Inglés que encontré gracias a Blabelia (os lo recomiendo si buscáis un profesor de idiomas)
  • empezar con Node.js: (conseguido) Esto empezó en serio desde enero cuando hice un curso de varias semanas después de trabajar en redradix (si os queréis formar en JS y vivís en Madrid, no lo dudéis. Y si vivís en otro lugar, mirad los cursos sobre JS de Udacity, os garantizo que el 80% de los que programan en JS no dominan lo que se aprende ahí). Y continuó con el descubrimiento de Meteor… y ya es una historia de amor que (espero) vaya para largo ;)

Para 2016 no voy a decir propósitos, no creo en ellos, porque no se pueden medir. Lo que voy a poner son las acciones/hábitos/logros del 2016:

  • bajar de los 100Kg: hacer deporte 3 dias por semana y seguir andando todos los días una hora. Actualmente solo hago deporte un dia y obviamente no es suficiente. Perder dos kilos al mes me parece una buena forma de medida.
  • inglés: seguir con las clases con John y empezar con alguien americano. El objetivo debe ser poder trabajar en remoto en inglés a final de año. Siguiendo con las 2 o 3 clases semanales actuales, se puede conseguir.
  • trabajar mayoritariamente con Node.js: aquí las acciones ya son más difíciles de definir. Ya se que no definir bien un objetivo es el camino más rápido a no cumplirlo, pero …
  • volver a escribir en el blog: con un post al mes, me doy por satisfecho
  • seguir intentando crear un producto mío que me de para vivir

Y para nota:

  • trabajar en remoto o con horarios muy flexibles para compaginar mejor vida personal y profesional
  • trabajar con meteor

Atributos privados en objectos Javascript

Quizás alguien te haya contado que ciertas cosas no se pueden hacer en Javascript, por ejemplo tener atributos privados. Pero gracias a las closures, podemos crear atributos privados en Javascript.

Veamos un ejemplo simple, donde creamos un objeto Persona con dos atributos, nombre (público) y edad (privado):

function Persona (nombre, edad){
	this.nombre = nombre;
	var edad_ = edad;

  this.getEdad = function() {
    return edad_;
  }

  this.setEdad = function(edad) {
    edad_ = edad;
  }
};

Persona.prototype.presentate = function(){
	return 'Nombre: ' + this.nombre + ' | Edad: ' + this.getEdad();
};

Si utilizamos el objeto:

var persona = new Persona('Simon', 28);
console.log(persona); //no vemos el atributo edad_
persona.presentate(); // devolverá: "Nombre: Simon | Edad: 28"

Parece que efectivamente, edad_ ha guardado su valor, pero ¿podremos acceder al atributo?

persona.nombre; //devuelve "Simon" 
persona.edad_; // devuelve undefined

Como buen atributo privado, solo podemos acceder a él desde dentro del propio objeto y no desde fuera. Para poder modificar nuestro atributo edad_, usaremos el método setEdad();

persona.setEdad(30);
persona.presentate(); //"Nombre: Simon | Edad: 30"

Y de la misma manera podremos crear métodos privados. Si quisiésemos tener atributos de tipo “Private” y “Protected”, tendríamos que entrar en más detalle, pero como idea inicial creo que es un buen ejemplo.

Si no terminas de ver claro el código, échale un ojo a este artículo de la MDN sobre las Closures

Autenticación personalizada con meteor

meteor-logo

Aunque meteor ofrece la posibilidad extremadamente simple de crear un sistema completo de autenticación instalando dos paquetes, accounts-password y accounts-ui, tiene dos inconvenientes claros: al ser tan simple, mucha gente la utiliza nada más comenzar desarrollado con meteor y puede dar a tu app una imagen “poco trabajada” o de “app beta” y por otro lado, no te permite configurar muchos de los elementos, lo que hace que estés “atado” a una solución que quizás no sea la ideal para tu app.

Por ello, me he creado el clásico proyecto “startup” o base, con mi propio sistema de autenticación y algunos detalles más para poder empezar a trabajar sobre él:

  • el registro y el login están en popups accesibles desde cualquier página de la app. De esta manera evitas temas de redirección después del registro/login del usuario
  • registro en dos pasos con sus respectivos emails
  • primeras configuraciones de rutas, incluyendo las rutas privadas de usuario autenticado
  • sistema (cutre) de notificación

Puedes probar la demo en customauth.meteor.com y descargarte el código en gitHub. No dudes en comentarme lo que te apetezca, será bien recibido. Necesitas instalar los siguientes paquetes:

  • meteor add accounts-password
  • meteor add iron:router
  • meteor add twbs:bootstrap
  • meteor add jquery

Poco a poco iré escribiendo más sobre meteor (eso espero!), ya que apenas hay documentación en español (incluido un pequeño tutorial sobre las 3 cositas que hace este sistema). Os dejo unos pantallazos del resultado:

La home:

El popup de registro
El usuario autenticado, justo después de verificar su email
Y el popup de login

 

Recordatorio: truncar textos con CSS

Esta es la típica cuestión que tengo que mirar en Google una y otra vez porque soy incapaz de memorizarla, así que la escribo aquí a ver si por fin se me queda grabado…

En muchas situaciones, por ejemplo cuando desarrollamos para diferentes dispositivos, suele haber problemas con las longitudes de los textos. Este es el truquito para que aparezcan los puntos suspensivos:

 {white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}

Gmail ha decidido bloquear mis mails…

Por problemas con spam de una de las web que tengo en mi servidor, mi servidor ha terminado viéndose señalado por Google como un spamer, lo que ha llevado a que ninguno de las webs del servidor podía enviar un mail a Gmail. Y eso que muchos cuentan con los certificados DKIM y SPF.

Consultando los logs, el error tenía una pinta como la siguiente:

Aug 1 13:47:32 XXX postfix/smtp[6473]: XXXX: to=XXX@gmail.com, relay=gmail-smtp-in.l.google.com[173.194.67.26]:25, delay=1.1, delays=0.4/0.11/0.16/0.42, dsn=5.7.1, status=bounced (host gmail-smtp-in.l.google.com[173.194.67.26] said: 550-5.7.1 [XXX.XXX.XXX.XXX] Our system has detected that this message is 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail, 550-5.7.1 this message has been blocked. Please visit 550-5.7.1 http://support.google.com/mail/bin/answer.py?hl=en&answer=188131 for 550 5.7.1 more information. a19si1537658wiw.32 – gsmtp (in reply to end of DATA command))

Después de visitar la web de Google que indica el error y de googlear todo lo que se me ha ocurrido, no he sacado nada en claro, salvo un recordatorio de lo que son los DKIM y SPF. Así que después de asegurarme de que en mi servidor no se genera SPAM y sabiendo que de los DKIM no hay mucho que se pueda sacar (son las firmas que son), me he planteado revisar los SPF a los que personalmente nunca les había dedicado más tiempo del que se tarda en copiar en los DNS lo que te recomienda Google Apps o Outlook para dominios.

Resulta que tanto Google Apps como Outlook para dominios, te dan un SPF como los siguientes:

Google Apps: v=spf1 include:_spf.google.com ~all

Outlook para dominios: v=spf1 include:hotmail.com ~all

Esto significa básicamente que son SPF de versión 1, que valide los mails que vienen de google.com o hotmail.com y que rechace los demás. Esto ha sido lo que me ha llamado la atención. Así que he pensado: “bueno, si pudiera añadir la IP de mi servidor, solucionado”. Y así ha sido. Tras pasar por una herramienta onine para estos menesteres, he visto que solo tenía que añadir una simple “a” a los SPF que ya tenía:

Google Apps: v=spf1 a include:_spf.google.com ~all

Outlook para dominios: v=spf1 a include:hotmail.com ~all

Lo que significa esa letra, es que también se valide la IP que marca el registro A de los DNS, es decir, la IP de mi servidor.

Precarga y caché de páginas con jQueryMobile

Regreso al futuo

En general, cuando utilizamos jQueryMobile es conveniente no sobrecargar los archivos HTML con gran cantidad de páginas para hacer el DOM más liviano y por lo tanto, mejorar el rendimiento.

Esto no significa que no puedas poner algunas en un solo archivo, a lo que me refiero es que si tu app tiene 50 páginas, no es recomendable ponerlo todo en un solo HTML. No solo por la carga excesiva a la que vas a someter al teléfono o tablet con la merma de rendimiento que lleva asociado, sino también por una cuestión de limpieza y mantenimiento del código.

Precarga

Si ya actúas de esta manera, ahora el siguiente paso es aprovechar la funcionalidad de precarga de páginas jQueryMobile. Para ello, simplemente tienes que utilizar el atributo data-prefetch en tus enlaces:

<a href="precarga.html" data-prefetch>Precarga está página</a>

Con este método, lo que haces es precargar todos los elementos del archivo precarga.html cuando termine de cargarse el archivo actual, por lo que por un lado no ralentiza la página actual y por otro mejora el rendimiento al visitar la siguiente página.

Ni que decir tiene, que esto no tiene sentido entre las propias páginas de un mismo archivo HTML, puesto que ya están cargadas en el DOM.

Caché

El siguiente paso, es utilizar el caché de jQueryMobile. Las páginas que ya has visitado, se pueden guardar en caché mediante el atributo data-dom-cache=”true” De esta manera, cuando vuelvas a visitarlas se cargarán instantáneamente. Su uso es simple:

<div data-role="page" id="cacheame" data-dom-cache="true">

Ojo con el uso excesivo de esto, ya que si cacheamos las 50 páginas de nuestra app, volveremos a tener el problema del que hablaba al principio y en vez de mejorar el rendimiento de nuestra app, lo empeoraremos.

Esto son solo dos formas de mejorar el rendimiento de nuestras apps que nos ofrece jQueryMobile, pero realmente, el sentido común es la mejor forma ;)

Multiidioma en Codeigniter

i18n

CodeIgniter no trae por defecto un buen soporte para multiidioma y si quieres añadirlo recomiendan utilizar el paquete de internacionalización i18n. Pero este paquete no es de mi agrado, por dos razones.

La primera es que te fuerzan a cambiar tus url al tipo:

  • http://tuproyecto/es/…
  • http://tuproyecto/en/…

Y por supuesto, esta solución tiene que hacer uso del archivo routes, que modifica las rutas de los controladores, lo que para mi es una verdadera fuente de problemas.

Como googleando no he encontrado nada nuevo, he tenido que crear un pequeño y simple sistema para poder poner la funcionalidad de multiidioma en CodeIgniter que podéis descargar de GitHub.

La idea ha sido añadir un poco de funcionalidad a la clase Lang.php creando una extensión que añada un método que borre los textos que ya se han cargado y otro que recargue los textos de un nuevo idioma.

Básicamente, el proceso es el siguiente:

  • el usuario elige el idioma y se guarda en sesión
  • la librería multiidioma lee esta variable de sesión y le dice a la extensión que recargue los textos del idioma elegido

Instrucciones:

1- Copia los archivos en su respectivas carpetas de tu proyecto (/application/)
2- En el archivo de configuración autoload (/application/config/autoload.php):

  • Añade la librería multilanguage:   $autoload['libraries'] = array(‘multilanguage’);
  • Añade los archivos de idiomas: $autoload['language'] = array(‘app’);

3- Prueba: http://tuporoyecto.com/test

Y listo, ya lo tienes funcionando.

HTML dinámico con jQueryMobile

listado dinamico

 

Un poco de historia (si quieres)

jQuery Mobile tiene 5 temas que nos ayudan en gran medida a la hora de desarrollar nuestras aplicaciones, los utilicemos de serie o con nuestras propias modificaciones. Cada uno de los temas tiene un diseño predefinido para páginas, toolbars, botones, formularios, listados, … Además, estos temas aprovechan en gran medida las ventajas de CSS3, como el uso de gradientes de color para los backgrounds, el listado de iconos (quizás un poco corto), … que nos reduce la carga de imágenes y las peticiones al servidor.

Para poder utilizar estos temas, hay que añadir atributos al elemento html que especifiquen qué queremos utilizar. El más básico es:

<div data-theme="a">

Este uso de atributos hace que una vez cargado el DOM, si añadimos o modificamos dinámicamente algún elemento que los utilice, no se verán reflejados los cambios en nuestro navegador.

Existen múltiples formas de solucionarlo, si bien, jQuery Mobile ya nos da la herramienta adecuada para ello… bueno, una para cada caso. Vemos un ejemplo con un listado.

 

Veamos la solución con un ejemplo

Supongamos que queremos realizar el listado de la imagen de la cabecera del post. El código que lo genera es el siguiente:

<ul id="listado" data-role="listview">
<li data-role="list-divider">Listado dinámico</li>
<li>Elemento 1</li>
<li>Elemento 2</li>
<li>Elemento 3</li>
</ul>

Si lo generáramos dinámicamente tendríamos un listado sin ningún estilo por las razones que os comentaba antes. La solución es refrescar el listado para que se recojan los cambios:

$('#listado').append('<li>Elemento 1</li><li>...);
$('#listado').listview('refresh');

En el caso de que ni siquiera tengamos el inicializado el listado antes de añadirle los elementos, es decir:

<ul id="listado" data-role="listview"></ul>

Tendríamos que anteponer una sentencia más a nuestro código para realizar la inicialización del listado:

$('#listado').listview();
$('#listado').append('<ul ...><li></li>...</ul>');
$('#listado').listview('refresh');

Os dejo la solución para algunos elementos más:

Checkbox:

$("input[type='checkbox']").prop("checked",true).checkboxradio("refresh");

Radio:

$("input[type='radio']").prop("checked",true).checkboxradio("refresh");

Select:

var myselect = $("#selectfoo");
myselect[0].selectedIndex = 3;
myselect.selectmenu("refresh");

Slide:

$("input[type='range']").val(60).slider("refresh");

Listado:

$('#listado').listview('refresh');

Inicialización de modelos en Code Ingniter 2

Codeigniter

Uno de los problemas que encuentro al usar Code Igniter 2, es la forma de utilizar los modelos. Como casi todo en Code Igniter, los modelos están optimizados para que la programación se realice lo más rápido posible. Así, crear un modelo tiene básicamente el siguiente código:

class nombre_modelo extends CI_Model
{
	private $_id;

	public function __construct()
	{
		parent::__construct();
	}

	public function metodo()
	{
		//hago algo;
	}
}

Y cuando lo necesitas, lo instancias y usas así:

$this->load->model('nombre_modelo');
$this->nombre_modelo->metodo();

El problema que encuentro y que no llego a comprender, es por qué no puedo pasarle parámetros al construct en la función load del modelo. Es decir:

new Modelo($parametro1, $parametro2);

Una solución a este error (al menos yo no encuentro otra forma de llamarlo) de Code Igniter es modificar la base del Framework y darle esta funcionalidad al modelo CI_Model. Y esto es un hardcodeo en toda regla…

La solución que utilizo es crear un método initialize que haga la labor definida para el método construct. Esto me sigue pareciendo algo cercano a lo absurdo, pero no se me ha ocurrido nada mejor, ni he encontrado nada mejor googleando. De esta manera, el modelo y su uso sería el siguiente:

class nombre_modelo extends CI_Model
{
	private $_id;

	public function __construct()
	{
		parent::__construct();
	}

	public function init($id)
	{
		$this->_id = $id;
	}

	public function metodo()
	{
		//hago algo;
	}
}
$this->load->model('nombre_modelo');
$this->nombre_modelo->init($id);
$this->nombre_modelo->metodo();

¿Alguien usa una solución mejor? Se que a algunos esto les parecerá una pequeñez, pero en ocasiones hago código erróneo por esta cuestión.

Y sobre todo, ya que Code Igniter es muy simple de usar, se recomienda a programadores nóveles, los cuales no utilizan los objetos adecuadamente por esta razón, con los problemas que esto acarrea.

Crear app móvil con HTML5 (III)

Phonegap

Parte 3: como llevar una webApp a Google Play con PhoneGap

Una vez que ya hemos visto cómo construir una webApp de una manera bastante simple en los dos post anteriores, en este vamos a ver como llevarla a los markets. Antes de nada, apuntar que evidentemente, este paso no es necesario en muchos casos, nuestra webApp es totalmente funcional. Además, la competencia en los markets es muy grande y es complicado no perderse en la inmensidad de aplicaciones que tienen.

Dicho esto, vamos a comenzar con PhoneGap. Lo primero es ir hasta su web, concretamente al manual de inicio, seleccionáis la plataforma que os interese y realizáis todos los pasos que os indican. Al final, una vez configurado el proyecto, tendréis que tener vuestra webApp en la carpeta www. La documentación está muy bien y es fácil de seguir, pero tranquilos si tenéis algún problemilla, especialmente si no estáis acostumbrados a usar el IDE que utilicen (Eclipse en Android y XCode en iOS).

Para el caso concreto de Android, una vez que hemos probado la app en el emulador y luego en nuestro terminal a fondo, llega el momento de comenzar a pensar Google Play. No es un proceso especialmente complicado, pero hay que tomárselo con calma, especialmente el firmado de la aplicación. Sigue este tutorial y no tendrás ningún problema.

Crear app móvil con HTML5 (II)

HTML5

Parte 2: JavaScript con jQuery Mobile, Google Maps, HTML5 Local Storage y HTML5 caché

En la primera parte vimos cómo crear las páginas de una webapp y navegar por ellas, gracias HTML5 y jQuery Mobile. En esta segunda vamos a terminar la webApp viendo cómo funciona el código JavaScript de geoMe, la webApp que estamos utilizando como modelo. Veremos lo elemental de JS con jQuery Mobile, HTML5 LocalStorage y HTML5 caché.

JavaScript con jQuery Mobile

El código JS de geoMe está en el archivo main.js. Es muy sencillo, pero vamos a pasar a analizarlo. Existen 3 objetos JS principales: geoMe, Google Map y Storage.

Este objeto es el encargado de gestionar la aplicación. Veamos será su definición:

var geoMe = $.mobile.geoMe

Lo que hacemos es sobreescribir el objeto principal de jQuery Mobile y generamos las propiedades y métodos que necesitamos. Si observáis el archivo, solo tenemos los 3 constructores de los objetos y una llamada al método init del objeto geoMe. Por ello, este método sera el punto de entrada de nuestra app. Básicamente, su cometido es esperar los eventos que lance el usuario y realizar las tareas oportunas.

Lo primero que vemos en el método es:

$(document).bind('pageinit')

en lugar del clásico:

$(document).ready()

Esto es así ya que ready() se ejecuta cuando se carga el DOM, es decir en la primera carga de la webApp. Y como hemos visto en la primera parte de este tutorial, nuestra aplicación tiene varias páginas dentro de un solo archivo html. Por ello, si utilizamos ready(), cuando naveguemos por nuestras páginas, no ejecutaríamos este código. Gracias a bind(‘pageinit) siempre que carguemos una página de jQuery Mobile, podremos ejecutar el código que deseemos sin bugs no esperados.

Otro elemento importante de la función main es:

$('#save').live('pageshow')
o
$('#see').live('pageshow')

Este código llamará a la función que le precede justo en el momento en el que se carga la página de guardar posición (id=”save”). Esto nos permite realizar un código mucho más interesante, por ejemplo, que intentar capturar cuando se hace click en el botón que nos lleva a dicha página, porque si se recarga la página, siempre se ejecutará el código.

No olvidemos que es una app en un móvil y que se puede cerrar en cualquier momento, por ejemplo, al recibir una llamada. Sería bastante frustrante para el usuario que al volver a la aplicación (la página de la webApp se recargaría) y encontrarse con una página en blanco.

Google Maps

El objeto googleMap tiene dos métodos principales que se encargan de guardar la posición del usuario (método savePositionMap) y de mostrar la posición guardada (método loadPositionMap). Además, ambos muestran la información en un mapa de Google, construyendo los mapas con la versión 3 de estos. Para que funcionen correctamente, en las cabeceras de index.html hay que llamar a:


HTML5 Local Storage

Y por último, el objeto Storage que se encarga de guardar la información de la posición del usuario en el Local Storage que nos ofrece HTML5. Es un espacio de 5mb como máximo en el navegador para guardar la información que queramos. Los métodos son simples y se puede entender fácilmente.

Una cosa a tener en cuenta: se guarda en el navegador, por lo que si el usuario cambia del móvil al ordenador, o de móvil, la información no será accesible. Puedes ver más información en este tutorial de Paper Killed.

HTML5 caché

Una app no serviría de nada, si cuando accedemos a ella sin conexión a internet, no nos muestrara nada. Por las funcionalidades de geoMe, esta app no tiene sentido sin conexión a internet, pero eso no impide que no podamos utilizarla o dar un servicio adecuado.

HTML5 trae la posibilidad de cachear todo los elementos que necesitemos para el funcionamiento de nuestra aplicación. Para ello, dentro del archivo cache.manifest debemos poner todas las rutas de nuestros ficheros. Y después, al comienzo del archivo html, hay que decirle al navegador que en la primera carga, guarde todos los archivos en caché:


Todo archivo manifest debe tener al menos la siguiente línea:

CACHE MANIFEST

Detrás, vienen todas las rutas de los archivos que queremos cachear.

Si queremos que algún elemento sea llamado a través de la red, tendremos que ponerlo detrás de

NETWORK

En nuestro caso, la llamada a Google será obligatoria si queremos que funcionen los mapas.

Puedes encontrar más información sobre HTML5 caché en HTML5 Rocks.

Ya tenemos lista la webApp. En caso de que nos interesara que la webApp estuviera en Google Play o en la App Store, os recomiendo que uséis PhoneGap. Desde su documentación de inicio no tendréis demasiados problemas para conseguir ejecutar la webApp como si de una app nativa se tratara. Después del proceso de testeo de la app, llegará el momento de subirla a los markets.

Crear app móvil con HTML5 (I)

jQuery Mobile

Parte 1: HTML de una webApp con jQuery Mobile

Para su desarrollo me he basado en Jquery Mobile, probablemente el framework HTML5 para dispositivos móviles más conocido, aunque seguramente, no el mejor. No entraremos a fondo en él, para eso ya está su documentación, pero veremos algunos elementos básicos.

Comenzaremos viendo cómo definir páginas. En el archivo index.html podemos encontrar el siguiente código que define la home de la aplicación:

geoMe

Save a place easily

Save place Load saved place About

La propiedad data-role nos permite asignarle el tipo al elemento div que la contiene. Como veis en la primera línea se define la página con:

data-role="page"

Y dentro de la página hay otros dos bloques div con la propiedad data-role cuyas finalidades son crear los bloques cabecera y contenido:

data-role="header" y data-role="content"

También existe un tercer valor que no utilizo, “footer” para crear el bloque pie de página.

En el archivo index.html podemos observar como la aplicación tiene 4 páginas básicas y todas dentro del mismo archivo: la home, la página de guardar posición, la página de mostrar la posición guardada y una página informativa.

Otro elemento importante son los que nos permiten pasar de una página a otra. Veamos por ejemplo cómo la aplicación pasa de la home a la página que permite guardar una posición:

Save place

En el atributo href apunta al id de la página de guardar posición y es el que permite pasar de una página a otra. Otro atributo importante es data-transition que permite realizar efectos en transiciones entre páginas: slide, flip, turn, …

jQuery Mobile dispone de histórico y gracias ello, en la página de destino, podemos poner un botón que nos permite regresar a la home y además, con el mismo efecto en la transición gracias a data-rel = “back”:

Home

Con esto, ya hemos visto unas pinceladas muy básicas de como crear páginas y navegar por ellas con jQuery Mobile. Ahora os toca a vosotros trastear con la documentación para aprender más ;)

En el próximo tutorial nos centraremos en el código JavaScript con jQuery Mobile, Google Maps API, HTML5 Local Storage y HTML5 caché.

Crear app móvil con HTML5 (introduccion)

Vamos a crear una una webApp en HTML5, lo cual quiere decir, que será una aplicación que puede ser usada por todos los dispositivos móviles (ya que es ejecutada desde los navegares web) gracias al estandar HTML5 de la W3C y gracias a PhoneGap, veremos como conseguir que la aplicación aparezca en los markets como si de una app nativa se tratara. La aplicación será muy simple y tiene como objetivo ver algunos de los elementos más básicos de la construcción de una webApp en HTML5.

La webApp que vamos a desarrollar es geoMe. Como podéis ver, es una webApp muy simple con 2 funcionalidades básicas: guardar una posición y mostrala. El código os lo podéis descargar de GitHub.

En la primera parte veremos como hacer codigo HTML5 con jQuery Mobile.

El la segunda veremos algunas peculiaridades del JS con jQuery Mobile, algunas de las funcionalidades claves de HTML5 (local storage y caché).

Empezamos.

geoMe: guarda un lugar fácilmente

Os presento geoMe, una webapp muy simple cuya finalidad es guardar un lugar geoposicionado. ¿Por qué? ¿para qué? La idea surgió porque me molesta profundamente cuando salgo de casa y no recuerdo dónde demonios aparqué el coche. ¿Cómo algo así me puede ocurrir tantas veces!! Evidentemente, también puede ser usada con otras finalidades, como guardar la posición de un sitio que nos haya gustado en un paseo de domingo ;)

Si, ya se que nos es una idea original, pero realmente, las apps que existen son “demasido” para lo que yo necesitaba. El objetivo fue hacerla lo más simple posible, por lo que las funcionalidades debían ser (y son) únicamente:

  • Guardar posición
  • Mostrar la posición guardada y la del usuario.
  • Opción de Street View para una mejor visualización.

 

La pega principal de las webapps es que muchas personas tienen problemas para salvar un acceso directo en sus teléfonos (sobre todo en Android), así que gracias a PhoneGap he creado la app para Android. Para iPhone será otro día que llueva ;)

Descarga geoMe

Quizás en otro artículo hable un poco de la tecnología, pero decir que me he basado en HTML5, los códigos de ejemplo de Google Maps, Jquery Mobile y PhoneGap. Podéis ver todo el código en GitHub y por supuesto utilizarlo como queráis. Todo el código es realmente simple.

Os dejo unas imágenes del resultado:

El selector nth-child

CSS3

Al maquetar cualquier proyecto, tenemos que lidiar en varias ocasiones con un listado de elementos como el de la imagen siguiente, es decir, muchos elemento cogiendo el ancho completo de la capa en la que trabajamos con un margen separando cada uno de los elementos.

listado

Si le asignamos a cada elemento un margen para separarlos, siempre tendremos un espacio indeseable al final de cada fila. Para estas ocasiones, se suele utilizar el truco de ponerle un clase “last” a cada uno de los últimos elementos de cada fila en el HTML y ponerle un margen cero a ese elemento en la hoja de estilos:

elemento {margin-right:10px;}
elemento.last {margin-right:0;}

Si el contenido es estático no tendremos ningún problema, pero para el caso de que sea dinámico, tendremos que forzar el “truco” y el resultado del código no será tan limpio. Pero gracias a CSS2 y CSS3, ya no existe este problema y podemos usar el selector:

nth-child()

Así, para el caso de la imagen, en el que cada 3 elementos el margen tiene que ser cero, nos podemos olvidar del HTML y procederemos de la siguiente manera:

elemento {margin-right:10px;}
elemento:nth-child(3n) {margin-right:0;}

Como veis, simplemente le indicamos que seleccione cada 3 elementos (3n).

Otro ejemplo clásico de este selector se produce cuando queremos darle claridad a un listado de elementos de texto:

listado2
En este caso, el css necesario sería al siguiente:

li:nth-child(even) {background: #eee;}
li:nth-child(odd) {background: #fff;}

Así, a cada elemento impar le asignamos un background gris y a cada par uno blanco. Y si quisiéramos, por ejemplo, asignarle un color al texto de cada uno de los elementos:

li:nth-child(1) {color: black;}
li:nth-child(2) {color: Blue;}
li:nth-child(3) {color: red;}
li:nth-child(4) {color: yellow;}

Formularios con Zend Framework (parte II)

En la parte I del tutorial vimos como crear un formulario con Zend Framework, sus posibilidades generales y cómo pasarlo a la vista. En este segundo vamos a ver como realizar la validación y en el caso de que existan errores, cómo mostrarlos sin que el usuario tenga que reescribir la información correcta. Vamos allá.

Dentro de nuestro Controller de Login, crearemos nuestro método encargado de la validación y submit de la información. En nuestro formulario, el action se dirigía a check y por POST $form->setAction(‘/check’)->setMethod(‘post’); de modo que nuestro método se llamará checkAction y contrendrá lo siguiente:

public function checkAction()
{
//comprobamos si nos llega un POST
	if(!$this->getRequest()->isPost()){
		return $this->_forward('index');
	}
//guardamos el POST y los datos del formulario
	$formData = $this->_request->getPost();
	$form = $this->_getForm();

//realizamos la validacion en función de valores de addValidator del formulario
	if(!$form->isValid($formData)) {
		// validación errónea: Poblamos al formulario con los datos
		$form->populate($formData);
		$this->view->form = $form;

		return $this->render('form');
	}

	//recogemos los datos y continuamos con nuestras gestiones
	//$values = $form->getValues();
} 

El código está mínimamente comentado para que se pueda ver qué hace cada bloque. Una vez que comprobamos que realmente nos está llegando un POST, lo primero es guardar los datos que nos llegan, así como los del formulario.

¿Para qué guardamos los datos del formulario? Para que Zend_Form sepa que tipos de datos debería haber en el POST y los validadores que asignamos a cada uno. De este modo y según creamos el formulario, Zend_Form sabrá que tiene que haber dos datos: el primero de tipo email y el segundo de tipo password con una longitud entre 4 y 8 caracteres.

Con estos datos, realizamos la validación:

$form->isValid($formData)

Si es correcta, pasaríamos a las siguientes gestiones. Pero lo que nos interesa ahora mismo es qué hacer si los datos no son correctos.

Zend_Form nos proporciona el método populate, el cual se encarga de recoger el formulario completo, adjunta los datos que se introdujeron y muestra los errores de cada uno. Después solo tenemos que pasar de nuevo el formulario a la vista y el render correspondientes. Si en nuestro formulario introducimos los siguientes datos erróneos:

El resultado sería el siguiente:

Así de fácil. El resultado es francamente rápido y para el usuario la respuesta con los errores parecerá como si estuviera hecha con AJAX.

Una vez que lo datos fueran correctos, tendríamos que hacer todas gestiones que necesitáramos en función de nuestro cometido.

Formularios con Zend Framework (parte I)

Los formularios son una tarea repetitiva que todo desarrollador web ha tenido que hacer en un centenar de ocasiones, como mínimo. A pesar de ello, cuando comienzas a utilizar Zend Framework, Zend_Form se convierte en una de las clases estrella.

Zend Form permite crear los formularios desde el propio PHP sin utilizar HTML, facilita las tareas de validación y devuelve los errores como si de AJAX se tratara. Además, esto nos evita las clásicos errores en la elaboración del HTML. En este primer tutorial, vamos a ver un ejemplo básico de su uso con la creación del clásico formulario de Login.

Dentro de nuestro Controller de Login o aquel que se encargue de dicha tarea, construiremos el método que cree del formulario con dos campos, el mail y el password:

private function _getForm()
{
	$form = new Zend_Form();
	$form->setAction('/check')
		->setMethod('post');
	//creamos los dos campos
	$mail = $form->createElement('text', 'email');
	$mail->addValidator('emailAddress')
		->setRequired(true)
		->setLabel('Email');

	$password = $form->createElement('password', 'pass');
	$password->addValidator('stringLength', false, array(4, 8))
		->setRequired(true)
		->setLabel('Password');

	// Agregar los elementos al formumario:
	$form->addElement($mail)
		->addElement($password)
		->addElement('submit', 'login', array('label' => 'Login'));

	return $form;
}

El primer paso es la llamada a Zend_Form, el cual ya habremos cargado con anterioridad con un requiere o con la clase Zend_Loader_Autoloader.

A continuación definimos el action del formulario con setAction enviándolo a la URL que lo recibirá y el método con setMethod que puede ser POST o GET. Si quisiéramos podríamos añadir atributos al formulario con setAttrib, por ejemplo:

$form->setAttrib('id', 'login');

El siguiente paso es la creación de los dos campos. Vamos todos los pasos y posibilidades. El primero es la definición del tipo de campo con createElement que recibe como parámetros el tipo y el nombre del campo. Existen los siguientes tipos: button, checkbox, hidden, image, password, radio, reset, select, submit, text y textarea.

Después, añadimos un validador con addValidator. Estos son los tipos principales:
- alnum: alfanumérico
- alpha: solo letras
- digits: solo números
- stringLength: nos permite configurar la longitud mínima y/o máxima en caracteres. En el ejemplo el password debe contener entre 4 y 8 caracteres.

$password->addValidator('stringLength', false, array(4, 8));

- emailAddress: email
- notEmpty: campo no vacío
- regex: expresión regular. Por ejemplo:

$campo->addValidator('regex', false, array('/^[a-z]/'));

Como podéis ver en el ejemplo, para añadir un label hay que utilizar setLabel.

Otra posibilidad más son los filtros con addFilter. Si por ejemplo, queremos pasar todos los caracteres a minúsculas utilizaremos:

$campo->addFilter('StringtoLower');

Y la última posibilidad que os comento será setOrder, que como os imaginaréis sirve para ordenar los elementos como queramos. Por defecto se muestran en el orden en que se crean.

Bien, ya tenemos nuestro formulario creado, pero aun nos queda pasárselo a la vista. Para ello, dentro del método encargado de mostrar este formulario, tendremos que añadir la llamada a la creación del formulario y pasárselo a la vista. Por último, tendremos que hacer el render del contenido.

$this->view->form = $this->_getForm();
$this->render('form');

Tener en cuenta que el formulario será renderizado en el archivo form.phtml. Si quisiéramos mostrarlo dentro de otro archivo, por ejemplo el index.phtml:

$this->render('index');

Dentro del archivo form.phtml simplemente tendremos que hacer lo siguiente:

<h2>Introduce tus datos de acceso:</h2>
<?php echo $this->form ?>

En el siguiente tutorial, veremos como realizar la validación del formulario.

Sublime Text 2 y Drupal

Desde hacía un tiempo, estaba cansado del gran gasto de recursos que necesita Eclipse para funcionar y los problemas que ello me conllevaba a la hora de desarrollar, sobre todo la lentitud en las tareas más insignificantes. De este modo conocí Sublime Text 2 que desde un principio enamora, principalmente por todo lo contrario: simplicidad, rapidez y un gran diseño. Si tienes los mismos problemas, no lo dudes, la adaptación es muy rápida.

Sublime Text 2 ya trae por defecto el control de sintaxis de una cantidad impresionante de lenguajes: prácticamente cualquiera actual está incluido. Además, opciones como el gestor de Snippets, los plugins, la velocidad del buscador o la configuración, lo hacen realmente funcional. Si quieres leer todas sus bondades, pásate por su web, lo terminarás usando.

Si trabajas con un Framework existen configuraciones para adaptarlo totalmente con tu trabajo diario. Vamos a ver la configuración básica para Drupal.

Lo primero sería configurar la sintaxis de nuestro código para adaptarlo al de Drupal. Para ello hay que cambiar las siguientes campos del archivo de configuración (Preferences -> File Settings – Default):

"rulers": [80],
"tab_size": 2,
"translate_tabs_to_spaces": true,
"use_tab_stops": true,
"trim_automatic_white_space": true,
"trim_trailing_white_space_on_save": true,
"ensure_newline_at_eof_on_save": true,
"fallback_encoding": "UTF-8",
"default_line_ending": "unix",
"shift_tab_unindent": true,

Y el siguiente paso sería obtener el autocompletado de las funciones de Drupal. Una vez configurado y como es de esperar, al comenzar a escribir una función podremos presionar las teclas control + espacio y nos parecerá un cuadro con las funciones disponibles.

Drupal6.sublime-completions

Descarga el archivo anterior y ponlo en tu carpeta de usuario de Sublime Text, que para Ubuntu estará en la siguiente ruta:

~/.config/sublime-text-2/Packages/User/

Este archivo lo ha realizado Tanc y lo publicó en su web. El paso siguiente será buscar algo similar para Zend Framework y para Drupal 7 ;)