jQuery, la libreria de javascript

Existen diversas librerías javascript disponibles para utilizar en tus proyectos web sin necesidad de empezar desde cero. Por nombrar algunas de las más extendidas: jquery, MooTools, prototype, script.aculo.us, YUI tools o Dojo. Existen muchas más; unas cuantas búsquedas por google te traerán listados más amplios que este. Sin embargo estas son quizás las más recomendables o las que quizás necesites conocer para hacerte una buena idea de las opciones que tienes disponibles.

En este artículo comentaré la filosofía y las características principales de jQuery. No entraré a hacer una comparativa entre las distintas librerías del tipo: jQuery vs prototype vs YUI etc, etc, etc. Sólo indicar que aunque muchas tengan el pomposo nombre de framework, yo no se lo voy a atribuir. Para mi un framework es un concepto más amplio que involucra desde el desarrollo del software en si pasando por la gestión del versionado de su código, los procesos asociados a su desarrollo (gestión de incidencias, subidas a producción) y llegando hasta el control de calidad (test unitarios y funcionales), incluyendo las herramientas utilizadas para llevar a cabo todo esto, editores de código, gestores de workflow, etc. Un framework debería tener, incluir o al menos tener en mente todas o varias de estas características.

Bueno volviendo a jQuery empezaré comenzando por una pequeña característica que permite emplear esta librería con cualquier otra. O sea que si tienes dudas entre jQuery y YUI, por ejmplo, ten en cuenta que puedes emplear las dos pues jQuery ya ha pensado en esto. Lo explico: jQuery emplea su propio namespace para evitar colisionar con otras librerías, el nombre de este namespace es obviamente jQuery (incluso los plugins basados en jQuery emplean casi todos este namespace). Sin embargo, hay un pequeño asunto a solucionar y es que jQuery emplea como alias el identificado $. Por ejemplo:

jQuery(“div”).hide(); //Oculta todos los div del documento

es igual a:

$(“div”).hide();

Y como muchos sabréis hay otras librerías javascript que también lo emplean. Para solucionarlo basta con llamar a la siguiente función:

jQuery.noConflict();

Teniendo en cuenta que esta llamada ha de hacerse después de cargar las dos librerías que colisionan:

<html>
<head>
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script>
jQuery.noConflict();

// Use jQuery via jQuery(...)
jQuery(document).ready(function(){
jQuery("div").hide();
});

// Use Prototype with $(...), etc.
$('someid').hide();
</script>
</head>
<body></body>
</html>

Bien, con este tema aclarado pasemos a la filosofía de jQuery. jQuery emplea selectores CSS para referirse a uno o a un grupo de elementos sobre los que actúa. Emplea incluso selectores que no están completamente implementados en los más modernos navegadores pero si estandarizados (selectores CSS3) y añade incluso algunos más para añadir más versatilidad a la librería. jQuery trabaja principalmente con el DOM de los documentos XHTML. La sintaxis básica es:

$(selector)

por ejemplo

$(“a”)

Hace referencia a todos los enlaces del documento actual

$(“p a”)

Hace referencia a todos los enlaces dentro de párrafos (etiqueta p).

Lo que devuelven estas funciones es un objeto Javascript especial que contiene un array de elementos DOM que verifican el selector. Este objeto tiene un elevado número de funciones predefinidas que, de ser llamadas, actuan sobre todo el grupo de elementos. Por ejemplo si quieres que añadir una clase especial llamada “enlace” a todos los enlaces de tu documento bastaría con poner:

$(“a”).addClass(“enlace”);

Otra propiedad es que estas funciones al terminar de actuar devuelven a su vez el mismo array de elementos DOM. Así que puedes agregar un método tras otro, por ejemplo:

$(“a”).addClass(“enlace”).append(“<strong>[ ENLACE ]</strong>”);

Que añade la clase enlace a todos los enlaces y además les añade el fragmento de código html “<strong>[ ENLACE ]</strong>” después de su contenido normal.

