<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Scriptia</title>
	<atom:link href="http://blog.scriptia.net/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.scriptia.net</link>
	<description>Javascript y buenas prácticas en español</description>
	<pubDate>Tue, 09 Mar 2010 00:36:14 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<item>
		<title>Keypress, apilado de eventos, control de valores y setTimeout</title>
		<link>http://blog.scriptia.net/articulos/2009/12/keypress-apilado-de-eventos-control-de-valores-y-settimeout.html</link>
		<comments>http://blog.scriptia.net/articulos/2009/12/keypress-apilado-de-eventos-control-de-valores-y-settimeout.html#comments</comments>
		<pubDate>Tue, 01 Dec 2009 13:50:34 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[artículos]]></category>

		<category><![CDATA[eventos]]></category>

		<category><![CDATA[keypress]]></category>

		<category><![CDATA[setTimeout]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/?p=187</guid>
		<description><![CDATA[Algo que me han preguntado hoy:
Choan, cariño mío, guapetón de mi alma&#8230; tengo dos campos en un formulario y quiero que uno refleje los cambios en el otro&#8230; y controlando keypress no tengo el valor actualizado

Pues no, no lo tienes. Solución: controlar la pila de ejecución. El truco: usar un timeout para que el método [...]


Related posts:<ol><li><a href='http://blog.scriptia.net/al-margen/2006/11/referencia-de-eventos-dom-en-la-wikipedia.html' rel='bookmark' title='Permanent Link: Referencia de eventos DOM en la Wikipedia'>Referencia de eventos DOM en la Wikipedia</a> <small>Eventos DOM --estándares y propietarios-- correctamente descritos en DOM events...</small></li><li><a href='http://blog.scriptia.net/articulos/2006/12/eventos-en-jquery.html' rel='bookmark' title='Permanent Link: Eventos en jQuery'>Eventos en jQuery</a> <small>Presentamos un repaso en profundidad a los métodos de jQuery...</small></li><li><a href='http://blog.scriptia.net/articulos/2007/01/onbeforeunload.html' rel='bookmark' title='Permanent Link: <code>onbeforeunload</code>: tiende una mano al usuario'><code>onbeforeunload</code>: tiende una mano al usuario</a> <small>¿Alguna vez has cerrado una ventana cuando tenías un formulario...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Algo que me han preguntado hoy:</p>
<blockquote><p>Choan, cariño mío, guapetón de mi alma&#8230; tengo dos campos en un formulario y quiero que uno refleje los cambios en el otro&#8230; y controlando keypress no tengo el valor actualizado</p>
</blockquote>
<p>Pues no, no lo tienes. Solución: controlar la pila de ejecución. El truco: usar un timeout para que el método que actualiza los valores se ejecute <em>después</em> de acabar con la gestión de eventos. Algo así:</p>
<pre><code>// en el manejador del evento keypress
setTimeout(updateValue, 0); // &lt;-- la clave está en el cero</code></pre>
<p>Ahora bien, lo de recoger el valor actualizado basándonos en <code>keypress</code> no es suficiente, porque hay mil maneras de rellenar el campo sin pulsar una tecla (copipegar por menús, lectores de códigos de barras, <em>yo-que-sés</em>&#8230;)</p>
<p>Así que mi consejo es <em>defenderse</em> controlando también el evento <code>blur</code>. Lo pongo en términos de jQuery, suponiendo que el campo que controlamos lleva el identificador <var>source</var> y el de destino es conocido como <var>destination</var>.</p>
<pre><code>(function($) {

  var init_copy_values = function() {
    $('#source').bind('keypress blur', function(e) {
      if (e.type == 'keypress') setTimeout(updateValue, 0);
      else updateValue();
    });
  },
  updateValue = function() {
    $('#destination').val($('#source').val());
  };

  $(init_copy_values);

}(jQuery));</code></pre>
<p>Pues nada, ya está, un post sin insultar a nadie.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/articulos/2009/12/keypress-apilado-de-eventos-control-de-valores-y-settimeout.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Vilaweb y el desarrollador tonto del haba</title>
		<link>http://blog.scriptia.net/articulos/2009/11/vilaweb-y-el-desarrollador-tonto-del-haba.html</link>
		<comments>http://blog.scriptia.net/articulos/2009/11/vilaweb-y-el-desarrollador-tonto-del-haba.html#comments</comments>
		<pubDate>Tue, 24 Nov 2009 11:52:18 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[artículos]]></category>

		<category><![CDATA[vilaweb]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/?p=184</guid>
		<description><![CDATA[Me cuentan por ahí que hoy se ha lanzado la nueva versión de Vilaweb. El culmen de las buenas prácticas en marcado HTML (sí, es sarcasmo).
Atención al siguiente fragmento, extraído del tal sitio el 24 de noviembre de 2009:
&#60;div class=&#34;zona-imatge&#34;&#62;
  &#60;img alt=&#34;Detingut el batlle de Polop per la mort del seu predecessor&#38;lt;br/&#38;gt;&#34; src=&#34;/media/portada/81/1259046000.jpg&#34; width=&#34;299&#34; [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>Me cuentan por ahí que hoy se ha lanzado la nueva versión de <a href="http://www.vilaweb.cat/">Vilaweb</a>. El culmen de las buenas prácticas en marcado HTML (sí, es sarcasmo).</p>
<p>Atención al siguiente fragmento, extraído del tal sitio el 24 de noviembre de 2009:</p>
<pre><code>&lt;div class=&quot;zona-imatge&quot;&gt;
  &lt;img alt=&quot;Detingut el batlle de Polop per la mort del seu predecessor&amp;lt;br/&amp;gt;&quot; src=&quot;/media/portada/81/1259046000.jpg&quot; width=&quot;299&quot; height=&quot;254&quot;/&gt;
  &lt;div class=&quot;params&quot; style=&quot;display: none&quot;&gt;
    &lt;div class=&quot;w&quot;&gt;299&lt;/div&gt;
    &lt;div class=&quot;h&quot;&gt;254&lt;/div&gt;
    &lt;div class=&quot;file&quot;&gt;/media/portada/81/1259046000.jpg&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>Mi comentario (versión breve): imbécil.</p>
<p>Mi comentario (versión extendida): eres tan tonto que cada vez que te documentas, en lugar de mejorar empeoras. ¿Qué demonios hacen esos «parámetros» metiendo ruido en el HTML? ¿Se te ha ocurrido, por ventura, aplicar un tipo de «no intrusividad» parida por tu genial cerebro?</p>
<p>Supongo que estarás pensando: ya te vale, Choan, despotricas y no dices nada. Así es, en efecto. Si sabes lo que está mal (fatal, punible con muerte) en ese pedazo de código no hace falta que te cuente nada. Y si no lo sabes, sigue en tu santa ignorancia, busca una multinacional en la que triunfar como un programador mediocre y haz que tu madre se sienta orgullosa de ti. Cretino.</p>
<p>(Hay otras perlas, pero la que más ganas me ha dado de ponerme faltón ha sido esta. Y sí, el diseño también me parece una mierda.)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/articulos/2009/11/vilaweb-y-el-desarrollador-tonto-del-haba.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Número de días en un mes</title>
		<link>http://blog.scriptia.net/articulos/2009/03/numero-de-dias-en-un-mes.html</link>
		<comments>http://blog.scriptia.net/articulos/2009/03/numero-de-dias-en-un-mes.html#comments</comments>
		<pubDate>Thu, 05 Mar 2009 17:09:07 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[artículos]]></category>

		<category><![CDATA[Date]]></category>

		<category><![CDATA[fechas]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/?p=166</guid>
		<description><![CDATA[Ver una vaca encima de un cobertizo no es nada comparado con las cosas que uno se encuentra en los scripts que corren por estos mundos de dios.
Uno de los campos en los que cualquier mindundi es capaz de aplicar al máximo su desconocimiento de javascript es el del cálculo de días en un mes. [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>Ver una vaca encima de un cobertizo no es nada comparado con las cosas que uno se encuentra en los scripts que corren por estos mundos de dios.</p>
<p>Uno de los campos en los que cualquier mindundi es capaz de aplicar al máximo su desconocimiento de javascript es el del cálculo de días en un mes. Utilizar una docena de condicionales es de flojos.</p>
<p>La máxima: cuando tengas que echar cuentas, sobre cualquier cosa, utiliza las herramientas del lenguaje. No hagas cuentas de la vieja.</p>
<p>El código. Función que recibe un mes (en notación numérica humana) y un año (opcional, si no se recibe tomamos el año actual) y retorna el número de días en el mes. Ningún condicional fue dañado durante el experimento.</p>
<pre><code class="javascript">function daysInMonth(humanMonth, year) {
  return new Date(year || new Date().getFullYear(), humanMonth, 0).getDate();
}
daysInMonth(2, 2009); // 28
daysInMonth(2, 2008); // 29</code></pre>
<p>Las claves:</p>
<ul>
<li>ECMAScript maneja internamente las fechas como datos numéricos (véase <a href="http://es.wikipedia.org/wiki/Tiempo_Unix" title="Tiempo Unix, Wikipedia">Tiempo Unix</a>)</li>
<li>en ECMAScript, los meses se numeran del 0 al 11 y los días de 1 a <var>N</var>. Nosotros alimentamos la función con un mes <em>humano</em>. Así que la fecha que se crea (<code>d</code>) corresponderá al día 0 del mes siguiente al que buscamos. El algoritmo de creación de fechas es tolerante (básicamente suma lo que le demos y obtiene un entero, así que el día 0 de un mes es siempre el último día del mes anterior).</li>
</ul>
<p>En fin, que todo esto va de que la máquina es más lista que tú y tus nudillos. Y que todos los blogueros juntos, incluido el menda.</p>
<h2>Adendum</h2>
<p>Podemos usar una estratagema similar para saber si el año es bisiesto:</p>
<pre><code class="javascript">function isLeapYear(year) {
  return new Date(year, 0, 366).getFullYear() == year;
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/articulos/2009/03/numero-de-dias-en-un-mes.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Trabajando con jQuery: timeline arrastrable, del espaguetismo al plugin</title>
		<link>http://blog.scriptia.net/articulos/2008/10/jquery-del-espagueti-al-plugin.html</link>
		<comments>http://blog.scriptia.net/articulos/2008/10/jquery-del-espagueti-al-plugin.html#comments</comments>
		<pubDate>Mon, 20 Oct 2008 18:44:20 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[artículos]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[plugins]]></category>

		<category><![CDATA[tutoriales]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/articulos/2008/10/jquery-del-espagueti-al-plugin.html</guid>
		<description><![CDATA[En el capítulo de hoy veremos cómo reconvertir un código espagueti en un bonito plugin reutilizable.
Objetivo del widget: permitir desplazar horizontalmente mediante arrastre (pincho, arrastro, suelto) un bloque de contenido. Si tienes prisa por ver en qué acaba la cosa, ve directamente a la demo.
Elementos: un contenedor (con overflow: auto) y su contenido. Para nuestro [...]


Related posts:<ol><li><a href='http://blog.scriptia.net/al-margen/2006/09/carrusel.html' rel='bookmark' title='Permanent Link: Carrusel'>Carrusel</a> <small>Continua la lluvia de plugins para jQuery. Esta vez nos...</small></li><li><a href='http://blog.scriptia.net/al-margen/2007/10/un-patron-de-desarrollo-de-plugins-para-jquery.html' rel='bookmark' title='Permanent Link: Un patrón de desarrollo de plugins para jQuery'>Un patrón de desarrollo de plugins para jQuery</a> <small>Mike Alsup, autor de jQuery form plugin y otras delicias,...</small></li><li><a href='http://blog.scriptia.net/articulos/2008/07/eventos-en-jquery-12.html' rel='bookmark' title='Permanent Link: Eventos en jQuery 1.2'>Eventos en jQuery 1.2</a> <small>Días ha que escribí una nota sobre los eventos en...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>En el capítulo de hoy veremos cómo reconvertir un código espagueti en un bonito plugin reutilizable.</p>
<p>Objetivo del widget: permitir desplazar horizontalmente mediante arrastre (pincho, arrastro, suelto) un bloque de contenido. Si tienes prisa por ver en qué acaba la cosa, ve directamente a <a href="http://choangalvez.nom.es/presentaciones/jquery/examples/timeline-jquery.html">la demo</a>.</p>
<p>Elementos: un contenedor (con <code>overflow: auto</code>) y su contenido. Para nuestro ejemplo:</p>
<pre><code class="html">&lt;div id="#timeline"&gt;
  &lt;ul&gt;
    &lt;li&gt;...&lt;/li&gt;
    &lt;li&gt;...&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;</code></pre>
<p>Con unos estilos tal que:</p>
<pre><code class="css">#timeline {
 width: 600px;
 height: 400px;
 overflow: auto;
}

#timeline ul {
 width: 1000px;
 margin: 0;
 padding: 0;
}

#timeline li {
 display: block;
 width: 200px;
 padding: 10px;
 margin: 0;
 float: left;
}</code></pre>
<p>Sobre estas piedras edificaremos nuestra iglesia. Veamos paso a paso el código necesario para hacer que la cosa se mueva. Pondremos en marcha la maquinaria cuando pinchemos sobre el contenedor:</p>
<pre><code class="javascript">$('#timeline')
  .bind('mousedown', function(e) {
    // aquí vendrá nuestro código
  });</code></pre>
<p>A fin de evitar el uso de variables globales, utilizarmos <code>data</code>, un método de jQuery que nos permite mantener relaciones entre valores y elementos DOM. Vamos a mantener los siguientes datos: posición actual del scroll, elemento al que afecta y posición del puntero en el momento del <code>mousedown</code>.</p>
<pre><code class="javascript">$(document)
  .data('timeline', {
    element: this,
    scroll: this.scrollLeft,
    x : e.clientX
  });</code></pre>
<p>Observa que estamos conservando los datos en <code>document</code>. En cada momento existirá un máximo de un elemento en desplazamiento.</p>
<p>Bien, ha empezado la acción&#8230; pero todavía no estamos siguiendo los movimientos del puntero. Asignemos un par de manejadores para los eventos <code>mousemove</code> y <code>mouseup</code> de <code>document</code>.</p>
<p>¿Por qué para <code>document</code> y no para el contenedor con el que estamos tratando? Aunque el puntero salga del contenedor durante el arrastre, queremos seguir desplazando el contenido. Y si saliera y no controláramos <code>mouseup</code> a nivel de documento, nuestro script nunca abandonaría el modo &#8220;estamos arrastrando cositas&#8221;.</p>
<p>Como somos chulos y modernos, aprovecharemos los eventos.con-espacio-de-nombres que jQuery gentilmente pone a nuestra disposición. Para <code>mousemove</code>, recuperamos los datos que hemos almacenado en <code>mousedown</code> y modificamos la propiedad <code>scrollLeft</code> del contenedor sumándole la diferencia entre la posición actual del ratón y la almacenada. En <code>mouseup</code>, limpiamos los datos almacenados y eliminamos los manejadores de eventos del espacio <code>timeline</code> asignados a <code>document</code>.</p>
<pre><code class="javascript">jQuery(document)
  .bind('mousemove.timeline', function(e) {
    var data = jQuery(this).data('timeline');
    data.element.scrollLeft = data.scroll + data.x - e.clientX;
  })
  .bind('mouseup.timeline', function(e) {
    jQuery(this)
      .removeData('timeline')
      .unbind('.timeline');
  });</code></pre>
<p>Para rematar, cancelaremos la acción por defecto de <code>mousedown</code> para no seleccionar texto mientras arrastramos:</p>
<pre><code class="javascript">e.preventDefault();</code></pre>
<p>Poniéndolo todo junto y dentro de una llamada a <code>ready</code>, tenemos la cosita funcionando:</p>
<pre><code class="javascript">jQuery(document).ready(function() {

  jQuery('#timeline')
    .bind('mousedown', function(e) {

      jQuery(document)
        .data('timeline', {
          element: this,
          scroll: this.scrollLeft,
          x : e.clientX
        })
        .bind('mousemove.timeline', function(e) {
          var data = jQuery(this).data('timeline');
          data.element.scrollLeft = data.scroll + data.x - e.clientX;
        })
        .bind('mouseup.timeline', function(e) {
          jQuery(this)
            .removeData('timeline')
            .unbind('.timeline');
        });

      e.preventDefault();

    });
});</code></pre>
<p>¡Genial! Con esto ya tenemos el comportamiento deseado, pero&#8230; no parece muy reutilizable. Pluguinifiquemos.</p>
<h2 id="construyendo_un_plugin">Construyendo un plugin</h2>
<p>Cuando invocamos la función <code>jQuery</code> (o su alias habitual, <code>$</code>), recuperamos un objeto. Dicho objeto tiene un prototipo. Para añadir métodos al objeto devuelto por <code>jQuery</code>, los añadimos a su prototipo. Así que algo tal que:</p>
<pre><code class="javascript">jQuery.prototype.miMetodo = function() {

};</code></pre>
<p>Ya nos serviría para ir tirando. Pero hay un idioma más <em>jotacueriesco</em> para decir lo mismo. De paso añadamos un <code>return this</code> a nuestro método para permitir el encadenamiento de llamadas:</p>
<pre><code class="javascript">jQuery.extend(jQuery.fn, {
  miMetodo : function() {
    return this;
  }
});</code></pre>
<p>Con esto ya podemos darnos el gustazo de escribir:</p>
<pre><code class="javascript">jQuery('#miCosa')
  .miMetodo()
  .etcetera();</code></pre>
<p>Pero escribir <code>jQuery</code> (que es lo que debemos hacer si queremos asegurarnos de que nuestro plugin es compatible con otras bibliotecas) una y otra vez es escribir mucho. Vamos a meter <strong>todo</strong> el código de nuestro plugin dentro de una función anónima que nos permita tener un alias <strong>seguro</strong> para <code>jQuery</code>.</p>
<pre><code class="javascript">(function($) {

})(jQuery);</code></pre>
<p>Y vamos a rellenarlo poquito a poco.</p>
<pre><code class="javascript">(function($) {
  $.extend($.fn, {
    timeline : function() {
      this
        .bind('mousedown', handleMouseDown);
      return this;
    }
  });

  function handleMouseDown(e) {
    // bla bla
  }

})(jQuery);</code></pre>
<p>Fíjate: extraemos el código de manejo del evento <code>mousedown</code>. ¿Por qué? No necesitamos ningún dato <strong>local</strong> y por tanto no necesitamos del cierre funcional para acceder a dicho dato (ni generar la función al vuelo para cada widget). Haremos lo mismo para los manejadores de <code>mousemove</code> y <code>mouseup</code>:</p>
<pre><code class="javascript">(function($) {
  $.extend($.fn, {
    timeline : function() {
      this
        .bind('mousedown', handleMouseDown);
      return this;
    }
  });

  function handleMouseDown(e) {
    $(document)
      .data('timeline', {
        element: this,
        scroll: this.scrollLeft,
        x : e.clientX
      })
      .bind('mousemove.timeline', handleMouseMove)
      .bind('mouseup.timeline', handleMouseUp);
    e.preventDefault();
  }

  function handleMouseMove(e) {
    var data = $(this).data('timeline');
    data.element.scrollLeft = data.scroll + data.x - e.clientX;
  }

  function handleMouseUp(e) {
    $(this)
      .removeData('timeline')
      .unbind('.timeline');
  }

})(jQuery);</code></pre>
<p>Con esto nuestro código espagueti ya parece algo más ordenadito. Pero un plugin sin opciones sabe a poco. Vamos a considerar la posibilidad de configurar la proporción de desplazamiento/arrastre y de decidir si ocultamos o no la barra de scroll nativa. Por partes:</p>
<pre><code class="javascript">$.extend($.fn, {
  timeline : function(opts) {
    var config = $.extend({
      speed: 1.5,
      accesible: true
    }, opts || {});

    this
      .bind('mousedown', config, handleMouseDown);

    if (!config.accesible) {
      this.css('overflow', 'hidden');
    }

    return this;
  }
});</code></pre>
<p>Ahora el método <code>timeline</code> acepta un argumento que corresponde a un objeto de configuración. Utilizamos <code>jQuery.extend</code> para aplicar los valores sobre una configuración por defecto. Y al asignar el manejador para <code>mousedown</code> lo pasamos como argumento. Si esto resulta nuevo para ti, lo que te falta saber es que con una asignación de este tipo, el manejador recibirá estos datos extra en la propiedad <code>data</code> del objeto que representa el evento. Modifiquemos el manejador para transmitir la configuración:</p>
<pre><code class="javascript">function handleMouseDown(e) {
  $(document)
    .data('timeline', {
      element: this,
      scroll: this.scrollLeft,
      x : e.clientX,
      config : e.data
    })
    .bind('mousemove.timeline', handleMouseMove)
    .bind('mouseup.timeline', handleMouseUp);
  e.preventDefault();
}</code></pre>
<p>Utilicemos la configuración en <code>handleMouseMove</code>:</p>
<pre><code class="javascript">function handleMouseMove(e) {
  var data = $(this).data('timeline');
  data.element.scrollLeft = data.scroll + (data.x - e.clientX) * data.config.speed;
}</code></pre>
<p>Y listo. Ya tenemos un plugin bastante decente. Para ponerlo en marcha:</p>
<pre><code class="javascript">jQuery(document)
  .ready(function() {
    $('el.selector-de-dios')
      .timeline({ speed: 2, accesible: false })
  });</code></pre>
<h2>Bola extra 1: configuración por defecto</h2>
<p>Si nuestro usuario siempre va a preferir la opción no accesible del plugin, no por ser idiota (u obedecer órdenes) le vamos a obligar a pasar la configuración una y otra vez. Apañemos:</p>
<pre><code class="javascript">$.extend($.fn, {
  timeline : function(opts) {
    var config = $.extend({}, $.fn.timeline.defaults, opts || {});
    // ...
    return this;
  }
});

$.fn.timeline.defaults = {
  speed: 1.5,
  accesible: true
};</code></pre>
<p>De esta manera permitimos al usuario configurar las opciones de manera global manipulando <code>jQuery.fn.timeline.defaults</code> a su antojo.</p>
<h2>Bola extra 2: mousewheel</h2>
<p>El plugin <a href="http://plugins.jquery.com/project/mousewheel" hreflang="en">mousewheel</a> permite controlar los movimientos de la ruedita del ratón. Aprovechémoslo:</p>
<pre><code class="javascript">$.extend($.fn, {
    timeline : function(opts) {
      // ...
      if ($.fn.mousewheel) {
        this
          .mousewheel(function(e, delta) {
            this.scrollLeft -= delta * config.mousewheelSpeed;
            e.preventDefault();
          });
      }
      return this;
    }
  });</code></pre>
<p>Puedes probar la combinación de todos estos elementos en la <a href="http://choangalvez.nom.es/presentaciones/jquery/examples/timeline-jquery.html">demo correspondiente</a>.</p>
<h2>Coda</h2>
<p>Choan no inventa nada nuevo, lo tratado aquí viene a ser una combinación de mis conocimientos, gustos y experiencia y lo expuesto en estos dos artículos:</p>
<ul>
<li><a href="http://jqueryfordesigners.com/fun-with-overflows/" hreflang="en" xml:lang="en" lang="en">Fun with overflows</a>, de Remy Sharp.</li>
<li><a href="http://www.learningjquery.com/2007/10/a-plugin-development-pattern" hreflang="en" xml:lang="en" lang="en">A Plugin Development Pattern</a>, de Mike Alsup.</li>
</ul>
<p>Ten presente que la arquitectura propuesta para este plugin no siempre es la más adecuada —ya hablaremos de ello— y que el plugin de ejemplo no está publicado ni oficial ni extra oficialmente y <strong>nadie</strong> te dará soporte.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/articulos/2008/10/jquery-del-espagueti-al-plugin.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>jShoulda y JsUnitTest, pruebas unitarias en JavaScript al estilo Shoulda</title>
		<link>http://blog.scriptia.net/al-margen/2008/10/jshoulda-y-jsunit-test-unit-testing-javascript.html</link>
		<comments>http://blog.scriptia.net/al-margen/2008/10/jshoulda-y-jsunit-test-unit-testing-javascript.html#comments</comments>
		<pubDate>Sat, 11 Oct 2008 16:57:45 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[al margen]]></category>

		<category><![CDATA[jShoulda]]></category>

		<category><![CDATA[JsUnitTest]]></category>

		<category><![CDATA[newjs]]></category>

		<category><![CDATA[unit-testing]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/al-margen/2008/10/jshoulda-y-jsunit-test-unit-testing-javascript.html</guid>
		<description><![CDATA[Hablábamos el otro día de QUnit, hoy hablaremos de JsUnitTest –otro sistema de testing– y de jShoulda, una capa de abstracción que un servidor ha moldeado con sus propias manos y a imagen y semejanza de Shoulda.
Principiemos hablando de JsUnitTest, un port sin dependencias del sistema de testing desarrollado para probar prototype y script.aculo.us.
¿Qué necesitamos?

jsunittest.js, [...]


Related posts:<ol><li><a href='http://blog.scriptia.net/articulos/2008/07/pruebas-unitarias-con-qunit.html' rel='bookmark' title='Permanent Link: Pruebas unitarias con QUnit'>Pruebas unitarias con QUnit</a> <small>Las pruebas unitarias (unit testing) son necesarias y convenientes, ya...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Hablábamos el otro día de <a href="http://blog.scriptia.net/articulos/2008/07/pruebas-unitarias-con-qunit.html">QUnit</a>, hoy hablaremos de JsUnitTest –otro sistema de testing– y de jShoulda, una capa de abstracción que un servidor ha moldeado con sus propias manos y a imagen y semejanza de <a href="http://www.thoughtbot.com/projects/shoulda" title="thoughtbot: Shoulda testing plugin" hreflang="en">Shoulda</a>.</p>
<p>Principiemos hablando de <a href="http://jsunittest.com/" hreflang="en">JsUnitTest</a>, un <em xml:lang="en" lang="en">port</em> <strong>sin dependencias</strong> del sistema de testing desarrollado para probar <a href="http://www.prototypejs.org/" title="Prototype JavaScript framework: Easy Ajax and DOM manipulation for dynamic web applications" hreflang="en">prototype</a> y <a href="http://script.aculo.us/" title="script.aculo.us - web 2.0 javascript" hreflang="en">script.aculo.us</a>.</p>
<h2>¿Qué necesitamos?</h2>
<ul>
<li><a href="http://jsunittest.com/dist/jsunittest.js">jsunittest.js</a>, la biblioteca de testing;</li>
<li>un documento HTML que la referencie.</li>
</ul>
<p>Algo como esto bastará:</p>
<pre><code class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;

&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
  &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/&gt;
  &lt;title&gt;Minimal JsUnitTest&lt;/title&gt;
  &lt;script src="/js/jsunittest.js" type="text/javascript"&gt;&lt;/script&gt;
  &lt;link rel="stylesheet" href="/css/unittest.css" type="text/css" media="screen"/&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;h1&gt;Minimal JsUnitTest&lt;/h1&gt;

  &lt;div id="testlog"&gt;
    Los resultados de las pruebas se muestran, por defecto
    en el elemento con id=testlog
  &lt;/div&gt;

&lt;script type="text/javascript"&gt;
  // aquí irá el código de nuestras pruebas,
  // también podemos hacer referencia a un script externo
&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h2>Cómo escribir tests con JsUnitTest</h2>
<p>Para definir y ejecutar las pruebas, creamos una instancia de <code>Test.Unit.Runner</code>:</p>
<pre><code class="javascript">new Test.Unit.Runner({});</code></pre>
<p>En el objeto de configuración que pasamos como argumento, definimos como propiedades las pruebas a realizar:</p>
<pre><code class="javascript">new Test.Unit.Runner({
  testNombreDelTest : function() {
    this.assert(true);
  },
  testOtroTest : function() {
    this.assert(true);
  }
});</code></pre>
<p>Los nombres de las propiedades correspondientes a pruebas deben comenzar por &#8220;test&#8221;. Si deseamos ejecutar funciones de preparación y limpieza antes y después de cada una de las pruebas, utilizamos las propiedades <var>setup</var> y <var>teardown</var> para definirlas:</p>
<pre><code class="javascript">new Test.Unit.Runner({
  setup : function() {
    this.foo = 1;
  },
  testNombreDelTest : function() {
    this.assert(true);
  },
  testFoo : function() {
    this.assertEqual(1, this.foo);
  }
});</code></pre>
<p>Observa: tanto las funciones de preparación como las de prueba se ejecutan en el contexto de una instancia de <code>Test.Unit.Testcase</code>. Las posibles aserciones son métodos de dicha instancia (por eso usamos <code>this</code>). También podemos utilizar <code>this</code> para mantener variables que vayamos a utilizar en nuestras pruebas.</p>
<p>La mayor parte de los métodos asertivos aceptan tres parámetros: el valor esperado, el valor real y (opcionalmente) un mensaje que el sistema nos mostrará en caso de error.</p>
<p>He aquí una lista deliberadamente incompleta de los métodos de aserción:</p>
<ul>
<li>assert</li>
<li>assertEqual</li>
<li>assertNotEqual</li>
<li>assertEnumEqual</li>
<li>assertEnumNotEqual</li>
<li>assertHashEqual</li>
<li>assertHashNotEqual</li>
<li>assertIdentical</li>
<li>assertNotIdentical</li>
<li>assertNull</li>
<li>assertNotNull</li>
<li>assertUndefined</li>
<li>assertNotUndefined</li>
</ul>
<p>Comprueban lo que su nombre parece indicar. Un detalle importante: en JavaScript, dos arrays con el mismo contenido (o dos objetos-usados-como-hashes) no pueden compararse mediante igualdad. Por tanto, si quieres comparar dos arrays necesitarás utilizar <code>assertEnumEqual</code>. Y para comparar dos objetos, <code>assertHashEqual</code>.</p>
<h2>Automatización</h2>
<p><a href="http://drnicwilliams.com/" title="Dr Nic" hreflang="en">drnic</a>, el humano detrás de JsUnitTest, es también padre de <a href="http://newjs.rubyforge.org/" title="JavaScript Project Generator">newjs</a>, un gem (si no sabes qué es un gem, ignora esta sección hasta que lo averigües) pensada para facilitar el desarrollo de bibliotecas JavaScript. Sus virtudes:</p>
<ul>
<li>incluye JsUnitTest;</li>
<li>simplifica la creación de nuevos tests;</li>
<li>automatiza la ejecución de los tests.</li>
</ul>
<p>Sin entrar en detalles. O lo ves, o no lo ves:</p>
<pre><code>$ newjs milib
      create
      create  config
      create  lib
      create  src
      create  script
      create  tasks
      create  test/assets
      create  test/unit
      create  test/functional
      create  test/assets/unittest.css
      create  test/assets/jsunittest.js
      # etcetera
  dependency  install_rubigen_scripts
      exists    script
      create    script/generate
      create    script/destroy
$ cd milib
$ script/generate unit_test basic
      exists  test/unit
      create  test/unit/basic_test.html
$ rake test_units
(in /Users/choan/Current/tirame/milib)

Started tests in Safari
.
Finished in 2 seconds.
1 tests, 1 assertions, 0 failures, 0 errors

Started tests in Firefox
.
Finished in 1 seconds.
1 tests, 1 assertions, 0 failures, 0 errors

Skipping Internet Explorer, not supported on this OS

Skipping Konqueror, not supported on this OS

Started tests in Opera
.
Finished in 3 seconds.
1 tests, 1 assertions, 0 failures, 0 errors</code></pre>
<p>Sí, amigo mío, mediante la ejecución de una tarea <a href="http://rake.rubyforge.org/" title="Rake -- Ruby Make" hreflang="en">rake</a> hemos ejecutado las pruebas en cada uno de los navegadores disponibles en nuestro sistema y hemos recogido los resultados. Algo que Chuck Norris no es capaz de hacer.</p>
<h2>jShoulda</h2>
<p>Pero vayamos con jShoulda, que yo he venido aquí a hablar de mi libro.</p>
<p><a href="http://jshoulda.scriptia.net/" hreflang="en">jShoulda</a> es una capa de abstracción para JsUnitTest que permite escribir nuestros tests al más puro estilo Shoulda. Algo así:</p>
<pre><code class="javascript">context('A context', {},
  should('run a test', function() {
    this.assert('Yay!');
  }),
)();</code></pre>
<p>¿Y qué ventaja tiene esto? Para un test vulgar, ninguna, francamente. Pero si tus pruebas requieren de inicializaciones complejas, la cosa se pone chula.</p>
<pre><code class="javascript">context('A context', {
  setup: function() {
    this.foo = 1;
  }
  },
  should('run its setup function', function() {
    this.assertEqual(1, this.foo);
  }),
  context('which is a "nested" context', {
    setup: function() {
      this.foo +=1;
    }
    },
    should('run both setup functions', function() {
      this.assertEqual(2, this.foo);
    })
  )
)();
</code></pre>
<p>Para utilizar jShoulda necesitas&#8230; <a href="http://jshoulda.scriptia.net/js/jshoulda.js">jshoulda.js</a>. Y un documento HTML como el anterior, al que añadirás la referencia a la biblioteca.</p>
<p>Pero para probarlo no necesitas descargar nada. Pásate por la <a href="http://jshoulda.scriptia.net/">página del proyecto</a>. Los resultados de pruebas que encontrarás en ella (suponiendo que la visites con JavaScript activado) corresponden al test de ejemplo ejecutado <em>en vivo</em>. Si quieres juguetear, doblecliquea en el código, modifícalo a tu gusto y pulsa el botón. Sugerencia: haz fallar las pruebas. Mola.</p>
<p>Si estás interesado en jShoulda y tu inglés no es ni mejor ni peor que el mío, lee el <a href="http://jshoulda.scriptia.net" hreflang="en">tutorial de jShoulda</a>, suscríbete a la <a href="http://groups.google.com/group/jshoulda">lista de correo</a> y, si das con algún bug, <a href="http://github.com/choan/jshoulda/tree/master" title="jShoulda en github">arréglalo</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/al-margen/2008/10/jshoulda-y-jsunit-test-unit-testing-javascript.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Pruebas unitarias con QUnit</title>
		<link>http://blog.scriptia.net/articulos/2008/07/pruebas-unitarias-con-qunit.html</link>
		<comments>http://blog.scriptia.net/articulos/2008/07/pruebas-unitarias-con-qunit.html#comments</comments>
		<pubDate>Sat, 26 Jul 2008 19:15:40 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[artículos]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[Qunit]]></category>

		<category><![CDATA[unit-testing]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/articulos/2008/07/pruebas-unitarias-con-qunit.html</guid>
		<description><![CDATA[Las pruebas unitarias (unit testing) son necesarias y convenientes, ya programes en Ruby, en PHP, en JavaScript o en Cuenca. En esta notita veremos cómo utilizar QUnit –la biblioteca creada para el testeo del núcleo de jQuery– para testear nuestros propios proyectos.

El documento base
Comencemos pues, por descargar QUnit y preparar un documento HTML con la [...]


Related posts:<ol><li><a href='http://blog.scriptia.net/al-margen/2006/08/comenzando-con-jquery.html' rel='bookmark' title='Permanent Link: Comenzando con jQuery'>Comenzando con jQuery</a> <small>Si todavía no conoces jQuery esta guía escrita por Jörn...</small></li><li><a href='http://blog.scriptia.net/al-margen/2006/08/jquery-10.html' rel='bookmark' title='Permanent Link: jQuery 1.0'>jQuery 1.0</a> <small>jQuery 1.0 está en la calle....</small></li><li><a href='http://blog.scriptia.net/al-margen/2006/09/carrusel.html' rel='bookmark' title='Permanent Link: Carrusel'>Carrusel</a> <small>Continua la lluvia de plugins para jQuery. Esta vez nos...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Las pruebas unitarias (unit testing) son <strong>necesarias</strong> y <strong>convenientes</strong>, ya programes en Ruby, en PHP, en JavaScript o en Cuenca. En esta notita veremos cómo utilizar <a href="http://docs.jquery.com/QUnit" hreflang="en">QUnit</a> –la biblioteca creada para el testeo del núcleo de <a href="http://jquery.com" hreflang="en">jQuery</a>– para testear nuestros propios proyectos.</p>
<p><span id="more-120"></span></p>
<h2>El documento base</h2>
<p>Comencemos pues, por <a href="http://dev.jquery.com/view/trunk/qunit/" hreflang="en">descargar QUnit</a> y preparar un documento HTML con la siguiente estructura:</p>
<pre><code class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;My Test Suite&lt;/title&gt;
  &lt;link rel="Stylesheet" media="screen" href="ruta/a/testsuite.css" /&gt;
  &lt;script type="text/javascript" src="ruta/a/jquery.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src="ruta/a/testrunner.js"&gt;&lt;/script&gt;

  &lt;style type="text/css" media="screen"&gt;
  /* &lt;![CDATA[ */
    #main {
      display: none;
    }
  /* ]]&gt; */
  &lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;h1&gt;My Test Suite&lt;/h1&gt;
  &lt;h2 id="banner"&gt;&lt;/h2&gt;
  &lt;h2 id="userAgent"&gt;&lt;/h2&gt;

  &lt;div id="main"&gt;
  &lt;/div&gt;

  &lt;ol id="tests"&gt;&lt;/ol&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>El elemento con <code>id="banner"</code> es utilizado por QUnit para mostrar el resultado global de la ejecución de las pruebas. En <code>id="userAgent"</code> se muestra información relativa al navegador utilizado. La lista y el detalle de la ejecución de cada prueba se genera en <code>id="tests"</code>.</p>
<p>En caso de disponer de <a href="http://getfirebug.com/" hreflang="en">Firebug</a>, QUnit volcará abundante y útil información en la consola.</p>
<p>Si necesitamos un fragmento de HTML para la ejecución de las pruebas, lo incluiremos en <code>id="main"</code>. Ojo: antes de la ejecución de cada test se devuelve el contenido de este elemento a su estado inicial, esto es, no se mantienen los eventos asignados ni las modificaciones realizadas sobre el árbol en tests anteriores.</p>
<h2>Nuestro primer test</h2>
<p>Al ajo. La ejecución de una prueba implica una llamada a la función <code>test</code>, pasando como parámetros una cadena identificativa y la referencia a una función en la que se realizan las comprobaciones (aserciones).</p>
<p>La más sencilla de las comprobaciones es <code>ok</code>. Si el parámetro que recibe evalúa a <code>true</code>, el resultado se considera satisfactorio.</p>
<p>Poniendo los dos últimos párrafos en código:</p>
<pre><code class="javascript">test('Prueba minimalista', function(){
  ok(1, 'mi mensajito');
});</code></pre>
<p>Incorpora esas líneas a tu documento de pruebas (dentro de un elemento <em class="element">SCRIPT</em>) y échale un vistazo en el navegador. ¿Todo bien?</p>
<h2>Comprobaciones varias</h2>
<p>Por supuesto disponemos de otros métodos de comprobación de resultados, estos son los fundamentales:</p>
<dl>
<dt><code>equals(unArgumento, otroArgumento, mensaje)</code></dt>
<dd>Comprueba la igualdad de dos argumentos primitivos.</dd>
<dt><code>isSet(unArray, otroArray, mensaje)</code></dt>
<dd>Comprueba que dos arrays tienen el mismo contenido.</dd>
<dt><code>isObject(unObjeto, otroObjeto, mensaje)</code></dt>
<dd>Comprueba que dos objetos tienen los mismos valores asignados a las mismas propiedades.</dd>
</dl>
<h2>Módulos</h2>
<p>Si utilizamos el mismo documento para probar distintas partes de nuestra biblioteca podemos utilizar la función <code>module</code> para dar nombre a las secciones de la suite.</p>
<pre><code class="javascript">module('Widget de votaciones');
test('tras la inicialización'), function() {
  // inicializamos un widget, etc.
  equals($('a.rate', widget).length, 5, 'contiene 5 estrellicas');
});

test('etcetera', function() {
  // otro test por aquí
});</code></pre>
<h2>Expectaciones</h2>
<p>Todo lo que puede fallar, falla (de hecho, si practicas el desarrollo basado en pruebas, lo primero que debería hacer cada test es fallar). Para indicar el total de comprobaciones que se realizarán en una prueba, utilizamos la función <code>expect</code>.</p>
<pre><code class="javascript">module('expectaciones');
test('un test', function() {
  expect(3);
  ok(1, 'una');
  equals(1 + 1, 2, 'dos');
  equals(calculoCasiImposible(), 42, 'y tres');
});</code></pre>
<p>De esta manera, si la ejecución de <code>calculoCasiImposible</code> (la tercera comprobación) falla estrepitosamente, la prueba no se da por buena.</p>
<h2>Asincronía y pausas</h2>
<p>Si realizamos peticiones asíncronas en nuestros tests, necesitaremos detener la ejecución de la serie y reanudarla cuando convenga. Los métodos <code>stop</code> y <code>start</code> hacen lo que su nombre parece indicar.</p>
<pre><code class="javascript">module('asincronía');
test('con pausa', function() {
  expect(2);
  ok(1, 'una');
  function my_callback(response, status) {
    start();
    equals(response, '1', 'el servidor devuelve lo que toca');
  }
  // detenemos la ejecución de las pruebas
  stop();
  // lanzamos una petición Ajax
  $.get(some_url, my_callback);
});
</code></pre>
<p>Si quieres empaparte de pruebas escritas con y para QUnit, lo mejor es que descargues una <a href="http://jqueryjs.googlecode.com/files/jquery-1.2.6-release.zip">una release completa de jQuery</a> y bucees en sus entrañas.</p>
<p>Y esto ha sido todo. La semana que viene más y más sexy (si cabe).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/articulos/2008/07/pruebas-unitarias-con-qunit.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Eventos en jQuery 1.2</title>
		<link>http://blog.scriptia.net/articulos/2008/07/eventos-en-jquery-12.html</link>
		<comments>http://blog.scriptia.net/articulos/2008/07/eventos-en-jquery-12.html#comments</comments>
		<pubDate>Thu, 17 Jul 2008 00:45:58 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[artículos]]></category>

		<category><![CDATA[eventos]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[tutoriales]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/articulos/2008/07/eventos-en-jquery-12.html</guid>
		<description><![CDATA[Días ha que escribí una nota sobre los eventos en jQuery. Y hora es de ampliar dicho artículo con las novedades que la serie 1.2 de jQuery añade al respecto.

Lo de siempre
Recordemos las bases de la asignación y el manejo de eventos en jQuery. La forma básica de asignar un manejador es la siguiente:
$('un.selector')
  [...]


Related posts:<ol><li><a href='http://blog.scriptia.net/articulos/2006/12/eventos-en-jquery.html' rel='bookmark' title='Permanent Link: Eventos en jQuery'>Eventos en jQuery</a> <small>Presentamos un repaso en profundidad a los métodos de jQuery...</small></li><li><a href='http://blog.scriptia.net/al-margen/2007/10/un-patron-de-desarrollo-de-plugins-para-jquery.html' rel='bookmark' title='Permanent Link: Un patrón de desarrollo de plugins para jQuery'>Un patrón de desarrollo de plugins para jQuery</a> <small>Mike Alsup, autor de jQuery form plugin y otras delicias,...</small></li><li><a href='http://blog.scriptia.net/articulos/2008/06/ajax-eventos-y-jquery.html' rel='bookmark' title='Permanent Link: Ajax, eventos y jQuery'>Ajax, eventos y jQuery</a> <small>Un «problema» con el que todo novato de la programación...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Días ha que escribí una nota sobre los <a href="http://blog.scriptia.net/articulos/2006/12/eventos-en-jquery.html">eventos en jQuery</a>. Y hora es de ampliar dicho artículo con las novedades que la serie 1.2 de jQuery añade al respecto.</p>
<p><span id="more-119"></span></p>
<h2>Lo de siempre</h2>
<p>Recordemos las bases de la asignación y el manejo de eventos en jQuery. La forma básica de asignar un manejador es la siguiente:</p>
<pre><code class="javascript">$('un.selector')
  .bind('click', unaFuncion);</code></pre>
<p>El manejador (<code>unaFuncion</code>) recibe como parámetro el objeto que representa el evento (normalizado para tener acceso común a sus propiedades en los distintos navegadores). La función se ejecuta en el contexto del elemento al que se ha asignado el manejador.</p>
<pre><code class="javascript">function unaFuncion(e) {
	console.log('Contexto', this);
	console.log('Evento', e);
}

$('un.selector')
	.bind('click', unaFuncion);</code></pre>
<h2>Lo nuevo</h2>
<p>Con jQuery 1.2 podemos asignar un manejador para varios eventos con una sola llamada a <code>bind()</code>. Utilizamos para ello una lista de nombres de evento separados por espacios. Observa que en el manejador tomamos una decisión basada en la propiedad <code>type</code> del objeto del evento.</p>
<pre><code class="javascript">function handle(e) {
  var $label = $(this).prev();
  if (e.type == 'focus') {
    $label.hide();
  }
  else if (this.value == '') {
    $label.show();
  }
}

$('#login input')
  .filter('[type=text], [type=password]')
    .bind('focus blur', handle);</code></pre>
<p>Otra novedad interesante es la <em>pseudonombrespaciación</em> de eventos, que se puede practicar utilizando el nombre del evento seguido de un punto y un identificador arbitrario al asignar el manejador.</p>
<p>Y esto, ¿para qué? Para facilitar la eliminación de grupos de manejadores.</p>
<pre><code class="javascript">// en algún lugar del código de un drag'n'drop
$(document)
  .bind('mousemove.rock_n_roll', some_handler)
  .bind('mouseup.rock_n_roll', mouseup_handler);

// en el código de finalización del arrastre
$(document)
  .unbind('.rock_n_roll');</code></pre>
<p>Y algo que no es exactamente nuevo pero mola todo y se conoce poco: podemos pasar un objeto de datos en la asignación. El manejador lo recibirá en la propiedad <code>data</code> del evento.</p>
<pre><code class="javascript">function handle_click(e) {
  alert(e.data.foo);
}

$.fn.somePlugin(opts) {
  var settings = $.extend({
    foo: 'bar'
  });
  this.bind('click', settings, handle_click);
  return this;
}

// mostrará "bar" al activar los enlaces
// con clase "tigre"
$('a.tigre').somePlugin();

// mostrará "tolo" al activar los enlaces
// con clase "leon"
$('a.leon').somePlugin({ foo: 'tolo' });</code></pre>
<p>Por último, se incorpora a la API el método <code>triggerHandler</code> que complementa a <code>trigger</code>. La diferencia: <code>triggerHandler</code> dispara los manejadores asignados al evento pero no ejecuta las acciones por defecto del navegador.</p>
<p>Para más y mejor información y, de paso, practicar el inglés: <a href="http://docs.jquery.com/Release:jQuery_1.2/Events" hreflang="en" xml:lang="en" lang="en">Release: jQuery 1.2/Events</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/articulos/2008/07/eventos-en-jquery-12.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Ajax, eventos y jQuery</title>
		<link>http://blog.scriptia.net/articulos/2008/06/ajax-eventos-y-jquery.html</link>
		<comments>http://blog.scriptia.net/articulos/2008/06/ajax-eventos-y-jquery.html#comments</comments>
		<pubDate>Wed, 18 Jun 2008 22:38:44 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[artículos]]></category>

		<category><![CDATA[eventos]]></category>

		<category><![CDATA[inicialización]]></category>

		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/articulos/2008/06/ajax-eventos-y-jquery.html</guid>
		<description><![CDATA[Un «problema» con el que todo novato de la programación con jQuery se encuentra tarde o temprano (y las listas de correo lo demuestran) es que el contenido cargado (o generado) dinámicamente no dispara los manejadores de eventos asignados en $(document).ready.

Y, hoygan, esto es de lo más normal.
Si repasamos nuestra forma habitual de trabajar con [...]


Related posts:<ol><li><a href='http://blog.scriptia.net/articulos/2006/12/eventos-en-jquery.html' rel='bookmark' title='Permanent Link: Eventos en jQuery'>Eventos en jQuery</a> <small>Presentamos un repaso en profundidad a los métodos de jQuery...</small></li><li><a href='http://blog.scriptia.net/articulos/2008/07/eventos-en-jquery-12.html' rel='bookmark' title='Permanent Link: Eventos en jQuery 1.2'>Eventos en jQuery 1.2</a> <small>Días ha que escribí una nota sobre los eventos en...</small></li><li><a href='http://blog.scriptia.net/al-margen/2006/08/comenzando-con-jquery.html' rel='bookmark' title='Permanent Link: Comenzando con jQuery'>Comenzando con jQuery</a> <small>Si todavía no conoces jQuery esta guía escrita por Jörn...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Un «problema» con el que todo novato de la programación con jQuery se encuentra tarde o temprano (y las listas de correo lo demuestran) es que el contenido cargado (o generado) dinámicamente no dispara los manejadores de eventos asignados en <code>$(document).ready</code>.</p>
<p><span id="more-118"></span></p>
<p>Y, <em>hoygan</em>, esto <strong>es de lo más normal</strong>.</p>
<p>Si repasamos nuestra forma habitual de trabajar con jQuery, y reflexionamos un poquito&#8230;</p>
<pre><code class="javascript">$(document).ready(function() {
  $('selecciono.algo')
    .bind('click', hazCosasBonitas);
});</code></pre>
<p>&#8230; recordaremos que estamos utilizando <code>$(document).ready</code> porque <strong>no podemos seleccionar elementos que no existen</strong>. De ahí que tengamos que esperar a disponer de un árbol DOM completo. De ahí que los manejadores de eventos no afecten a elementos <strong>nuevos</strong>.</p>
<p>¿Entonces?</p>
<p>Opciones las hay adecuadas a unos casos y a otros. La más sencilla, para casos sencillos, es inicializar los contenidos nuevos una vez los hayamos insertado en el documento.</p>
<p>Necesitamos, pues, una función que nos permita seleccionar y actuar dentro de un contexto. Recuerda que jQuery provee de selecciones basadas en contexto. Si utilizas</p>
<pre><code class="javascript">$('a');</code></pre>
<p>seleccionarás todos los enlaces del documento. Pero si usas</p>
<pre><code class="javascript">$('a', unElementoSelecto);</code></pre>
<p>seleccionarás los enlaces descendientes de <var>unElementoSelecto</var>.</p>
<p>Por tanto, podemos crear nuestra función de inicialización según contexto como sigue.</p>
<pre><code class="javascript">function initLinks(context) {
  $('a', context)
    .bind('click', hazCosasBonitas)
}</code></pre>
<p>Que ejecutaremos desde nuestro manejador para <code>$(document).ready</code>, pasando el documento como contexto de búsqueda:</p>
<pre><code class="javascript">$(document).ready(function() {
  initLinks(document);
});</code></pre>
<p>Así que estamos como al principio&#8230; pero mucho más cerca del final. Lo único que nos queda por hacer es ejecutar <code>initLinks</code> cuando recuperemos nuevo contenido. Si usamos <code>load</code>, el más simplón de los métodos Ajax de jQuery, basta con usar una función de callback:</p>
<pre><code class="javascript">function loadNewContent() {
  $('#holder').load('ajax-content.html #response p', function() {
    // `this` apunta al elemento que acabamos de rellenar
    initLinks(this);
  });
}</code></pre>
<p>Y esta es la idea básica, que he reflejado en esta <a href="http://choangalvez.nom.es/presentaciones/jquery/examples/ajax-content.html">pequeña demo en latín</a>.</p>
<p>Por supuesto, hay otras opciones. Si eres de los que para clavar un clavo usa un plugin, échale un vistazo a <a href="http://docs.jquery.com/Plugins/livequery" hreflang="en">LiveQuery</a>; si tienes un serio trasiego de elementos <em>vivos</em>, mejor apostar por la delegación de eventos. Pero esas son otras historias que contaré a su debido momento.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/articulos/2008/06/ajax-eventos-y-jquery.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Taller de jQuery en The Cocktail el 29 de mayo</title>
		<link>http://blog.scriptia.net/al-margen/2008/05/taller-de-jquery-en-the-cocktail-el-29-de-mayo.html</link>
		<comments>http://blog.scriptia.net/al-margen/2008/05/taller-de-jquery-en-the-cocktail-el-29-de-mayo.html#comments</comments>
		<pubDate>Mon, 19 May 2008 14:33:43 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[al margen]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[presentaciones]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/al-margen/2008/05/taller-de-jquery-en-the-cocktail-el-29-de-mayo.html</guid>
		<description><![CDATA[Los muchachos de The Cocktail me han invitado a impartir un taller de jQuery en The Cocktail Academy.
Será el jueves 29 de mayo de 2008, a partir de las las 19.30h en los locales de Salamanca, 17 (Madrid). Si piensas asistir (es gratis), inscríbete cuanto antes en el wiki de los talleres.
Una pista de por [...]


Related posts:<ol><li><a href='http://blog.scriptia.net/al-margen/2006/08/comenzando-con-jquery.html' rel='bookmark' title='Permanent Link: Comenzando con jQuery'>Comenzando con jQuery</a> <small>Si todavía no conoces jQuery esta guía escrita por Jörn...</small></li><li><a href='http://blog.scriptia.net/al-margen/2006/08/jquery-10.html' rel='bookmark' title='Permanent Link: jQuery 1.0'>jQuery 1.0</a> <small>jQuery 1.0 está en la calle....</small></li><li><a href='http://blog.scriptia.net/al-margen/2006/09/carrusel.html' rel='bookmark' title='Permanent Link: Carrusel'>Carrusel</a> <small>Continua la lluvia de plugins para jQuery. Esta vez nos...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Los muchachos de <a href="http://www.the-cocktail.com/" title="The Cocktail: consultora de experiencia de usuario y diseño de interacción">The Cocktail</a> me han invitado a impartir un taller de <a href="http://jquery.com/" hreflang="en">jQuery</a> en <a href="http://aulathecocktail.pbwiki.com/" lang="en" xml:lang="en">The Cocktail Academy</a>.</p>
<p>Será el jueves 29 de mayo de 2008, a partir de las las 19.30h en los locales de <a href="http://maps.google.com/maps?q=c%2F+Salamanca+17,+Madrid,+Madrid+28020">Salamanca, 17</a> (Madrid). Si piensas asistir (es gratis), <a href="http://aulathecocktail.pbwiki.com/jQuery,+haz+m%C3%A1s+con+menos+c%C3%B3digo">inscríbete</a> cuanto antes en el wiki de los talleres.</p>
<p>Una pista de por donde irán los tiros. Hablaremos de:</p>
<ul>
<li>selección de elementos, filtrado, etc.;</li>
<li>eventos a fondo, incluyendo delegación de eventos y sus ventajas;</li>
<li>navegación por el DOM;</li>
<li>algún que otro truquito de lo más chachipiruli.</li>
</ul>
<p>Y por supuesto, de algunas razones para usar (o no usar) jQuery.</p>
<p>Después del taller, estáis todos invitados a pagarme unas cañas.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/al-margen/2008/05/taller-de-jquery-en-the-cocktail-el-29-de-mayo.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Embellecedor de código javascript</title>
		<link>http://blog.scriptia.net/al-margen/2007/11/embellecedor-de-codigo-javascript.html</link>
		<comments>http://blog.scriptia.net/al-margen/2007/11/embellecedor-de-codigo-javascript.html#comments</comments>
		<pubDate>Thu, 22 Nov 2007 12:02:10 +0000</pubDate>
		<dc:creator>choan</dc:creator>
		
		<category><![CDATA[al margen]]></category>

		<category><![CDATA[embellecedores]]></category>

		<category><![CDATA[herramientas]]></category>

		<guid isPermaLink="false">http://blog.scriptia.net/al-margen/2007/11/embellecedor-de-codigo-javascript.html</guid>
		<description><![CDATA[¿Diste con un código que te gustaría estudiar y está compactado en una línea? Beautify Javascript reformatea cualquier cosa para convertirla en algo legible.
Visto en Sentido web.



Related posts:<ol><li><a href='http://blog.scriptia.net/al-margen/2006/07/javascript-shell.html' rel='bookmark' title='Permanent Link: JavaScript Shell'>JavaScript Shell</a> <small>Una herramienta que uso a diario. Tan pequeña como un...</small></li><li><a href='http://blog.scriptia.net/articulos/2006/07/de-como-comprimir-ficheros-javascript.html' rel='bookmark' title='Permanent Link: De cómo comprimir ficheros javascript'>De cómo comprimir ficheros javascript</a> <small>Ahora que javascript comienza a perder la fama de lenguaje...</small></li><li><a href='http://blog.scriptia.net/al-margen/2007/06/herramientas-de-desarrollo-web-para-internet-explorer.html' rel='bookmark' title='Permanent Link: Herramientas de desarrollo web para Internet Explorer'>Herramientas de desarrollo web para Internet Explorer</a> <small>John Hrvatin presenta en IE Blog una serie de herramientas...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>¿Diste con un código que te gustaría estudiar y está compactado en una línea? <a href="http://elfz.laacz.lv/beautify/" hreflang="en" lang="en" xml:lang="en">Beautify Javascript</a> reformatea cualquier cosa para convertirla en algo legible.</p>
<p>Visto en <a href="http://sentidoweb.com/2007/11/20/beautify-javascript-aclara-codigo-javascript.php">Sentido web</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.scriptia.net/al-margen/2007/11/embellecedor-de-codigo-javascript.html/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
