Uninstallme

Desarrollo front-end, estándares web, accesibilidad y más

Crear un plugin con jQuery

Por kcmr, el 6 de junio de 2010 en Javascript, jQuery

Etiquetas:

Quienes suelan leer este blog sabrán que soy de Mootools, pero empecé con jQuery. Donde trabajaba entonces todo el mundo usaba Prototype, así que me pasé pronto a este framework y mi jQuery se quedó olvidado hasta tal punto de que cada vez que intento tocar un script en jQuery las paso canutas, acostumbrada a la forma de hacer las cosas en Mootools y Prototype, que es bastante parecida.

La verdad es que a juzgar por las veces que se nombra jQuery en blogs y la cantidad de plugins disponibles para esta librería, diría que es la más popular y la preferida de muchos, así que me voy a obligar a ponerme las pilas.

Captura de la comparación del volumen de búsqueda en Google entre jQuery y Mootools (Fuente: Google Trends)

Una de las cosas que no me gustaba de jQuery, en comparación con Mootools o Prototype, es que no se pueden crear “clases”. Las clases permiten de una forma fácil crear scripts reutilizables que incluso se pueden extender. A decir verdad, nunca he tenido la necesidad de extender una clase.

En jQuery se pueden crear plugins, esto es añadir un método de nuestra propia cosecha a jQuery, para utilizar sobre los elementos que queramos y con las opciones que pasemos como parámetro, como si fuera un método más de jQuery.

Podríamos crear un método llamado miPlugin() que se utilizaría así:


$('#id').miPlugin({
	opcion: 'valor',
	opcion2: 'valor2'
});

Como estoy un poco cruda en cuanto a los métodos de jQuery, voy a usar un ejemplo bastante tonto a fin de ilustrar la forma de crear un plugin. El plugin se limita a cambiar los colores de primer plano y fondo del objeto clicado y reemplazar o añadir un texto.

En primer lugar tenemos que evitar que pueda entrar en conflicto con otras librerías, para lo que meteremos nuestro plugin dentro de una función anónima. De paso también evitamos tener variables globales.


(function($){
 … código
})(jQuery);

Extendemos jQuery añadiéndole nuestro método.


$.fn.miPlugin = function(options){
}

He pasado como parámetro options, que será un objeto con todas las opciones personalizables que sobrescribirán a las opciones por defecto del plugin. Esas opciones por defecto están dentro de un objeto que hemos llamado defaults.


var defaults = {
	colorFondo: 'red',
	colorTexto: 'white',
	texto: 'Hola, me has clicado'
	animar: true
}

Necesitamos extender estas opciones por defecto con las opciones que se pasen como parámetro.


var options = $.extend(defaults, options);

De esta forma, nos referiremos a las opciones en el código del plugin mediante options.nombreOpcion

Por último inicializamos la función y escribimos el código necesario.


return this.each(function(){
	$(this).bind('click', init);
});

Todo junto:


(function($){
	$.fn.miPlugin = function(options){
		var defaults = {
			colorFondo: 'red',
			colorTexto: 'white',
			texto: 'Hola, me has clicado',
			animar: true
		};
		var options = $.extend(defaults, options);
		return this.each(function(){
			$(this).bind('click', init);
		});
		function init(ev){
			ev.preventDefault();
			$(this).css({
				background: options.colorFondo,
				color: options.colorTexto
			}).text(options.texto);
			if(options.animar){
				$(this).css('display', 'block').animate({
					'width': 300
				});
			}
		};
	}
})(jQuery);

Ya podemos usar nuestro método sobre el elemento que queramos. Ejemplos:

Con las opciones predeterminadas:

$('a').miPlugin();
Cambiando los colores de fondo y primer plano:

$('a').miPlugin({
	colorFondo: 'black',
	colorTexto: 'red'
});
Sin animación final:

$('a').miPlugin({animar: false});

Pues hasta aquí mi pequeña contribución para los “jQuerianos”. Probablemente nada nuevo para los más experimentados, pero ha sido un gran descubrimiento para mí y he querido compartirlo. Espero ir publicando más cosillas próximamente (sin tener que justificarme)

Demo del ejemplo