Estas cadenas de funciones pueden continuar indefinidamente. Además de este módo de trabajo jQuery también tiene otras funciones, digamos, de propósito general que no actúan sobre elementos DOM. Son funciones tradicionales por ejemplo

$.trim(” Elimina espacios sobrantes del principio y final de la cadena “);

Un poco raro ¿no? Pero recordemos que $ es un alisas de jQuery

jQuery.trim(” Elimina espacios sobrantes del principio y final de la cadena “);

Ahora parece más normal esta llamada.

Estas funciones aumentan las funcionalidades disponibles (que no tiene javascript) sin tener que crearlas tu mismo.

Ahora que sabemos cual es la filosofía de trabajo de jQuery basado en emplear selectores del DOM cobra especial importancia esta pregunta. Cuando se carga una página ¿Cuando tenemos disponible el DOM del documento?. La respuesta podría ser cuando el navegador lance el evento onload. Pero no, esto no es correcto, pues el DOM se completa antes de lanzarse este evento. El evento onload se lanza cuando la página se ha cargado completamente, esto involucra no sólo la carga del documento html y su procesamiento para formar el árbol DOM sino también la carga de las imágenes y otros recursos necesarios para mostrar la página. Por otro lado javascript comienza a ejecutarse antes de que se haya completado el DOM. ¿Como podemos ejecutar una sentencia de jQuery asegurándonos que los elementos del DOM estén completos?

Pues jQuery tiene la solución a través de su función ready que se ejecuta cuando el árbol DOM esté completamente formado. Pongámoslo en un ejemplo:

$(document).ready(function() {$(“table”).slideDown(“slow”)})

Esto hace que cuando se cargue el DOM de la página todas las tablas ocultas se muestren poco a poco de arriba a abajo (ajustando su altura). Si a la función $() le pasamos una función esta se ejecutará también cuando el DOM este listo. Es pues un alias de la función ready

$(function() {$(“table”).slideDown(“slow”)})

Una pregunta. Porqué empleamos estas funciones anónimas en lugar de escribir directamente:

$(document).ready($(“table”).slideDown(“slow”))

La respuesta procede de la forma de trabajar de javascript y es que si utilizamos esta última forma, Javascript va a evaluar el argumento de la llamada a la función al ejecutar esta línea de código, es decir, antes de que esté listo el DOM. Empleando la función anónima sólo se evaluará una vez que tengamos el DOM listo

Bueno pues jQuery tiene muchas otras características. Por ejemplo, puedes extenderlo fácilmente. Mira este código:

<script type="text/javascript">
$.fn.idle = function(time)
{
var o = $(this);
o.queue(function()
{
setTimeout(function()
{
o.dequeue();
}, time);
});
return this;
}
</script>

Añade la función idle que puedes encadenar en las llamadas a jQuery para poner una pausa entre los efectos que añadas a los elementos. Ejemplo:

$(function() {$(“a”).hide(1000).idle(2000).show(1000);});

Hace que se oculten los enlaces lentamente (en un segundo) y tras dos segundos vuelvan a aparecer lentamente (en otro segundo).

Comentar por último que la funcion jQuery o $ también puede ser empleada para crear nuevos elementos DOM a través de html, por ejemplo:

$(‘<div>Hola mundo</div>’);

Con sólo parsarle como argumento a la función un fragmento de html podemos crear nuevos elementos DOM. Si queremos agregar este elemento DOM al documento actual podríamos por ejemplo escribir:

$(‘<div>Hola mundo</div>’).insertAfter(‘#identificador’);

Que hará que se agrege el fragmento después de la capa con id=”identificador”

Espero que haya sido de utilidad esta pequeña introducción a jQuery.

nmap, herramienta de seguridad

Nmap es una aplicación que sirve para explorar y auditar una red. Nmap lanza paquetes IP a la red para averiguar que servidores están disponibles en la red, que servicios (aplicaciones y versión) están ofreciendo estos servidores, que sistema operativo ejecutan, que tipo de cortafuegos están utilizando y otras muchas características.

Nmap tiene una utilidad gráfica que facilitará la tarea para aquellos menos avezados en la línea de comandos, su nombre es zenmap.

nmap es gratuito y open source bajo licencia GNU GPL versión 2

sshfs, el sistema de ficheros ssh

Con la llegada de fuse (file system userspace), que nos permite crear completos sistemas de archivos a través de programas en el espacio de usuario estaba claro que muchos desarrolladores iban a sacar buen provecho de esta herramienta para crear utilidades realmente interesantes. Cosas como un repositorio de subversión, cvs, git o mercurial como sistema de archivos o sistemas de archivos ad-hoc por ejemplo. En fin FUSE ofrece muchas posibilidades. Aunque ciertamente muchas de estas aplicaciones parecen estar bastante verdes y no será por falta de ports a diferentes lenguajes porque FUSE está disponible para C, C++, Java, C#, Haskell, TCL, Python, Perl, Ruby, Lua, Erlang o incluso PHP.

Bueno, volviendo al tema en cuestión una de las aplicaciones más interesantes que emplean FUSE es SSHFS. Como su nombre indica se trata de acceder por ssh a un equipo remoto como si fuera un punto de montaje más dentro de nuestro sistema de ficheros local. Es realmente sencillo de instalar (está en las fuentes de debian: # apt-get install sshfs) y de configurar.

Una vez correctamente instalado ya deberíamos tener la aplicación sshfs en nuestro path, ahora basta con ejecutar (mejor como usuario sin privilegios)

$ sshfs hostname: mountpoint

A continuación se te preguntará el password de acceso para la máquina hostname (con el usuario igual al de la sesión actual). Si quieres especificar un usuario diferente utiliza la sintaxis [email protected] delante del nombre de host:

sshfs [[email protected]]host:[dir] mountpoint [options]

Por ejemplo:

$ sshfs [email protected] /mnt /

$ sshfs -h

o

$ man sshf

Te da toda la información que necesitas sobre las opciones disponibles.

Para desmontar el sistema de archivos basta con ejecutar

$ fusermount -u mountpoint

Puedes descargar sshfs en sourceforge y también fuse.

Para más información esta es la página principal de sshfs

Redis, un nuevo modelo de base de datos ligero

Redis es una base de datos que asocia a una clave un determinado valor. Es similar a memcache pero con un conjunto de datos persistente (no volátiles).

Para ser lo más rápida posible y a la vez no volátil redis tiene todo el conjunto de datos en memoria y de vez en cuando o cuando el número de registros cambiados llega a cierto valor estos son escritos asincronamente en disco. Podrían perderse un pequeño número de valores que es aceptable para la mayoría de las aplicaciones pero es tan rápido como una base de datos en memoria.

Redis está escrito en ANSI C y funciona en la mayoría de sistemas POSIX como Linux, BSD, Mac OS X. Redis es software libre bajo licencia BSD.

Internacionalización y localizacion con gettext

Trataré de explicar algo de terminología antes de entrar en los detalles técnicos de este artículo:

Gettext es un conjunto de herramientas que sirven para que un programa pueda producir mensajes en múltiples idiomas.
Los ficheros po son ficheros de traducciones empleados por el conjunto de herramientas gettext de GNU. Un fichero po contiene una relación entre una cadena no traducida a otra cadena traducida en un idioma en particular.
A la operación por el cual un programa ha sido preparado y es capaz de soportar múltiples idiomas se le llama internacionalización, abreviado por I18n (en inglés internazionalization tiene 18 caracteres entre la i y la n, igual que en castellano)
A la operación por la cual un programa, ya internacionalizado, se le pasa toda la información necesaria para que pueda adaptar su entrada (stdin) y su salida (stdout) de manera que sea correcta para diferentes idiomas y hábitos culturales de un idioma o país en concreto se le llama localización, y suele ser abreviado por L10n (localization, 10 caracteres entre la ele y la ene)
El soporte de lenguaje nativo (Native Language Support o NLS) engloba ambos procesos; internacionalización y localización.
Un locale es un conjunto de componentes de los datos culturales de idiomas y/o países. El soporte de mensajes es uno de los locales más importantes, además hay como locales: los conjuntos de caracteres a utilizar (charsets), la representación de números (numbers), la representación de fechas (dates) y la representación de monedas (currency).

El po de la extensión de los ficheros de traducción significa Portable Object, para distinguirlo de los ficheros mo que significa Machine Object. Los ficheros po son legibles y editables por humanos. Cada fichero po está dedicado a sólo un idioma. Si un programa necesita traducciones en más idiomas se precisa crear un fichero po por idioma. Gettext tiene utilidades para detectar cadenas marcadas para traducir en un programa (xgettext) que crea un fichero tipo pot Portable Object Template que sirve de planilla para iniciar el trabajo de traducción, y utilidades para comentar cadenas que ya no se utilizan en futuras versiones del programa (msgmerge). También lógicamente para convertir los po’s en mo’s mediante fmtstr.

Los fichero mo son ficheros compilados para la lectura por parte del programa y son de tipo binario. El formato de los ficheros mo es a menudo diferente de sistema a sistema y cada sistema debe tener sus propias utilidades para convertir po’s a mo’s.

El formato del fichero po

Esta es la estructura general de una entrada en un fichero po

white-space
# translator-comments
#. extracted-comments
#: reference…
#, flag…
#| msgid previous-untranslated-string
msgid untranslated-string
msgstr translated-string

El fichero po esta formada por múltiples entrada de este estilo un ejemplo podría ser:

#: hello.c:17
msgid “hello world!”
msgstr “¡hola mundo!”

Las entradas comienzan por white-space opcional (generalmente un linea en blanco). Luego vienen los comentarios, todos ellos comienzan por el caracter #. Un espacio en blanco después del # indican un comentario creado y mantenido exclusivamente por el traductor. Si al caracter le sigue un punto este indica que el comentario esta sacado del código del programa, es decir, es un comentario del programador. Si el caracter tras el # es el de dos puntos : indica una referencia al punto en el programa donde esta la cadena por traducir, si hay más de una se separan por un espacio. Si la línea comienza por ‘#|’ indica la última cadena no traducida por el traductor. Y finalmente ‘#,’ contiene flags que veremos más adelante. Todos estos comentarios son también opcionales.

Todas las entradas tienen 2 cadenas una muestra la cadena no traducida (msgid) en la misma manera que aparece en el programa fuente y la otra contiene la cadena traducida (msgstr). Las cadenas traducidas y no traducidas usan comilla doble ‘ ” ‘ como delimitador y barra invertida ‘ \ ‘ como escapador (inicio de secuencia de escape). Pero el traductor no necesita tener esto en cuenta a la hora de editar los po’s.

El comentario ‘#,’ es una lista separada por comas de una o varias opciones. Estas son

fuzzy – indica que la traducción ya no tiene por que ser correcta
xxx-format o no-xxx-format – Donde xxx indica el lenguaje que se emplea en la programación (C, Lisp, PHP, C++, Python etc) o entornos específicos de desarrollo (KDE, GCC, Qt, …)

Contextualizar con gettext

También es posible tener entradas con un contexto específico. Por ejemplo:

white-space
# translator-comments
#. extracted-comments
#: reference…
#, flag…
#| msgctxt previous-context
#| msgid previous-untranslated-string
msgctxt context
msgid untranslated-string
msgstr translated-string

El contexto se emplea para desambiguar mensajes con la misma cadena no traducida ya que esto es posible en un fichero po haciendo que cada una tenga un contexto específico. Observa que es diferente tener un contexto vacío que no tenerlo en absoluto.

Es posible, sobre todo en cadenas cortas, que existan varias traducciones para una misma palabra o grupo de palabras. Para tener con el mismo identificador de mensajes msgid varios mensajes debemos emplear msgctx seguido de una cadena para desambiguar los diferentes mensajes. En el programa para indicar el contexto adecuado de un mensaje que necesita ser contextualizado basta con utilizar la función C (o la equivalente en otros lenguajes soportados):

const char *pgettext (const char *msgctxt, const char *msgid);

En la llamada a esta macro, msgctxt y msgid deben ser cadenas literales. La macro devuelve la traducción del msgid pero restringida al contexto dado por msgctxt.

La ‘p’ en ‘pgettext’ significa “particular: pgettext devuelve una traducción en particular de msgid

También existen estas funciones

const char *dpgettext (const char *domain_name,
const char *msgctxt, const char *msgid);
const char *dcpgettext (const char *domain_name,
const char *msgctxt, const char *msgid,
int category);

Que son generalizaciones de pgettext. Estas funciones permiten especificar el nombre de dominio para la traducción y la categoría permite usar otra categoría locale que la proporcionada por la variable de entorno LC_MESSAGES

Para tener una información completa sobre internacionalización y localización, junto con gettext visita el Manual sobre gettext que está disponible en múltiples formatos.

Formas en plural/singular con gettext

Uno de los problemas que no se han tenido en cuanta hasta ahora es el que tiene que ver con las modificaciones en las cadenas debido al número. Existen muchas diferencias en la cadena e incluso en las diferentes formas que adopta una cadena dependiendo del número. Por ejemplo en español se emplea lo que llamamos la forma plural para el 0 y todos los números mayores que uno y para el 1 se emplea la forma singular. Esto puede no ser así para otros idiomas o tener incluso más casos diferenciados para distintas cantidades (por ejemplo, entre otros muchos, el Polaco, el turco o el Japonés).

En la cabecera del fichero po se puede introducir una cabecera para indicar las reglas de las formas plurales en el idioma específico. Este es un ejemplo:

Plural-Forms: nplurals=2; plural=n == 1 ? 0 : 1;

nplurals es un entero que indica cuantas formas de plural hay en un idioma en concreto, la cadena que sigue a ‘plural=’ es una expresión en C que cuya una variable permitida es la n y que no debe contener números negativos.

Para el español podríamos utilizar:

Plural-Forms: nplurals=2; plural=n != 1;

Atención ten en cuenta que la expresión emplea la característica de C que devuelve 0 para false y 1 para true.

La sintaxis para el tipo de entradas que sirven para resolver formas en plural/singular tiene la siguiente formato:

white-space
# translator-comments
#. extracted-comments
#: reference…
#, flag…
#| msgid previous-untranslated-string-singular
#| msgid_plural previous-untranslated-string-plural
msgid untranslated-string-singular
msgid_plural untranslated-string-plural
msgstr[0] translated-string-case-0

msgstr[N] translated-string-case-n

Las diferentes versiones pluralizadas aparecen con indices del array msgstr y el indice se escoge de la expresión en C anterior. Observa que ahora tenemos dos identificadores de cadena no traducida una para el singular y otra para el plural.

La función que permite traducir estos formatos en el programa es ngettext:

char * ngettext (const char *msgid1, const char *msgid2, unsigned long int n)

Un ejemplo de su uso sería este:

printf (ngettext (“%d objeto encontrado”, “%d objetos encontrados”, n), n);

Fijate que hay que pasarle también el valor n a printf, además de a ngettext. Es posible además no tener cardinales en la función aprovechando la característica de que printf descarta los parámetros por defecto. Ejemplo

printf(ngettext(“Un objeto encontrado”,”Varios objetos encontrados”,n),n);