Más información

4 Comentarios

El uso del pseudoprotocolo (href="javascript:nombreFuncion();") en enlaces es una mala práctica de acuerdo con las normas del Javascript no intrusivo. Los enlaces deben tener una url válida que funcione sin Javascript. Por ejemplo, un enlace que abre una popup debe tener una url en su atributo href, de manera que sin Javascript siga siendo un enlace válido.

Pero no todos los enlaces que ejecutan alguna función Javascript tienen que tener una url en su atributo href. Algunos sirven para realizar acciones dentro de la propia página, como puede ser mostrar / ocultar una capa, pasar a la imagen siguiente en un carrusel, etc.

En estos casos, lo correcto es crear esos enlaces con Javascript, ya que sólo con Javascript habilitado tienen sentido (no deben estar previamente en el código HTML), y asignarles como atributo href una almohadilla (#) o dejarlo vacío.

En algún blog que no consigo encontrar proponían usar para este tipo de enlaces el pseudoprotocolo javascript: u otro que consideremos más apropiado (inventado), como podría ser imagen:.

De esta forma, estos enlaces proporcionan información acerca de su función al hacer rollover sobre ellos o cuando tienen el foco. Esta información suele aparecer en la barra de estado del navegador. También es útil para usuarios de lectores de pantalla que puedan tenerlos configurados para no leer el atributo title.

Atributo href del enlace mostrado en la barra de estado de Firefox

Atributo href del enlace mostrado en la barra de estado de Firefox

Habrá quien se preguntará si es correcto asignar este tipo de funciones a enlaces en lugar de a otros elementos HTML. La respuesta es que sí, ya que los enlaces pueden tener de forma natural el foco y ser activados cuando se utiliza el teclado para navegar y moverse por la página.

Sin comentarios

Lazy Load de imágenes con Mootools

Por kcmr, el 30 de diciembre de 2009 en Javascript, Utilidades

La técnica “Lazy Load” consiste en detener la carga inicial de imágenes u otros elementos hasta que están en el área visible de la pantalla, momento en que se cargan con un efecto fade in (aparición suave).

Es ideal para páginas con galerías lineales de imágenes, en las que la carga de imágenes a petición (al hacer scroll) puede reducir considerablemente el tiempo inicial de carga de la página.

Existe un plugin para jQuery y también uno para Prototype, pero no acababa de encontrar uno que funcionara exactamente igual para Mootools, aunque existe uno, así que me he decidido a hacerlo basándome en el de Prototype.

Es un script bastante sencillo que no contempla otras opciones como ancho y alto mínimo de las imágenes o extensión (gif, jpg, etc). Su funcionamiento se basa en reemplazar el atributo src de las imágenes que no están en el área visible de la pantalla por el de una imagen de peso muy reducido (43 bytes) y utilizar el atributo src original cuando esta imagen pasa a estar en el área visible de la pantalla. La posición de la imagen se detecta con el evento scroll de la página.

Para saber si la imagen está en el área visible de la pantalla he utilizado el método explicado en otro post para hacer lo mismo con Prototype.

Archivos requeridos

Uso

Se inicializa con el evento ‘domready’ del objeto window. En la demo se utilizan todas las imágenes, pero se podría utilizar cualquier selector, sólo las imágenes con una determinada clase, o las imágenes que estén dentro de una capa, etc.

window.addEvent('domready', function(){
   $$('img').each(function(el){
      new Kcmr.MooLazyLoad(el);
   });
});

Como única opción se puede pasar la ruta a la imagen de 1x1px que se utiliza como sustitución de la imagen original. La ruta por defecto es “images/blank.gif”

Ejemplo con otros selectores y ruta personalizada a la imagen de sustitución:

window.addEvent('domready', function(){
   $$('.clase img.clase').each(function(el){
      new Kcmr.MooLazyLoad(el, {
         blank: 'directorio/imagen.gif'
      });
   });
});

Demo y descarga

Sin comentarios

Detectar suavizado de fuentes con javascript

Por kcmr, el 6 de diciembre de 2009 en Buenas ideas, CSS, Javascript

Etiquetas: , , ,

En User Agent Man han publicado un script para detectar el suavizado de fuentes en el navegador. Si el suavizado de fuentes está activado, se añade una clase al elemento html que permite usar unas u otras fuentes en la CSS dependiendo de esta característica.

Este script es especialmente útil para utilizar fuentes embebidas mediante @font-face, ya que la calidad del resultado depende muchísimo de si el suavizado de fuentes está o no habilitado en el SO del usuario. También es útil a la hora de decantarse por unas u otras fuentes de sistema, como por ejemplo, la Lucida Sans Unicode, que sin suavizado resulta de mala legibilidad en Windows.

Información relacionada (@font-face)

Bulletproof @font-face syntax
La mejor forma de utilizar @font-face.
Existe una traducción al español en CSSBlog
Font Squirrel
Kits de fuentes para usar mediante @font-face
@font-face generator
Nos permite subir una fuente y descargar el paquete completo para usar mediante @font-face
TTF to EOT Font Converter
Para convertir fuentes TrueType a OpenType (EOT), el formato usado por Internet Explorer

3 Comentarios

Ejemplo de Javascript Multiidioma

Por kcmr, el 1 de septiembre de 2009 en Javascript

Cuando tenemos un sitio en varios idiomas en el que estamos añadiendo atributos como ALT o TITLE a imágenes o enlaces, lo ideal es proporcionar esos literales en todos los idiomas del sitio y usar los correspondientes al idioma según el valor del atributo xml:lang o lang de la etiqueta HTML.

Para estos casos es útil crear un objeto en el que almacenamos todos los literales según el código del idioma.

Mediante una función que devuelva el valor del atributo xml:lang o lang del tag HTML, estableceremos el idioma del sitio y los literales a usar.

Ejemplo completo usando Mootools:

var MiClase = new Class({
  Implements: Options,
  // literales a usar
  options: {
    literales: {
      ES: {
        titleMostrar: 'Mostrar álbum',
        titleOcultar: 'Ocultar álbum'
      },
      EN: {
        titleMostrar: 'Show album',
        titleOcultar: 'Hide album'
      }
    }
  },
  initialize: function(element, options){
    this.setOptions(options);
    this.element = element;
    ...
    // llamamos a la función encargada de obtener el valor del atributo lang del tag HTML
    this.getDocumentLang();
    // según el valor de this.lang (devuelto por la función anterior) asociamos los literales de uno u otro idioma a una propiedad "literales" de nuestra clase "MiClase"
    this.lang == 'es' ? this.literales = this.options.literales.ES : this.literales = this.options.literales.EN;
  },
  getDocumentLang: function(){
    // obtengo el valor de xml:lang o de lang si xml:lang no se ha usado en el HTML
    this.lang = $$('html')[0].get('xml:lang') || $$('html')[0].get('lang');
    if(!this.lang) this.lang = 'es'; // idioma por defecto si no se ha declarado el idioma principal del documento
    return this.lang;
  },
  // uso de la propiedad literales en otras funciones
  funcionEjemplo: function(){
    var miElemento = ...;
    miElemento.set('title', this.literales.titleMostrar);
  }
});

En el caso de más de dos idiomas, en lugar del condicional usado dentro del método initialize en el ejemplo anterior, podríamos usar una estructura switch case.
Ejemplo:

initialize: function(element, options){
  ...
  this.getDocumentLang();
  switch(this.lang){
    case 'es':
      this.literales = this.options.literales.ES;
      break;
    case 'en':
      this.literales = this.options.literales.EN;
      break;
    case 'fr':
      this.literales = this.options.literales.FR;
      break;
    default:
      this.literales = this.options.literales.ES;
  }
}

1 Comentario

Usar PHP en archivos Javascript

Por kcmr, el 29 de agosto de 2009 en Javascript

La forma más sencilla de acceder a alguna variable de PHP desde Javascript, es colocar el Javascript en el código HTML.

Ejemplo:


<script type="text/javascript">
    var flashvars = {
        file: "<php echo get_settings('home'); ?>/archivo.xml"
    }
</script>

Afortunadamente existe otro método para poder mantener el Javascript en un archivo independiente en el que podamos acceder a variables PHP.

Para poder hacer esto necesitamos servir los archivos Javascript como PHP.

El primer paso es renombrar el archivo Javascript para que su extensión sea .php. Lo podemos dejar como nombrearchivo.js.php para facilitar su identificación.

Dentro del archivo Javascript, al comienzo, necesitamos indicar que el contenido del archivo es de tipo Javascript:


<?php
Header("content-type: application/x-javascript");
?>

Podemos pasar las variables PHP que necesitemos como parámetro en la url:


<script type="text/javascript" src="js/nombrearchivo.js.php?url=<?php get_settings('home'); ?>"></script>

De esta forma podemos acceder a ellas mediante $_GET en el archivo Javascript:


<?php
Header("content-type: aplication/x-javascript");

$variablePHP = $_GET['url'];
echo "var variableJS = '" .$variablePHP. "';\n";
?>

// inicio del código javascript
var flashvars = {
    file: variableJS + "/archivo.xml"
}

Usando este método también podemos reducir un poco el tamaño de los archivos Javascript encerrando los bloques de comentarios entre etiquetas PHP.

Más información: External JavaScript and PHP

2 Comentarios

Es una buena práctica, sobretodo cuando se usan vídeos o animaciones flash que contengan sonido, el dejar la reproducción de la película en manos del usuario en vez de iniciarla automáticamente.

Las veces que esto se cumple se suele hacer colocando un control en la propia película flash, como un icono de Play o similar semitransparente.

El uso exclusivo de este método puede suponer un problema para usuarios de navegadores que no sean Internet Explorer y no utilicen ratón, ya que los flashes no pueden recibir el foco mediante teclado a no ser que se activen previamente con el ratón.

Incluir además unos enlaces en HTML para iniciar o detener la reproducción de Flash supondría una pequeña mejora de accesibilidad para estos usuarios.

Los pasos que hay que seguir para conseguirlo son:

  1. Dar un ID al object que contiene el Flash
  2. Detener la reproducción automática de la animación:
    1. Si la animación está en la línea de tiempo principal basta con usar el parámetro play con el valor false en el HTML
    2. Si la animación está en otra línea de tiempo tendremos que detenerla en el propio flash mediante un nombreDeInstancia.stop() en la línea de tiempo principal.
  3. Asignar la función de iniciar / detener a los enlaces correspondientes en HTML

Ejemplos de los dos casos

Object película Flash con animación en la línea de tiempo principal

HTML del flash


<object width="155" height="17" id="ejemplo-1" type="application/x-shockwave-flash" data="ejemplo.swf">
    <param name="src" value="ejemplo.swf" />
    <param name="play" value="false" />
</object>

Controles HTML (lo ideal para una degradación elegante sería pintarlos con Javascript, ya que sólo con Javascript habilitado pueden funcionar)


<ul id="controles-1">
    <li><a href="#">Iniciar reproducción</a></li>
    <li><a href="#">Pausar reproducción</a></li>
</ul>

Javascript


var control1 = document.getElementById('controles-1').getElementsByTagName('a');
control1[0].onclick = function(){
    document.getElementById('ejemplo-1').Play();
    return false;
}
control1[1].onclick = function(){
    document.getElementById('ejemplo-1').StopPlay();
    return false;
}

Demo

Object película Flash con animación en una línea de tiempo distinta a la principal

HTML del flash


<object width="165" height="48" id="ejemplo-2" type="application/x-shockwave-flash" data="ejemplo-2.swf">
    <param name="src" value="ejemplo-2.swf" />
</object>

Javascript

En este caso, para iniciar o detener la animación tendremos que usar los métodos TPlay("ruta_a_linea_tiempo") y TStopPlay("ruta_a_linea_tiempo")


var control2 = document.getElementById('controles-2').getElementsByTagName('a');
control2[0].onclick = function(){
    document.getElementById('ejemplo-2').TPlay("_root/mc_barra");
    return false;
}
control2[1].onclick = function(){
document.getElementById('ejemplo-2').TStopPlay("_root/mc_barra");
    return false;
}

Demo

Existen otros métodos predefinidos útiles para controlar la reproducción de una película Flash, como Rewind() o GotoFrame()

Aprovecho este post para recomendar un par de recursos que pueden sernos de gran utilidad a la hora de mejorar la accesibilidad de vídeo Flash (ya que por la página de recursos no se pasa ni GOOGLE):

JW Player Controls
Reproductor de Flash Vídeo que permite controlar la reproducción mediante teclado, añadir subtítulos y descripciónes de audio y además añade los atributos apropiados ARIA. Utiliza JW FLV Player junto con un plugin de accesibilidad. Los controles javascript se proporcionan mediante la librería Dojo.
Ejemplos de control del reproductor JW Player mediante Javascript
Varios ejemplos de control de la reproducción de contenido multimedia mediante Javascript usando JW Player.

Más información

3 Comentarios

Mootools Dolar Safe Mode

Por kcmr, el 28 de junio de 2009 en Javascript

Etiquetas: ,

Si algo se echaba en falta en Mootools era la capacidad para poder ser usado sin conflicto junto con otras librerías que también hacen uso del dólar $, como permite jQuery con su jQuery.noConflict().

Desde la versión 1.2.3, lanzada este 19 de junio, Mootools ya implementa esta característica que han llamado Dolar Safe Mode.

A partir de ahora, podremos hacer uso de Mootools junto con otras librerías (cosa realmente no muy recomendable) usando document.id como alias para el acceso por ID ($(id)) y document.search para el acceso por selector CSS ($$(selector))

Hacer los plugins compatibles

Desde el blog de Mootools nos recomiendan simplemente reemplazar los símbolos $ en los plugins por document.id o bien encapsular el plugin en una función anónima. Como comentaba en Javascript Module Pattern, el uso de funciones anónimas nos permite tener variables privadas. De esta forma, podemos asignar document.id a $ y evitar el reemplazo de todas las coincidencias.

Ejemplo de adaptación de un plugin usando una función anónima:


(function(){
    var $ = document.id;
    this.X = new Class({
        ...
    });
})();

Más información sobre Dollar Safe Mode en el blog de Mootools.

Sin comentarios

Acabo de descubrir varios script que hacen posible, tanto la navegación “normal” mediante el botón volver del navegador, como el añadir páginas a los favoritos o marcadores en aplicaciones AJAX. Una solución a dos de los grandes problemas de usabilidad que presentan este tipo de aplicaciones.

Dejo cuatro enlaces rápidos:

  1. HistoryManager. Funciona con Mootools.
    It solves the typical “Back-Button” and “Ajax Bookmarks” problems for accessible browsing and a better usability in Rich Internet applications.
  2. Versión de HistoryManager para Prototype.
  3. History Keeper. No utiliza ninguna librería.
  4. UpdateControls: UpdateHistory and AnimatedUpdatePanel. Para ASP.NET AJAX.

Sin comentarios

Esta es la sintaxis del operador ternario, que equivale a una estructura de control de flujo if / else:


condicion ? instrucción si se cumple : instrucción si no se cumple;

Usando un ejemplo de código real podría ser así:


hasClassName(capa, clase) ? removeClassName(capa, clase) : addClassName(capa, clase);

Que para mayor legibilidad, si las instrucciones son muy largas, se puede separar en varias líneas:


hasClassName(capa, clase)
? removeClassName(capa, clase)
: addClassName(capa, clase);

Hasta ahora, siempre que había tenido que usar varias instrucciones en una condición, había abandonado el operador ternario en favor de una estructura if / else:


if(condicion){
    hazAlgo();
    yHazOtraCosa();
}
else{
    hazUnaCosa();
    hazOtraCosaMas();
}

Mediante el operador ternario podemos incluir varias instrucciones usando funciones anónimas:


condicion
? (function(){ hazAlgo(); hazOtraCosa();})()
: (function(){ hazUnaCosa(); hazOtraCosaMas();})();

Usando un ejemplo de código real, podría ser así:


hasClassName(capa, clase)
? (function(){ removeClassName(capa, clase); enlace.title = 'Ocultar';})()
: (function(){ addClassName(capa, clase); enlace.title = 'Mostrar';})();

Sin comentarios