Moderador del foro: ZorG  
jQuery
GUARAGUAO
Mensajes: 2362
Reputación: 81
Mensaje Nº 121 | 2:19 PM
Supersized 3.2 – Fullscreen Slideshow jQuery Plugin


Supersized es un script que permite crear presentaciones de diapositivas de fondo y ha pantalla completa, todo bajo la librería jQuery.

Es versión de Supersized tiene temas, vínculos directos de diapositivas, precarga dinámica, y una API.

Características
  • Cambia el tamaño de las imágenes para llenar completamente el navegador, manteniendo obvio la dimensión de la imagen
  • Ciclos de fondos a través de diapositivas con transiciones y precarga dinámica
  • Posee la versión base disponible para aquellos que sólo quieren cambiar el tamaño del fondo.
  • Controles de navegación con soporte para teclado
  • Integración con Flickr – tirar fotos del usuario, establecido o grupo
  • Dirígete a la página del proyecto para todos los detalles.

    Nuevo en Supersized 3.2
  • Completa reescritura del guión para imágenes super grandes.
  • Más opciones, incluida la capacidad para prevenir las diapositivas que se corten en carga.
  • Puedes ahora enlazar directamente a las diapositivas
  • API que te  permite llamar a funciones de forma directa (por ejemplo, el efecto / pausa, siguiente, anterior, y saltar directamente a una diapositiva)
  • Los archivos de los themes están separados de los archivos de base, lo que hará que las actualizaciones sean mucho más fácil. El Shutter theme está incluido en cada descarga.
  • Flickr no está actualizado a 3.2 (trabajando en eso)

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
  • lhmanuel
    Mensajes: 1
    Reputación: 0
    Mensaje Nº 122 | 3:27 PM
    Hola Guaraguo,

    Buenísimo tu script "Plugin jQuery ticker de noticias dinámico" (dwDinaNews). una pregunta: se puede usar distintos tiempos de retardo para cada li (noticia)?

    Un saludo y muchas gracias por compartir tus conocimientos con los que como yo empezamos en esto.

    manuel.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 123 | 3:20 PM
    TransformJS: efectos con jQuery


    Con el siguiente plugin para jQuery se pueden realizar transformaciones y efectos en 3D y 2D utilizando las propiedades del framework y las propias de CSS.

    Transform.js
    Aunque el proyecto se encuentra en fase Beta, se puede utilizar para transformar y realizar, por ejemplo, efectos 3D y 2D en imágenes.

    Para comenzar a utilizarlo sólo tendremos que descargar el plugin, descomprimirlo y copiar el siguiente código:

    Code
    $(document).ready(function() {
             $('#forward').click(function() {
               $('#test').animate({
                 translateX:'-=150',
                 translateY:'+=150',
                 scale:'+=2',
                 rotateY: '+='+(2*Math.PI),
                 rotateX: '+='+Math.PI,
                 rotateZ: '+='+Math.PI
               },1500);
             });   

             $('#backward').click(function() {
               $('#test').animate({
                 translateX:'+=150',
                 translateY:'-=150',
                 scale:'-=2',
                 rotateY: '-='+(2*Math.PI),
                 rotateX: '-='+Math.PI,
                 rotateZ: '-='+Math.PI
               },1500);
             })
    });


    Esto crea dos animaciones. La primera al hacer clcik sobre el elemente #forward que aumenta la imagen usando un efecto 3D y la otra al pulsar sobre #backward que reduce la imagen usando el mismo efecto. Para ver la demo del efecto en funcionamiento puedes ir al sitio oficial del proyecto.



    Transform.js es compatible con la gran mayoría de navegadores modernos: Safari, Chrome, Firefox, Opera, e [/b]IE. Aunque no todas las propiedades están disponibles por igual, en la siguiente tabla podemos consultar el soporte.

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 124 | 5:55 PM
    Animaciones con jQuery


    Las animaciones han formado parte de los sitios web casi desde que estos representan un interés comercial, es tal el vínculo que se ha establecido, que es difícil recordar un sitio que no haya intentado vender o mostrar una innovación sin mostrarnos una animación, aunque claro existen sus excepciones muy marcadas, pero no todos somos un Google como para prescindir de ellas.

    Si bien su implementación ha ido evolucionado, realizando animaciones a través de distintas formas de desarrollo, desde aquellos precarios gifs que intentaban darle dinamismo a un sitio pero terminaban aturdiendo al usuario, hasta la secuencia de acción desarrollada con flash, su propósito sigue siendo el mismo y se basa en entretener al usuario para que de alguna manera se logre llamar su atención.

    Animaciones con Flash
    Al mirar un sitio en Flash nos maravillamos con la gran cantidad de ideas que se hacen animación, grandiosos efectos, sincronización con canciones y sonidos, codificación y programación de botones, alta calidad de imágenes y estilización del sitio; todo esto nos hace querer aprender a programar en Flash de inmediato y comenzar a desarrollar esta clase de sitios, después de todo quien no puede considerar genial un sitio que se encuentra literalmente en movimiento constante.

    Pero no todo es dulzura en el mundo de Flash, al momento de cargar un sitio desarrollado con esta tecnología nos damos cuenta que es muy demandante tanto para el servidor como para el cliente, el tiempo de respuesta hace meditar más de una vez antes de usarlo, y el hecho de buscar una optimización resulta casi imposible, ni hablar del SEO, una palabra mostrada en Flash no puede ser rastreado por muchos buscadores, el contenido se puede perder y un usuario no puede rastrear lo que tratamos de mostrarle.

    Animaciones con JavaScript
    Hasta hace unos años era prácticamente imposible pensar que JavaScript nos podía ofrecer la funcionalidad de crear animaciones, las dificultades que se presentaban al mostrar contenido en browsers con distinto motor y la lentitud de las implementaciones, hacían que el mostrar una animación fuera verdaderamente difícil.
    Afortunadamente con el tiempo y la estandarización, se fue mejorando estos aspectos llegando los frameworks, que nos han permitido realizar animaciones con simples sentencias que utilizan el core de JavaScript para llevarlas a cabo.

    Debemos aclarar que las animaciones con JavaScript son mucho más sencillas y menos complejas que las realizadas con Flash, claro no hay un limite que nos diga que no podemos explorar más allá y la imaginación e inteligencia de varios puede hacer maravillas con el uso de JavaScript, simplemente debemos decir que es mucho más común utilizar este lenguaje para animaciones sencillas del lado cliente.

    Mostrar y ocultar elementos con jQuery
    jQuery fue uno de los primeros frameworks que se preocupo por facilitar el acceso a las animaciones y entre los efectos dinámicos más comunes en su implementación esta el esconder y mostrar elementos que se encuentran en el DOM de nuestro sitio. Con el tiempo, en este manual, abarcaremos animaciones un poco más elegantes pero no hay mejor introducción que un efecto tan esencial como el mostrar y ocultar.

    Los comandos jQuery para mostrar y ocultar elementos son bastante fáciles de recordar pues basta con saber las palabras mostrar y ocultar en ingles para aplicarlos. El comando show() para mostrar elementos y el comando hide() para ocultarlos, serán los encargados de llevar a cabo este efecto sin utilizar parámetro alguno.

    Su aplicación es de la siguiente manera:

    Code
    jQuery("#soyUnElemento").show();
    jQuery("#soyUnElemento").hide();


    Como se puede apreciar simplemente envolvemos un elemento o un conjunto y aplicamos la función. Estas funciones pueden llamarse desde alguna otra función, o mediante eventos como clicks, por ejemplo si quisiéramos que un elemento se oculte al momento de dar click sobre un conjunto abarcado por un clase, entonces haríamos algo como esto:

    Code
    jQuery(".elementosClick").click(function(){ jQuery("#soyUnElemento").hide(); });


    Si bien estos comandos son bastantes sencillos, hay que tener algunos factores en mente al momento de aplicarlos, como el hecho de que al momento de ocultar un elemento lo único que hace jQuery es cambiar el valor de la propiedad display de CSS a none, mientras que show() dará el valor de block a esta propiedad al momento de aplicarse.

    Conclusión
    Muchos consideran a las animaciones como algo extra, un lujo incluso, y si bien no están totalmente desubicados debemos aclarar que en estos tiempos realizar una animación no es demandante para el servidor y es muy fácil de realizar para el desarrollador, por lo que más que un capricho puede considerarse una herramienta que al final nos puede facilitar vender algún producto o darle un estilo único a nuestro sitio que le permita al usuario identificarlos sobre los demás.

    Esta solo fue una pequeña introducción de lo que veremos más adelante, las animaciones con jQuery es un tema bastante interesante del cual trataremos de abarcar lo más posible, explicando a detalle aquellas animaciones que sean más útiles para nuestros sitios.

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 125 | 1:40 PM
    Scroll infinito AJAX con jQuery


    Infinite AJAX Scroll es un plugin jQuery que sirve para recargar contenido sin la necesidad de refrescar la pagina completa, algo exactamente igual a lo que hacen sitios como Facebook o Twitter que utilizan la posición de la barra de scroll para cargar contenido bajo demanda.

    Para el que no conoce esta técnica de scroll infinito, la misma funciona de una forma muy sencilla y que consiste en cargar el contenido al detectar que el usuario llego al final del documento mediante la barra de scroll. De esta forma podemos cargar nuevo contenido mediante una llamada AJAX, cargando el nuevo a continuación del que ya se encontraba listado. Una practica muy interesante y practica de cara al usuario.

    Si bien parece un poco complicado, implementar una solución de este tipo es muy sencillo si utilizamos algunos de los plugins disponibles, en esta oportunidad estamos hablando de Infinite AJAX Scroll que cuenta con algunas mejoras interesantes.



    Una de las grandes ventajas de este plugin, y que alternativas similares no tiene, es que modifica la dirección de la barra del navegador a medida que vamos cargando nuevo contenido, mostrando de forma sencilla la posición exacta del nuevo contenido cargado recientemente mediante AJAX.

    Ejemplo de uso
    Code
    jQuery.ias({
       container     : ".listing",
       item          : ".post",
       pagination    : "#content .navigation",
       next          : ".next-posts a",
       loader        : "images/loader.gif"
    });


    Un pequeño consejo, si van a implementar este tipo de soluciones les recomiendo leer el apartado de Google Analytics referido al seguimiento de eventos AJAX, ya que es posible monitorear y contabilizar este tipo de eventos, que en lugar de recargar el sitio completo carga solamente una porción de contenido. De esta forma no van a perder el control sobre las paginas vistas de su sitio web.

  • DEMO
  • DESCARGA

    Web: Infinite AJAX Scroll

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
  • GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 126 | 3:43 PM
    jQuery: Tutorial del uso básico de jQuery


    Con algo más de 4 años de vida, jQuery se ha convertido en la librería JavaScript más utilizada actualmente, y es que, además, es gratuita, de código abierto (bajo licencia MIT y GPL v2) e increíblemente ligera. Entre sus usuarios podemos encontrar a Google, Microsoft, IBM, Amazon, Twitter, WordPress, Mozilla o Drupal.

    Para poder utilizar esta librería lo primero que tendremos que hacer será incluir su código en nuestro proyecto. Podemos descargar el script desde su página web, subirlo a nuestro servidor, y ejecutarlo con la etiqueta script:

    Code
    <script type="text/javascript" src="jquery.js"></script>


    También podemos cargarla directamente desde el CDN que mantiene Google:
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

    el de Microsoft:
    Code
    <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js"></script>


    o el del propio jQuery
    Code
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>


    Independientemente de la opción elegida, ya estaremos listos para comenzar a trabajar con la librería. Sin embargo, y aunque no es estrictamente necesario, os aconsejaría tener unos conocimientos básicos de JavaScript primero, conocimientos que podéis obtener con nuestro tutorial de JavaScript. Y ahora, manos a la obra.
    El corazón de jQuery es la función sobrecargada del mismo nombre, jQuery, que ofrece distinta funcionalidad dependiendo de los parámetros utilizados. Además, como JavaScript también toma conceptos del paradigma funcional, y las funciones no son más que otro tipo de objeto, la función jQuery cuenta a su vez con distintas propiedades y métodos. La intención de esta decisión de diseño es la de evitar llenar el espacio de nombres global con montones de nombres inútiles esperando a colisionar.

    Si queremos escribir menos y que nuestros archivos sean más pequeños, y si no utilizamos ninguna otra librería que pueda causar algún conflicto con este símbolo, también podemos utilizar el alias $ en sustitución de jQuery.

    Selectores jQuery
    El primer paso a la hora de trabajar con jQuery es seleccionar los elementos del árbol de documento sobre los que queremos trabajar. Para ello se utiliza la función jQuery, pasando como argumento a la función una cadena con un selector, la mayoría de los cuales utilizan una sintaxis similar a la de CSS 3. El engine que utiliza jQuery para seleccionar elementos se llama Sizzle, y puede descargarse y utilizarse de forma aislada.

    Los distintos selectores que podemos utilizar son los siguientes:

    Selectores básicos
    Selector universal: selecciona todos los elementos de la página (CSS 2)
    Code
    jquery("*")


    Selector de tipo o etiqueta: selecciona todos los elementos con el tipo de etiqueta indicado (CSS 1)
    Code
    jQuery("div")


    Selector de clase: selecciona todos los elementos con la clase indicada (atributo class) (CSS 1)
    Code
    jQuery("div.entrada")


    Selector de identificador: selecciona el elemento con el identificador (atributo id) indicado (CSS 1)
    Code
    jQuery("div#cabecera")


    Grupos de selectores: se puede combinar el resultado de varios selectores distintos separándolos con comas (CSS 1)
    Code
    jquery("p,div,a")


    Selectores de atributos
    Selector de atributo: selecciona elementos que tengan un cierto atributo (CSS 2)
    Code
    jquery("a[rel]")


    También se puede seleccionar aquellos que tengan un cierto valor para un atributo (CSS 2)
    Code
    jquery("a[rel='nofollow']")


    O que tengan un valor distinto del indicado (jQuery)
    Code
    jQuery("a[rel!='nofollow']")


    Aquellos cuyo valor empieza por una cierta cadena (CSS 3)
    Code
    jquery("a[href^='http://infrabios.com/']")


    Los que terminan con una cierta cadena (CSS 3)
    Code
    jquery("a[href$='.com']")


    Y los que contienen una cierta cadena (CSS 3)
    Code
    jquery("a[href*='Bios']")


    Por último, podemos hacer combinaciones de todo lo anterior (CSS 2)
    Code
    jquery("a[rel='nofollow'][href]")


    Selectores de widgets
    Pseudo clase botón: selecciona todos los botones (jQuery)
    Code
    jquery(":button")


    Pseudo clase checkbox: selecciona todos los checkboxes (jQuery)
    Code
    jquery(":checkbox")


    Pseudo clase archivo: selecciona todos los widgets de tipo archivo (jQuery)
    Code
    jquery(":file")


    Pseudo clase cabeceras: selecciona todas las cabeceras (jQuery)
    Code
    jquery(":header")


    Pseudo clase imagen: selecciona todas las imágenes (jQuery)
    Code
    jquery(":image")


    Pseudo clase input: selecciona todos los widgets de tipo input (jQuery)
    Code
    jquery(":input")


    Pseudo clase contraseña: selecciona todos los elementos password (jQuery)
    Code
    jquery(":password")


    Pseudo clase radiobutton: selecciona todos los elementos radiobutton (jQuery)
    Code
    jquery(":radio")


    Pseudo clase reset: selecciona todos los elementos reset (jQuery)
    Code
    jquery(":reset")


    Pseudo clase seleccionado: selecciona las opciones seleccionadas en un select (jQuery)
    Code
    jquery(":select")


    Pseudo clase submit: selecciona todos los elementos submit (jQuery)
    Code
    jquery(":submit")


    Pseudo clase texto: selecciona todos las cajas de texto (jQuery)
    Code
    jquery(":text")


    Pseudo clase marcado: selecciona todos los radiobuttons y checkboxes marcados (CSS 3)
    Code
    jquery(":checked")


    Pseudo clase activo: selecciona todos los elementos que estén activos (CSS 3)
    Code
    jquery("input:enabled")


    Pseudo clase inactivo: selecciona todos los elementos que no estén activos (CSS 3)
    Code
    jquery("input:disabled")


    Pseudo clase ocultos: selecciona todos los elementos ocultos (jQuery)
    Code
    jquery(":hidden")


    Pseudo clase visible: selecciona todos los elementos visibles (jQuery)
    Code
    jquery(":visible")


    Selectores de jerarquía
    Selector de descendientes: selecciona elementos que desciendan de otro elemento (CSS 1)
    Code
    jquery("div.entrada h2")


    Selector de hijos: selecciona elementos que sean hijos directos de otro elemento (CSS 2)
    Code
    jquery("div.entrada > h2")


    Pseudo clase hijo: selecciona el enésimo hijo de un elemento (CSS 3)
    Code
    jquery("tr:nth-child(1)")


    Pseudo clase primer hijo: selecciona el primero hijo de un elemento (CSS 2)
    Code
    jquery("tr:first-child")


    Pseudo clase último hijo: selecciona el último hijo de un elemento (CSS 3)
    Code
    jquery("tr:last-child")


    Pseudo clase hijo único: selecciona los elementos que sean hijos únicos de otros elementos (CSS 3)
    Code
    jquery("div:only-child")


    Pseudo clase índice: selecciona el elemento con el índice indicado de un grupo de elementos (jQuery)
    Code
    jquery("td:eq(0)")


    Pseudo clase primero: selecciona el primer elemento de un grupo de elementos. Equivale a eq(0) (jQuery)
    Code
    jquery("td:first)")


    Pseudo clase último: selecciona el último elemento de un grupo de elementos (jQuery)
    Code
    jquery("td:last)")


    Pseudo clase mayor que: selecciona todos los elementos con un índice mayor que el indicado en un grupo de elementos (jQuery)
    Code
    jquery("td:gt(0)")


    Pseudo clase menor que: selecciona todos los elementos con un índice menor que el indicado en un grupo de elementos (jQuery)
    Code
    jquery("td:lt(3)")


    Pseudo clase par: selecciona los elementos pares de un grupo de elementos (jQuery)
    Code
    jquery("td:even")


    Pseudo clase impar: selecciona los elementos impares de un grupo de elementos (jQuery)
    Code
    jquery("td:odd")


    Selector de hermanos: selecciona todos los hermanos que se encuentren precedidos de otro elemento (CSS 3)
    Code
    jquery("div.entrada ~ p")


    Selector de próximo adyacente: similar al anterior, pero sólo selecciona el adyacente directo (CSS 2)
    Code
    jquery("div.entrada + p")


    Pseudo clase padre: selecciona los padres de otros elementos (jQuery)
    Code
    jquery("h2:parent")


    Pseudo clase vacío: selecciona los elementos que no tengan ningún hijo, incluyendo texto plano (CSS 3)
    Code
    jquery(":empty")



    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 127 | 3:45 PM

    Otros selectores
    Pseudo clase animado: selecciona todos los elementos que están en proceso de animación en este momento (jQuery)
    Code
    jquery(":animated")


    Pseudo clase contiene: selecciona todos los elementos que contengan el texto indicado, directamente o en uno de los hijos (jQuery)
    Code
    jquery("div:contains('InfraBios')")


    Pseudo clase tiene: selecciona todos los elementos que contengan al menos un elemento que responda al selector indicado (jQuery)
    Code
    jquery("div:has(h2)")


    Pseudo clase negación: selecciona todos los elementos que no cumplan con el selector dado (CSS 3)
    Code
    jquery("div:not(.entrada)")


    Gestionando una colección jQuery
    Al llamar a la función jQuery con un selector como argumento, el valor devuelto será otro objeto jQuery representando la colección de elementos DOM seleccionados. Tanto es así, que podremos obtener uno de los elementos utilizando el operador [], como si de un array normal se tratara
    Code
    jQuery("div.entrada")[0]


    y también tenemos acceso a una propiedad length con el número de elementos que contiene la colección
    Code
    jQuery("div.entrada").length


    Otras cosas que podemos hacer con este objeto son añadir elementos a la colección
    Code
    jQuery("div.entrada").add("div.comentario")


    eliminar elementos
    Code
    jQuery("div.entrada").not("div.destacada")


    filtrar elementos con un selector o basándonos en el valor devuelto por una función
    Code
    jQuery("div.entrada").filter(":has(h2)")


    quedarnos con los elementos que contengan otro cierto elemento
    Code
    jQuery("div.entrada").has("h2")


    obtener un sólo elemento, por su índice
    Code
    jQuery("div.entrada").eq(3)


    obtener el primer elemento de la colección
    Code
    jQuery("div.entrada").first()


    obtener el último elemento de la colección
    Code
    jQuery("div.entrada").last()


    crear una sub colección a partir de la original
    Code
    jQuery("div.entrada").slice(0,5);
    jQuery("div.entrada").slice(3);


    obtener los descendientes directos
    Code
    jQuery("div.entrada").children()
    jQuery("div.entrada").children("p")


    obtener los descendientes directos, incluyendo el texto plano
    Code
    jQuery("div.entrada").contents()


    obtener los hijos que cumplan con un determinado selector
    Code
    jQuery("div.entrada").find("p")


    obtener el hermano siguiente
    Code
    jQuery("div.entrada").next()


    obtener los hermanos siguientes
    Code
    jQuery("div.entrada").nextAll()


    obtener el hermano anterior
    Code
    jQuery("div.entrada").prev()


    obtener los hermanos anteriores
    Code
    jQuery("div.entrada").prevAll()


    obtener todos los hermanos
    Code
    jQuery("div.entrada").siblings()


    obtener el padre de cada elemento
    Code
    jQuery("div.entrada").parent()


    obtener todos los ancestros de cada elemento
    Code
    jQuery("div.entrada").parents()


    crear una copia de la colección
    Code
    jQuery("div.entrada").clone()


    o buscar la posición que ocupa un elemento en la colección (si existe)
    Code
    jQuery("*").index("div.entrada")


    Modificar la página con jQuery
    Veamos ahora cómo utilizar jQuery para modificar nuestra página web. Podemos, por ejemplo, modificar el valor de un atributo
    Code
    jQuery("a#principal").attr("href", "http://uсoz.es/")


    añadir una nueva clase a uno o varios elementos
    Code
    jQuery("div.entrada:first").addClass("primera")


    añadir una propiedad CSS a uno o varios elementos
    Code
    jQuery("div.entrada").css("border", "1px solid red")


    añadir contenido a un elemento
    Code
    jQuery("div.entrada:first").before("<strong>Destacada</strong>")
    jQuery("div.entrada:first").prepend("<strong>Destacada</strong>")
    jQuery("div.entrada:first").after("<strong>Destacada</strong>")
    jQuery("div.entrada:first").append("<strong>Destacada</strong>")


    modificar el contenido de un elemento
    Code
    jQuery("p").html("<strong>Sustituido</strong>")


    eliminar un elemento de la página
    Code
    jQuery("div.entrada:first").remove()


    ocultar un elemento
    Code
    jQuery("p").hide()


    o volver a mostrar un elemento
    Code
    jQuery("p").show()


    Eventos en jQuery
    Existen distintas funciones para asignar una función que maneje un evento lanzado por un widget. Para el evento click, al hacer clic sobre un elemento:
    Code
    jQuery(":button#pulsame").click(function () {
       alert("Has hecho clic");
    });


    evento submit, cuando se pulsa sobre el botón de enviar de un formulario:
    Code
    jQuery("#formulario").submit(function() {
       alert("Enviando");
    });


    evento dblclick, al hacer doble clic sobre un elemento:
    Code
    jQuery("p:first").dblclick(function () {
       alert("Has hecho doble clic");
    });


    evento hover, cuando al pasar el ratón por encima de un elemento. Podemos utilizar jQuery(this) para referirnos a este elemento:
    Code
    jQuery("p:first").hover(function () {
       jQuery(this).css("border", "1px solid red");
    });


    evento mouseenter, cuando el cursor entra en un elemento
    Code
    jQuery("p:first").mouseenter(function () {
       jQuery(this).css("border", "1px solid red");
    });


    evento mouseout, cuando el cursor sale de un elemento
    Code
    jQuery("p:first").mouseenter(function () {
       jQuery(this).css("border", "1px solid red");
    });
       
    jQuery("p:first").mouseout(function () {
       jQuery(this).css("border", "0");
    });


    evento change, cuando se modifica un elemento:
    Code
    jQuery(":text#nombre").change(function () {
       alert("Cambiado");
    });


    evento load, cuando se termina de cargar el elemento:
    Code
    jQuery(window).load(function () {
       alert("Página cargada");
    });


    evento ready, cuando se termina de cargar el DOM, para no tener que esperar a cargar las imágenes, por ejemplo, de forma que el usuario pueda utilizar nuestra funcionalidad JavaScript cuanto antes:
    Code
    jQuery(document).ready(function () {
       alert("DOM cargado");
    });


    esto último, al ser esto algo muy común, se puede resumir pasando una función a la función jQuery, directamente:
    Code
    jQuery(function () {
       alert("DOM cargado");
    });


    Animaciones con jQuery
    jQuery viene con unas pocas animaciones útiles y vistosas por defecto, aunque para sacarle todo el partido probablemente tendremos que recurrir a plugins.

    Para hacer un fundido a opaco:
    Code
    jQuery(function () {
       jQuery("p").hide();
       jQuery("p").delay(200).fadeIn();
    });


    En el ejemplo anterior se utiliza delay para hacer pasar un par de segundos y que se vea más claramente el efecto. A esta función se le puede pasar un valor numérico con el número de milisegundos a esperar, o una cadena, como slow (lento) o fast (rápido).

    para hacer un fundido a transparente:
    Code
    jQuery(":button").click(function () {
       jQuery("p").fadeOut();
    });


    También podemos cambiar la opacidad de un elemento a cualquier valor intermedio
    Code
    jQuery(":button").click(function () {
       jQuery("p").fadeTo("slow", 0.5);
    });


    mostrar los elementos con una animación de deslizamiento de arriba a abajo:
    Code
    jQuery(function () {
       jQuery("p").hide().delay(200).slideDown();
    });


    ocultarlos deslizándolos hacia arriba:
    Code
    jQuery(function () {
       jQuery("p").delay(200).slideUp();
    });


    mostrarlos u ocultarlos, dependiendo de si se estaban mostrando o no:
    Code
    jQuery(":button").click(function () {
       jQuery("p").delay(200).slideToggle();
    });


    Por último, para cualquier otro tipo de animación con propiedades CSS cuyos valores sean numéricos, utilizaríamos:
    Code
    jQuery(":button").click(function () {
       jQuery("p").animate({opacity:0.50,width:100}, 'slow');
    });


    jQuery y AJAX
    La forma más sencilla de enviar una petición HTTP de forma asíncrona y mostrar el resultado en la página actual es utilizar la función load. Esta se ejecuta sobre el elemento al que se va a añadir la respuesta, y se le pasa como argumento una cadena con el archivo a cargar. Esta cadena puede contener también un selector con el que seleccionar qué elementos queremos mostrar de la respuesta.

    Code
    jQuery(":button").click(function () {
       $("#citas").load("citas.html li");
    });


    también se pueden enviar parámetros al documento (se utiliza GET a menos que los datos se manden en forma de objeto):

    Code
    jQuery(":button#login").click(function () {
       $("#mensaje").load("login.php", {nombre: "zootropo", pass: "contraseña"});
    });


    e indicar una función a ejecutar cuando se termine de llevar a cabo la petición
    Code
    jQuery(":button#login").click(function () {
       jQuery("#mensaje").load("login.php", {nombre: "zootropo", pass: "contraseña"}, function(responseText, textStatus, XMLHttpRequest) {
         alert("cargado");
         });
    });


    También se pueden utilizar los métodos get y post del objeto jQuery, en cuyo caso se nos devolverá unos ciertos datos con los que nosotros mismos tendremos que trabajar para generar la respuesta y mostrarla en nuestro documento actual:
    Code
    jQuery.get("login.php", {nombre: "zootropo", pass:"contraseña"},
       function(data, textStatus, XMLHttpRequest){
         jQuery("#mensaje").html("Han devuelto: " + data);
       });
       
    jQuery.post("login.php", {nombre: "zootropo", pass:"contraseña"},
       function(data, textStatus, XMLHttpRequest){
         jQuery("#mensaje").html("Han devuelto: " + data);
       });


    Si la respuesta del servidor va a estar en formato JSON (JavaScript Object Notation), muy utilizado actualmente, podemos utilizar el método jQuery.getJSON(), al que se le pasa la URL de la petición y, opcionalmente, cualquier parámetro que se necesite, además de una función de callback que ejecutar cuando se termine con la petición. Este método se encargará de parsear la estructura del objeto JSON devuelta utilizando jQuery.parseJSON(), objeto que estará disponible como primer parámetro de la función de callback.

    Code
    $.getJSON('tareas.php', function(data, textStatus){
               $.each(data, function(i, tarea){
                 $("<li></li>").html(tarea.nombre + " - " + tarea.hora).appendTo("ul#tareas");
               });
             });


    El código de este tareas.php podría tener este aspecto:
    Code
    <?php
    header('Content-type: text/javascript');
       
    $bbdd = new mysqli('servidor.com', 'usuario', 'pass', 'tareas');
       
    $query = 'SELECT * FROM tareas';
    $tareas = array();
    if($resultado = $bbdd->query($query))
       while($tarea = $resultado->fetch_object())
         $tareas[] = $tarea;
       
    $bbdd->close();
       
    echo json_encode($tareas);
    ?>


    Como veis, se utiliza la función json_encode para convertir el array u objeto PHP a formato JSON. Esta función, junto con su complemento, json_encode, se introdujo en PHP en la versión 5.2.0.

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 128 | 6:20 PM
    Porqué no debemos usar nunca jQuery Live


    Eventos en jQuery
    Uno de los aspectos más interesantes durante el uso de una biblioteca como jQuery o Mootools es su capacidad para manejar eventos de un modo transparente y válido en un entorno multinavegador. Por lo general, una asociación simple tendría el siguiente aspecto:
    Code
    $('#myDomElement').click( function(){
       alert( 'Click!' );
    });


    Gracias al uso de un callback, podemos asociar una determinada acción/comportamiento a un evento determinado; en este caso, un click sobre un elemento del DOM.

    Este tipo de estructuras la solemos aprendemos el primer día jugando con que nos acercamos a este tipo de bibliotecas. Sin embargo, tienen un defecto: solo funcionan sobre aquellos elementos que están presentes en el DOM tras la invocación del método document ready. Esto quiere decir que, una vez iniciado el script, si añadimos de forma dinámica un nuevo elemento, éste no responderá a los eventos que hayamos definidos anteriormente. Un caso típico sería el siguiente:
    Code
    $(document).ready( function(){
       $('.myListElement').click( function(){
         alert(' Click! ');
       });
       
       $('.addNewListElement').click( function(){
         $('<li class="myListElement" />').appendTo('#myList');
       });
    } );


    Tenemos el mismo evento anterior asociado a un li en nuestra página. Además, hemos incluido un botón que añade nuevos elementos li cuando se pulsa. Si hacemos click sobre algún elemento de la lista, obtenemos el alert indicado en el primer callback pero, si añadimos dinámicamente uno nuevo y pulsamos sobre él, no obtendremos respuesta alguna: no se han delegado los eventos desde el original a las nuevas copias.

    Casi igual de rápido que aprendemos a asociar eventos, descubrimos que existe una forma rápida de delegación: el método live().

    Delegando eventos con live
    El ejemplo anterior funcionaría como se espera si cambiamos el método click por el socorrido live:
    Code
    $(document).ready( function(){
       $('.myListElement').live( 'click', function(){
         alert(' Click! ');
       });
       
       $('.addNewListElement').click( function(){
         $('<li class="myListElement" />').appendTo('#myList');
       });
    } );


    Ahora todo parece ir bien: si añadimos nuevos elementos pulsando nuestro botón, éstos heredan los eventos que hayamos definido anteriormente. Si pulsamos sobre cualquiera de ellos, obtenemos nuestro alert.

    Esta solución es la que aparece siempre en los foros y tutoriales en Internet por lo que, una vez comprobado que funciona, no solemos profundizar más en cómo lo hace y qué implica. Rara vez continuamos leyendo hasta llegar a otro método mucho menos conocido pero con una funcionalidad similar: delegate

    Delegando eventos con delegate
    Pese a que también está diseñado para delegar eventos, la sintaxis de delegate es ligeramente diferente a la de live. El ejemplo anterior se escribiría como sigue:
    Code
    $(document).ready( function(){
       $('#myList').delegate( '.myListElement', 'click', function(){
         alert(' Click! ');
       });
       
       $('.addNewListElement').click( function(){
         $('<li class="myListElement" />').appendTo('#myList');
       });
    } );


    Como podemos ver, recibe tres parámetros: el elemento dentro del grupo (padre) seleccionado, el evento a asociar y su correspondiente callback.

    De nuevo, funciona como se espera: pulsamos sobre algún elemento añadido en tiempo de ejecución y responde correctamente. Sin embargo, hay una importante diferencia por debajo.

    Diferencia entre live y delegate
    La diferencia crítica entre ambos métodos es que, mientras que live asocia el evento al nivel más alto del DOM (el document), delegate se limita únicamente a aquellos que son llamados explícitamente en su selector.

    Esto quiere decir que en el ejemplo con delegate, cuando un usuario hace click sobre un elemento li, este evento sube hasta el padre (que es realmente el objeto jQuery seleccionado) y dispara el manejador click. Entonces, se comprueba si efectivamente cumple con el criterio del selector (“.myListElement”) y, en caso de coincidir, ejecuta el correspondiente callback.

    En el ejemplo con live, jQuery asocia el manejador al elemento más alto dentro de la estructura DOM, el document. Cualquier click en la página subirá hasta ahí y disparará el manejador que hemos definido. Se comprobará entonces si alguno de los elementos por encima del seleccionado (o el mismo) coinciden con el criterio definido (‘.myListElement’). Asumiendo que el usuario ha hecho click sobre un li o cualquier otra cosa en su interior, algún punto de la cadena desde ahí hacia el document coincidirá con la selección y ejecutará el callback.

    A priori, podemos comprobar como el esfuerzo que realiza jQuery para monitorizar los eventos es mucho mayor con live que con delegate. Sin embargo, al margen del rendimiento, existen otras consideraciones a tener en cuenta.

    No debes usar live para widgets que pueden aparecer más de una vez en una página
    Aquí tenemos un ejemplo muy común. Pensemos en un widget compuesto por una capa con pestañas. Queremos que, cuando se pulse en una de esas pestañas, ocurra una acción. Como live asocia el evento al document, si incluimos dos de estos widgets en la misma página, cada vez que pinchemos en una pestaña el manejador de ambas será invocado. Esto quiere decir que si pincho sobre una pestaña en el primer widget, se invocará también el manejador del segundo. Lo ideal es sólo escuchemos el evento del elemento sobre el que hemos pinchado, no todos los coincidentes!.
    Code
    <div class="tab1 tabwidget">
         <div class="tab"> ... </tab>
         <div class="tab> ... </tab>
       </div>
       <div class="tab2 tabwidget">
         <div class="tab"> ... </tab>
         <div class="tab> ... </tab>
       </div>


    Live puede decirse que crea manejadores globales mientras que delegate solo actúa a nivel local. En este caso, los eventos se asociarían por separado al .tab1 y al .tab2, por lo que obtendríamos una granularidad que live no permite.

    stopPropagate() no funciona con live
    Si aconsejamos utilizar stopPropagate para evitar el mal uso del return false, con el método live no funciona: ya que live asocia el elemento al nivel más alto de la página, el stopPropagate no hace absolutamente nada (no quedan elementos por encima a los que propagarse).

    Por el contrario, llamado al stopPropagate en un evento manejado con delegate, al permanecer encerrado dentro de su selector, funciona como se espera y evita que el evento se propage a los padres.

    live() es más lento
    Esto no debería sorprender: al tener que remontar constantemente la cadena de nodos hasta llegar al document, el uso de live es significativamente más lento que el de delegate. En aplicaciones con muchos niveles de profundidad, esta penalización puede llegar a ser importante.

    live() no permite encadenar acciones
    Aunque no solemos aprovechar al máximo (sobre todo por desconocimiento) la capacidad de jQuery para encadenar acciones, ésta permite reducir significativamente los códigos a la vez que mejora el rendimiento general. Por ejemplo, el siguiente código:
    Code
    $('.myElement').click( function(){
       $this = $(this);
       $this.width('300');
       $this.height('300');
       $this.addClass('selected');
    })


    es similar a
    Code
    $('.myElement').click( function(){
       $(this)
         .width('300');
         .height('300');
         .addClass('selected');
    })


    Encadenar acciones, además de resultar más limpio, permite aprovechar mejor la memoria del sistema: para cada acción, no tenemos que volver a seleccionar los elementos. Por otro lado, aunque tengamos la buena costumbre de cachearlo, con el encadenamiento encontramos que no es realmente necesario ni realizar esta asignación ( $this = $(this); ).

    Pero con live no podemos confiar en esta funcionalidad: ya que el elemento se asocia al document, el contexto cambia y la cadena puede no funcionar como se espera.

    Conclusiones
    Tras revisar todos los puntos anteriores, podemos concluir que las mejores prácticas recomiendan no utilizar live en ningún caso. Tras la introducción de live, rápidamente se comprobó que era necesario una mejora sustancial en la API para la delegación de eventos. Ésta fue la razón que motivó la creación de delegate. Actualmente, jQuery continúa soportando el método live únicamente por motivos de retro compatibilidad con las versiones anteriores. La recomendación oficial al respecto es utilizar siempre delegate para la asociación y delegación de eventos.

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 129 | 7:22 PM
    Los nuevos métodos jQuery on() y off()


    Introducción
    Con la llegada de jQuery 1.7, se han solucionado varios bugs que esta biblioteca arrastraba de versiones anteriores; también se ha mejorado una vez más el rendimiento general de la misma prestándose especial atención a selectores y a la portabilidad a los dispositivos móviles.

    Pero además de estos ‘arreglos’, tenemos nuevos métodos y nuevas funcionalidades interesantes. De entre los primeros, sin duda los más interesantes son los que se refieren a la nueva gestión de eventos: el corazón de jQuery.

    Los eventos en jQuery
    Desde su aparición, jQuery se ha caracterizado por la flexibilidad con la que el desarrollador puede efectuar selecciones de elementos dentro del DOM y por la facilidad para asociar eventos a cada uno de esos conjuntos seleccionados.

    Sin embargo, un problema con el que han tenido que lidiar los chicos del jQuery Team es que, con el paso de las versiones, estos manejadores (handlers) se han multiplicado hasta resultar confusos en las últimas releases.

    Al principio, solo disponíamos del viejo método bind con el que asignábamos un determinado evento a un objeto jQuery:
    Code
    $('mySelector').bind('click', function(){
       // The callback goes here...
    })


    Para aquellos eventos muy frecuentes, como en el caso del click anterior, contábamos incluso con prácticos atajos (shortcuts):
    Code
    $('mySelector').click( function(){
       // The callback goes here...
    });


    El problema de bind es que solo funciona con aquellos elementos del DOM que ya están presentes cuando la función se ejecuta. Es decir, aquellos otros elementos que pudieran añadirse de forma dinámica, no heredan este comportamiento.

    Para solventar este problema, apareció en escena el método live(). Sin embargo, live presentaba más problemas que ventajas y rápidamente se consideró obsoleto (deprecated). El problema con este método proviene de su bajo rendimiento en estructuras complejas y de algunos comportamientos impredecibles que se dan en determinados escenarios. Para un completo artículo sobre el porqué no debemos usar jQuery live, podemos leer el post anterior.

    Buscando una vía alternativa al uso de live, jQuery ofreció un nuevo método muy similar: delegate(). Hasta el momento, delegate ha tratado de cubrir la funcionalidad de asociar eventos a elementos DOM pero, de nuevo, el resultado no ha sido todo lo satisfactorio que cabría esperar.

    Es por todo esto que, frente a la confusión por parte del desarrollador de encontrarse tantos métodos similares (bind, live, delegate, one, …), el jQuery Team ha decidido crear dos nuevos métodos que aúnen el comportamiento de todos ellos buscando el máximo rendimiento y minimizando la confusión: on() y off().

    El método on()
    El objetivo de on() es reemplazar a los antiguos bind, live y delegate. Su sintaxis es la siguiente:
    Code
    $(elements).on(events [, selector] [, data], handler);


    Donde:
  • events son los eventos que se buscan asociar al conjunto de elementos seleccionados. La novedad aquí es que pueden asociarse más de un evento separándolos con espacios. Por ejemplo: click, click blur.
  • selector especifica los descendientes de los elementos seleccionados que dispararán el evento. Se trata de un parámetro opcional.
  • data indica cualquier tipo de datos que se necesite pasar al manejador cuando se dispara el evento. Es también un parámetro opcional y, por lo general, se corresponde con un objeto jQuery.
  • handler se corresponde con el callback o acción a realizar después de que el evento se dispare.

    Un ejemplo de uso completo puede ser el siguiente:
    Code
    $('#myContainer .item').on({
       click: function() {
         event.preventDefault();
         console.log('item clicked');
       },
       mouseenter: function() {
         console.log('enter!');
       }
    });


    El resultado del código anterior es que hemos asociado dos eventos diferentes, con dos callbacks diferentes a aquellos elementos DOM que cumplan con el criterio de la selección (en este caso aquellos con la clase item descendientes de un ID myContainer). Como hemos comentando más arriba, al reemplazar a live() y delegate(), este comportamiento será heredado por cualquier otro elemento que se inserte en el DOM de forma dinámica aún después de haber sido ejecutada la función anterior.

    Actualizaciones desde métodos antiguos
    Actualizar nuestros viejos códigos a la nueva versión resulta por lo general sencillo:
    Code
    // Old live() style:
    $('#myContainer .item').live('click', function(event) {
       event.preventDefault();
       console.log('item clicked');
    });
       
    // New on() style:
    $('#myContainer').on('click', '.item', function(event) {
       event.preventDefault();
       console.log('item clicked');
    });


    En el ejemplo anterior hemos visto además, como se asocian selectores dentro del propio cuerpo de la función para especificar aquellos descendientes que dispararán el evento.
    Code
    // Old delegate() style:
    $('#myContainer').delegate('.item', 'click', function(event) {
       event.preventDefault();
       console.log('item clicked');
    });
       
    // New on() style:
    $('#myContainer').on('click', '.item', function(event) {
       event.preventDefault();
       console.log('item clicked');
    });


    En el caso de la actualización desde delegate, solo necesitamos cambiar el orden de los parámetros.

    El método off()
    Al igual que con la asocación de eventos, la confusión de métodos también llegaba con la acción contraria: eliminarlos.

    Para esta acción, contábamos con varios métodos como unbind(), die() o undelegate(). De nuevo, el objetivo principal de la nueva instrucción es reemplazarlos a todos de un modo consistente.

    La sintaxis de off() resulta similar a la de on():
    Code
    $(elements).off( [ events ] [, selector] [, handler] );


    Con off(), todos los parámetros son opcionales. Cuando se utiliza en su forma más simple, $(elements).off(), se eliminan todos los eventos asociados al conjunto seleccionado.

    Actualizaciones desde métodos antiguos
    Como en el caso anterior, dependiendo de qué método vengamos, la conversión presenta más o menos cambios.

    Para el caso de unbind(), solo necesitamos cambiar el nombre del método:
    Code
    // Old unbid() style:
    $('#container a').unbind('click');
       
    // New off() style:
    $('#container a').off('click');


    Para aquellos códigos que hagan uso del live() / die(), el cambio es similar:
    Code
    // Old die() style:
    $('#container a').die('click');
       
    // New off() style:
    $('#container').off('click', 'a');


    De nuevo, solo es necesario organizar ligeramente el orden de los parámetros para aprovechar la nueva potencia del método off().

    Para la portabilidad desde undelegate(), solo tenemos que cambiar el orden de los parámetros:
    Code
    // Old undelegate() style:
    $('#container a').undelegate('a', 'click');
       
    // New off() style:
    $('#container a').off('click', 'a');


    Conclusión
    Con la nueva versión 1.7 de jQuery, se trata por fin de poner algo de orden en cuanto al manejo de eventos que ofrece esta biblioteca, aunando en unos mismos métodos toda la funcionalidad que hasta la fecha se había ido desplegando en varios.

    Con esto, el resultado es un API más robusto y sólido, exactamente lo que los desarrolladores jQuery han solicitado al equipo de desarrollo.

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
  • GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 130 | 6:19 PM
    Craftyslide: Una galería sencilla para jQuery


    Craftyslide es un pequeño plugin para jQuery que nos permite crear galerías de imágenes con mucha sencillez ya que basta agregarlas en una lista y llamar a la función, sin importar su tamaño original.

    Para utilizarlo, basta descargar el ZIP que contiene el ejemplo básico, tener jQuery en nuestra plantilla y agregar el plugin y el CSS antes de </head> ya sea copiando y pegando directamente el código o utilizando archivos externos:
    Code
    <script src='http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

    <link rel='stylesheet' href='URL_craftyslide.css' />

    <script src='URL_craftyslide.min'></script>


    El CSS sólo requiere que cambiemos una línea que es la que contiene la imagen que se utiliza para paginar la galería, subiendo esa imagen a cualquier servidor y colocando la nueva URL en esta regla de estilo:
    Code
    #pagination li a {
       .......
       background: transparent url(URL_pagination.png) repeat 0 0;
    }


    Obviamente, cualquier otra parte del CSS puede ser personalizada, y en este ejemplo, he hecho eso con la paginación de tal modo que pueda verse correctamente, sin importar la cantidad de imágenes que tenga la galería.
    Code
    #slideshow { /* es el DIV que contiene la galería */
       border: 15px solid #FFF;
       box-shadow: 0 3px 5px #999;
       margin: 0;
       padding: 0;
       position: relative;
    }
    #slideshow ul { /* la lista que contendrá las imágenes */
       margin: 0;
       overflow: hidden;
       padding: 0;
       position: relative;
    }
    #slideshow ul li { /* cada item de la lista */
       left:0;
       list-style-type:none;
       margin: 0;
       padding: 0;
       position: absolute;
       top: 0;
    }
    #pagination { /* la paginación inferior optativa */
       clear: both;
       margin: 25px auto 0;
       padding: 0;
       text-align: center;
    }
    #pagination li { /* cada item de la paginación */
       display: inline;
       list-style-type: none;
       margin: 0 2px;
    }
    #pagination li a { /* cada imagen de la paginación es un enlace */
       background: transparent url(URL_pagination.png) repeat 0 0;
       display: inline-block;
       height: 10px;
       text-indent: -10000px;
       width: 10px;
    }
    #pagination li a.active { /* la imagen cambia cuando se activa */
       background-position:0 10px;
    }
    .caption { /* el texto optativo que se coloca en el atributo title */
       background: rgba(0,0,0,0.6);
       border-top: 1px solid #000;
       color: #FFF;
       font-family: Helvetica, Arial, sans-serif;
       font-size: 14px;
       font-weight: lighter;
       left: 0;
       margin: 0;
       padding: 10px;
       position: absolute;
       width: 100%;
       z-index: 1;
    }


    Lo utilizamos colocando la lista allí donde se nos ocurra mostrar la galería:
    Code
    <div id="slideshow">
       <ul>
         <li><img src="URL_IMAGEN_1" title="text imagen 1" /></li>
         <li><img src="URL_IMAGEN_1" title="text imagen 1" /></li>
         <!-- y seguimos agregando tantas etiquetas LI como querra,os -->
       </ul>
    </div>


    Y al final, llamamos a la función de este modo:
    Code
    <script> $("#slideshow").craftyslide(); </script>


    o establecemos parámetros:
    Code
    <script>
      $("#slideshow").craftyslide({
         'width': 550,
         'height': 350,
         'pagination': true,
         'fadetime': 500,
         'delay': 2500
       });
    </script>


    donde:
  • width y height serán el tamaño total (por defecto 640x400)
  • pagination puede ser false en cuyo caso, funcionará como un slideshow
  • fadetime es el tiempo de demora entre dos imágenes
  • delay es el tiempo del slideshow si elegimos esa opción

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
  • GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 131 | 7:42 PM
    El nuevo objeto jQuery $.Callbacks()


    Introducción
    En el post anterior revisamos los nuevos métodos on() y off() de la versión 1.7 de jQuery, sin duda, una de las innovaciones más interesantes.
    Siguiendo con el estudio de esta versión, nos toca ahora echarle un vistazo a otra importante novedad: el objeto $.Callbacks().

    Básicamente, $.Callbacks ofrece un completo stack (conjunto de elementos) donde definir una serie de funciones que serán ejecutadas en secuencia como resultado de una determinada condición o acción previa.

    Como la explicación puede resultar confusa, comencemos con un ejemplo para ir luego avanzando con cada uno de los métodos que ofrece este nuevo elemento:

    Ejemplo de $.Callbacks
    Tenemos dos funciones como las siguientes:
    Code
    var fn1 = function( myStr ){
       console.log( 'Fn1 says: ', myStr );
    }
       
    var fn2 = function( myStr ){
       console.log( 'Fn2 says ', myStr );
    }


    Bien; nada complejo: dos funciones simples que reciben un argumento para pintarlo en la consola. Ahora, asociemos ambas funciones al nuevo objeto $.Callbacks para crear una pila o cola de ejecución con ellas:
    Code
    var stack = $.Callbacks();
    stack.add( fn1 );
    stack.fire( 'Hello World' ); // Fn1 says: Hello World
       
    stack.add( fn2 );
    stack.fire( 'Goodbye Lenin' ); // Fn1 says: Goodbye Obama, Fn2 says: Goodbye Obama


    Como podemos comprobar, hemos utilizado dos métodos que prácticamente hablan por si mismos: add() y fire(). El primero, se encarga de añadir una función al stack o pila mientras que el segundo, fire(), se encarga de ejecutar dicha pila a la vez que permite que enviemos argumentos a la misma.

    Junto a estos dos métodos, contamos con un tercero también básico: remove(), el cual permite, como su nombre indica, borrar una referencia determinada de nuestra lista. Su uso es igual de simple:
    Code
    var double = function( myVal ){
       if( $.isNumeric( myVal ) ){
         console.log( myVal * 2 );
       }else{
         console.log( myVal, ' is not Numeric!' );
         return false;
       }
    }
    var triple = function( myVal ){
       if( $.isNumeric( myVal ) ){
         console.log( myVal * 3 );
       }else{
         console.log( myVal, ' is not Numeric!' );
         return false;
       }
    }
       
    var stack = $.Callbacks();
    stack.add( double );
    stack.fire( 5 ); // 10
    stack.fire( 'foo' ); // foo is not Numeric!
       
    stack.add( triple );
    stack.fire( 10 ); // 20, 30
    stack.fire( 'bar' ); // bar is not Numeric!
       
    stack.remove( double );
    stack.fire( 2 ); // 6


    Lo primero es comentar el uso de otra de las nuevas funcionalidades de jQuery 1.7: la función isNumeric(). Con ella comprobamos si un determinado valor se corresponde con un valor numérico, independientemente de que se le pase como entero o cadena:
    Code
    console.log( $.isNumeric(5) ); // true
    console.log( $.isNumeric('10') ); // true
    console.log( $.isNumeric('one') ); // false
    console.log( $.isNumeric(NaN) ); // false


    NOTA: la última comprobación puede resultar confusa ya que para Javascript, NaN se corresponde con un valor númerico. jQuery, sin embargo, considera que NaN no se corresponde con un número.

    Volviendo al ejemplo anterior, vemos como remove() suprime una determinada función del stack. Pero si en lugar de una concreta, quisiéramos eliminar todas las funciones que hayamos incluido en nuestra pila, contamos con el método empty() para vaciarla de forma inmediata:
    Code
    stack.empty();
    console.log( stack.has( triple ) ); // false


    NOTA: El método has() lo revisaremos más adelante en este mismo post.

    Separando pilas
    Dado que, como hemos visto en los ejemplos anteriores, las pilas se asocian a variables, podemos tener varios entornos de forma simultánea.
    Code
    var calcDouble = $.Callbacks();
    var calcTriple = $.Callbacks();
       
    calcDouble.add( double );
    calcTriple.add( triple );
       
    calcDouble.fire( 10 ); // 20
    calcTriple.fire( 20 ); // 60


    Con esto, podemos tener varias colas o listas de ejecución independientes.

    Otros métodos
    Además de add, fire y remove, $.Callbacks soporta otros métodos que pueden resultar muy interesantes:

  • fireWith(): con este método, se puede especificar el contexto y los argumentos que se pasamos a la pila:
    Code
    var sum = function(){
       var result = 0;
       for( var x=0, i=arguments.length; x < i; x++){
         result += arguments[x];
       }
       
       console.log( result );
    }
       
    var stack = $.Callbacks();
    stack.add( sum );
       
    stack.fireWith( window, [2, 5, 10, 3] ); // 20


    En el ejemplo anterior, hemos creado una función sum que devuelve la suma de todos aquellos valores que se le pasan como argumentos. Para ejecutarla desde nuestra pila, hemos utilizado el fireWith pasándole como contexto window y como argumentos un array con diversos valores.

    Tenemos que tener en cuenta aquí que lo que recibe la función sum no es el array, sino que cada uno de los valores que hemos indicado se correspondería con un argumento en nuestra función:
    Code
    var sum = function(/* arg1, arg2, arg3, ... */){
       //...
    }


  • has(): este método sirve para determinar si una función concreta forma parte de nuestra pila.
    Code
    var fn1 = function(){
       console.log( 'Hello World' );
    };
    var fn2 = function(){
       console.log( 'Goodbye Lenin' );
    };
       
    var stack = $.Callbacks();
    stack.add( fn1 );
       
    console.log( stack.has( fn1 ) ); // true
    console.log( stack.has( fn2 ) ); // false


  • fired(): este método determina si una determinada lista ha sido ejecutada al menos una vez:
    Code
    var foo = function( value ){
       console.log( 'foo:' + value );
    }
       
    var stack = $.Callbacks();
    stack.add( foo );
       
    stack.fire( 'hello' ); // foo: hello
    stack.fire( 'world '); // foo: world
       
    console.log( stack.fired() ); // true


  • disable(): este método inutiliza la lista e impide la ejecución de la misma en futuras llamadas:
    Code
    var foo = function( value ){
       console.log( value );
    }
       
    var stack = $.Callbacks();
    stack.add( foo );
       
    stack.fire( 'foo' ); // foo
       
    stack.disable();
       
    stack.fire( 'foobar' ); // foobar isn't output so nothing is printed


    lock() y locked(): el primer método bloquea la lista para impedir que pueda ser modificada de forma dinámica desde el interior de la misma. El segundo método comprueba si la lista ha sido bloqueada devolviendo un valor booleano.

    Indicadores
    El objeto $.Callbacks() soporta además indicadores o flags que determinan el comportamiento de la lista. Estos indicadores se especifican al iniciar el objeto y se corresponden con una serie de palabras reservadas separadas por comas. Los posibles valores son:

  • once: especifica que la lista solo se ejecutará una vez (igual que Deferred).
  • memory: al igual que en Deferred, los valores previos se memorizan por lo que a cada llamada de la lista, éstos se tienen en cuenta.
  • unique: asegura que las funciones que forman una lista, solo se pueden incluir una vez evitando duplicados.
  • stopOnFalse: interrumpe la pila de ejecución cuando alguna de las funciones devuelve un valor false.

    Algunos ejemplos:
    Code
    var fn1 = function( str ){
       console.log( 'Fn1 says: ' + str );
    };
       
    var fn2 = function( str ){
       console.log( 'Fn2 says: ' + str );
    };
       
    var callbacks = $.Callbacks( "memory" );
       
    callbacks.add( fn1 );
    callbacks.fire( "foo" );
       
    callbacks.add( fn2 );
    callbacks.fire( "bar" );
       
    // Fn1 says: foo
    // Fn2 says: foo
    // Fn1 says: bar
    // Fn2 says: bar

    En el caso anterior, aunque fn2 no estaba incluida en la lista antes de la primera ejecución (fire), al si estarlo más adelante en el código, funciona devolviendo el valor ‘memorizado’ en fn1.
    Code
    var fn1 = function(){
       console.log( 'Hello World' );
    }
       
    var stack = $.Callbacks( 'unique' );
    stack.add( fn1 );
    stack.fire(); // Hello World
       
    stack.add( fn1 ); // repeat addition
    stack.fire(); // Hello World --> only once


    Aunque hemos incluido un par de veces la función fn1, gracias al indicador unique ésta solo se ejecuta una vez.
    Code
    var fn1 = function(){
       console.log( 'Hello World' );
       return false;
    };
       
    var fn2 = function(){
       console.log( 'Goodbye Lenin' );
    };
       
    var stack = $.Callbacks( 'stopOnFalse' );
    stack.add( fn1, fn2 );
    stack.fire(); // Hello World


    En esta ocasión, aunque dentro de nuestra lista estarían definidas las funciones fn1 y fn2, al devolver la primera un false y habiendo especificado el indicador stopOnFalse, la ejecución se interrumpe inmediatamente.

    Para definir más de un indicador al mismo tiempo, solo tenemos que separarlos con espacios:
    Code
    var stack = $.Callbacks( 'unique stopOnFalse' );


    Conclusión
    Pues esto es todo; un nuevo objeto jQuery con el que contar en nuestro inventario para programar callbacks de forma precisa.

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
  • GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 132 | 7:15 PM
    Ordenación básica de datos en Javascript


    Introducción
    Cuando comenzamos a estudiar algoritmos, uno de los temas más recurrentes para ejemplificar la materia es la ordenación de datos. Básicamente se trata de, partiendo de una lista con elementos dispuestos al azar, encontrar la forma de procesarla para devolverla ordenada.

    Para esto, existen varios tipos de algoritmos diferentes que resuelven el problema a través de distintos acercamientos; estudiarlos es una buena forma de entender cómo se diseñan y cómo se mide el rendimiento de los mismos según cada uno de los escenarios posibles en los que pueden aplicarse.

    En este artículo, repasaremos tres métodos muy conocidos de ordenación diferentes: bubblesort, selectionsort e insertionsort.

    Cada uno de estos tres algoritmos se resuelven por iteración y, ya que son muy sencillos de codificar, se los considera como métodos simples. Pasemos sin más a estudiar cada uno de ellos para descubrir cuál(es) es el más interesante a la hora de implementarlo en un proyecto.

    Preparando el terreno
    Por lo general, todos los algoritmos de ordenación funcionan de una forma similar. Toman una lista de elementos, en nuestro caso un array, comparan sus elementos siguiendo una estrategia definida y, según el resultado de dicha comparación, mueven los datos de un lugar a otro hasta conseguir una lista (array) final ordenado.

    Teniendo en cuenta lo anterior, un punto clave de nuestros métodos será mover valores entre los índices del array que queremos ordenar. Es decir, necesitaremos una función para intercambiar los valores de un array entre dos posiciones dadas.

    Como no tenemos en Javascript una función similar, crearemos una. Por seguir la convención, llamaremos a nuestra función swap y aceptará tres parámetros: el array sobre el que actuamos y los índices de aquellos dos elememtos que queremos intercambiar. Su codificación es muy simple:
    Code
    /**
      * @function
      * @name swap
      * @description Swap two elements in an array
      * @param {array} myArr The target array.
      * @param {int} indexOne The index of the first element to swap.
      * @param {int} indexTwo The index of the second element to swap.
      * @returns {array} The array with the two elements swapped.
      */
    function swap(myArr, indexOne, indexTwo){
       var tmpVal = myArr[indexOne];
       myArr[indexOne] = myArr[indexTwo];
       myArr[indexTwo] = tmpVal;
       return myArr;
    }


    He comentado la función siguiendo la convención JSDoc para que resulte más clara. Como podemos ver, no realizo comprobación de tipos ni si existen los índices que se pretenden intercambiar. No es el objetivo de este artículo.

    Una rápida demostración de su funcionamiento sería:
    Code
    var myArr = ['a', 'b', 'c', 'd'];
    console.log( swap( myArr, 0, 1) ); // ["b", "a", "c", "d"]


    Nuestra función hace el trabajo que se le espera: ha tomado los índices 0 y 1 del array para devolver uno nuevo con esos valores intercambiados. Un poco más adelante, afinaremos esta función para que ofrezca un mejor rendimiento.

    Estamos listos para comenzar a implementar nuestros métodos de ordenación de datos!

    Bubble Sort (u ordenamiento por burbuja)
    Imaginemos que estamos en un parque con nuestra familia y queremos hacer una foto en la que salgan todos. Decidimos que podemos ordenarlos según sus edades de tal modo que tengamos al más joven a la izquierda y al más mayor a la derecha. Sin embargo, como no les hemos dicho nada, se han colocado de forma aleatoria:



    Para aplicar un ordenamiento de tipo burbuja a este conjunto de elementos, tenemos que prestar atención a las dos primeras personas de la izquierda. Le preguntamos a cada uno por su edad y, si la que está a la izquierda es mayor que la de su derecha, intercambiamos sus posiciones. En el caso contrario, no hacemos nada ya que se encontrarían ordenados de forma relativa entre ellos.

    En nuestro ejemplo, la persona de la izquierda es mayor que la de su derecha por lo que tenemos que realizar el primer intercambio:



    Ahora fijamos nuestra atención en la segunda y tercera posición para repetir el proceso anterior: preguntamos por sus edades e intercambiamos posición si fuera necesario. En nuestro ejemplo, no tenemos que realizar ahora ningún intercambio, por lo que avanzaríamos para comparar la tercera y cuarta posición entre ellas. De nuevo, están ya ordenados de forma relativa puesto que la persona de la derecha, es mayor que la de su izquierda.

    Avanzamos sin alterar nada hasta comparar la cuarta persona con la quinta. Ahora si nos volvemos a encontrar con que la persona de la izquierda es mayor que la derecha, por lo que es necesario un nuevo intercambio:



    Hemos completado una vuelta sobre nuestro conjunto y de momento estamos aún lejos de tenerlo ordenado. Sin embargo, si que hemos conseguido algo importante: el elemento de la derecha está ya ubicado en su posición final; es decir, que como si de una burbuja se tratase, el elemento más grande (en este caso la persona más mayor) ha ido bullendo hasta su posición final.

    El siguiente paso, sería volver a repetir el proceso ignorando la persona (el elemento) que está a la derecha del conjunto (puesto que ya está en su posición final).

    Comparamos ahora la dos primeras posiciones y observamos que están ya ordenadas, por lo que pasamos directamente a comparar la segunda con la tercera posición. De nuevo tenemos los elementos ordenados de forma relativa entre ellos por lo que pasaríamos evaluar la tercera y cuarta posición.

    Llegados a ese punto, observamos que la persona de la izquierda es mayor que la de su derecha, por lo que intercambiamos posiciones obteniendo:



    Hemos completado la segunda vuelta; comenzamos de nuevo e ignoramos ahora los dos últimos elementos. Finalmente, tras todas las iteraciones posibles, obtenemos:



    Una vez que hemos comprendido cómo funciona, es hora de implementarlo en código.

    La idea tras este algoritmo es que, a cada iteración por el conjunto, un elemento es llevado hasta su posición final y tiene que ser por lo tanto ignorado en las siguientes. Esto se traduce en que, a cada paso, se debe compara un elemento menos que en el anterior. Si N es el número de items en la lista, entonces en la primera iteración necesitamos comparar N – 1; en la segunda, N – 2, y así sucesivamente. Este tipo de códigos basado en bucles dependientes se resuelven muy fácilmente:
    Code
    function bubbleSort(myArr){
       var size = myArr.length;
       
       for( var pass = 1; pass < size; pass++ ){ // outer loop
         for( var left = 0; left < (size - pass); left++){ // inner loop
           var right = left + 1;
           if( myArr[left] > myArr[right] ){
             swap(myArr, left, right);
           }
         }
       }
       
       return myArr;
    }


    El código anterior, resulta muy sencillo de seguir. Un bucle externo recorre nuestro array tantas veces como elementos tenga menos uno. El bucle interno compara cada uno de los valores que encuentra (left) con aquel que inmediatamente posterior (right). Si left es mayor que right, se intercambia la posición y se continúa con el siguiente par.

    Comprobamos nuestro código anterior con un array simple:
    Code
    var myArr = ['d', 'f', 'd', 'c', 'a', 'e', 'b'];
    console.log( bubbleSort( myArr ) ); // ["a", "b", "c", "d", "d", "e", "f"]


    La función nos devuelve nuestro array ordenado aunque, como seguramente intuimos, es probable que estemos realizando un alto número de iteraciones para ello…
    Más adelante, mediremos el rendimiento de este algoritmo para compararlo con los dos restantes.

    Selection sort (u ordenamiento por selección)
    Imaginemos que tenemos una estantería llena de libros de diferente tamaño (altura). Como no hemos seguido ningún criterio a la hora de colocarlos, están dispuestos de forma aleatoria y nos gustaría cambiar esto. Querríamos tenerlos colocados según su tamaño de tal modo que en el extremo izquierdo tuviéramos al más alto y en el derecho al más bajo.



    Sin embargo, son libros pesados y no parece interesante estar desplazándolos uno a uno como en el caso anterior. Lo ideal sería revisar todos los libros, seleccionar el siguiente según el orden que hemos establecido y colocarlo directamente en su posición final. Esta selección que da nombre al algoritmo permite tomar un elemento y desplazarlo en un único movimiento a su posición definitiva.



    En varias ocasiones, mientras escaneamos los libros, encontraremos que éstos están ya en su posición final y que no es necesario moverlos. También notaremos que tras cada movimiento, el conjunto de libros ordenados crece mientras que el de los desordenados disminuye lo que muestra el patrón que permite concluir el proceso.



    La secuencia completa para ordenar el resto de los libros sería el siguiente:



    Como hemos comentado más arriba, en este tipo de ordenaciones, a diferencia de lo que ocurre con el método de burbuja, podemos encontrarnos continuamente con que un elemento ya está ordenado y no requiere de ese intercambio. Para ahorrar ese paso, modificaremos ligeramente la función swap:
    Code
    function swap(myArr, indexOne, indexTwo){
       if( indexOne == indexTwo ){
         return myArr;
       }
       var tmpVal = myArr[indexOne];
       myArr[indexOne] = myArr[indexTwo];
       myArr[indexTwo] = tmpVal;
       return myArr;
    }


    Ahora estamos comprobando que las posiciones a intercambiar no sean la misma y, por tanto, estemos realizando una operación inútil.

    La implementación del selection sort se construye a partir de un buble externo y otro interno, como en el anterior, pero con sutiles diferencias.

    En primer lugar, el exterior recorre los valores entre cero y N-2 en lugar de entre 1 y N-1. Aunque en realidad se trate finalmente del mismo número de pasos (N-1), operamos directamente sobre los slots para enviar ahí el valor correcto en cada una de las iteraciones. Por ejemplo, en el primer paso, nuestro objetivo es desplazar el elemento correcto hasta la posición cero; en el segundo, nuestro objetivo es rellenar la posición 1, y así sucesivamente.

    De nuevo, necesitamos un número de iteraciones N-1 puesto que tras cada ciclo, tendremos un elemento ubicado en su posición definitiva que podemos ignorar.

    El código sería el siguiente:
    Code
    function selectionSort( myArr ){
       var size = myArr.length;
       for( var slot = 0; slot < size -1; slot ++ ){ // outer loop
         var smallest = slot;
         for( var check = slot + 1; check < size; check++ ){ // inner loop
           if( myArr[check] < myArr[smallest] ){
             smallest = check;
           }
         }
         swap( myArr, smallest, slot );
       }
       return myArr;
    }


    Lo probamos:
    Code
    var myArr = ['d', 'f', 'd', 'c', 'a', 'e', 'b'];
    console.log( selectionSort( myArr ) ); // ["a", "b", "c", "d", "d", "e", "f"]


    Como ocurría con el método anterior, un simple vistazo a la lógica del código nos puede poner sobre la pista de que quizá, hacemos más comparaciones de las que podrían ser necesarias. Eso por no entrar en la complejidad ciclomática de tres niveles que presenta.

    Insertion Sort (u ordenación por inserción)
    Este algoritmo es muy similar al que utilizaríamos para ordenar las cartas en una mano de póquer a medida que nos las van sirviendo.


    La idea tras este concepto es la siguiente:
  • Separamos según los palos en el siguiente orden: picas, tréboles, diamantes y corazones.
  • Por cada uno de esos palos, ordenamos de forma ascendiente: As, 2, 3, …, 9, 10, jota, reina y rey.

    La siguiente sucesión de imágenes nos mostraría el proceso de ordenación según fuéramos descubriendo cartas:



    Inicialmente se tiene un solo elemento, que obviamente es un conjunto ordenado. Después, cuando hay K elementos ordenados de menor a mayor, se toma el elemento K + 1 y se compara con todos aquellos ya ordenados, deteniéndose cuando se encuentra uno menor (todos los elementos mayores han sido desplazados una posición a la derecha). En este punto se insertaría el elemento K + 1 desplazándose al resto.



    Avanzando en el ejemplo anterior, la siguiente carta se ordenaría siguiendo el mismo criterio:



    El resto de la secuencia sería:



    El código sería el siguiente:
    Code
    function insertionSort( myArr ) {
       var size = myArr.length,
           slot,
           tmp;
       
       for ( var item = 0; item < size; item++ ) { // outer loop      
         tmp = myArr[item];
         for ( slot = item - 1; slot >= 0 && myArr[slot] > tmp; slot-- ){ // inner loop
           myArr[ slot + 1 ] = myArr[slot];
         }
         myArr[ slot + 1 ] = tmp;
       }
       return myArr;
    };


    Y la comprobación de rigor:
    Code
    var myArr = ['d', 'f', 'd', 'c', 'a', 'e', 'b'];
    console.log( insertionSort( myArr ) ); // ["a", "b", "c", "d", "d", "e", "f"]


    Es cierto que este código es más difícil de seguir a simple vista y quizá no seamos capaces de advertir qué nivel de complejidad presenta. Pero no hay problema; ha llegado el momento de medir cada uno de los métodos anteriores y comparar los resultados.

    Comparando los algoritmos de ordenación básicos
    Una vez que hemos presentado algunos de estos algoritmos básicos, vamos a analizar su rendimiento de un modo práctico. Esta comparación no será definitiva en tanto a qué método escoger independientemente del escenario, sino que supone un ejemplo de cómo implementar un sistema de métrica sencillo sobre un código a evaluar.

    Para ello, debemos contemplar los tres escenarios clave a la hora de medir un algoritmo de ordenación:
  • Todos los datos se encuentran de partida ya ordenados (el mejor de los casos).
  • Todos los datos se encuentran de partida ya ordenados pero en sentido inverso al deseado (el peor de los casos).
  • Los datos se encuentran dispuestos en cualquier orden (el caso más habitual).

    Para simular cada uno de estos estados, crearemos 3 listas diferentes de 1000 elementos sobre la que aplicaremos nuestros algoritmos y sus mediciones:
    Code
    var TEST_SIZE = 1000,
         sortedArr = [],
         reverseArr = [],
         randomArr = [];
       
    for( var x = 1; x0; x-- ){
       reverseArr.push(x);
    }
       
    for( var x = 1; x


    Con nuestros arrays preparados, nos falta implementar algún tipo de contador para medir el número de iteraciones que realizan nuestros algoritmos. Para ello, nos valdremos de una variable contadora que introduciremos en el interior (inner loop) de cada una de nuestras funciones:
    Code
    var counter = 0;
       
    function bubbleSort(myArr){
       var size = myArr.length;
       counter = 0;
       
       for( var pass = 1; pass < size; pass++ ){ // outer loop
         for( var left = 0; left < (size - pass); left++){ // inner loop        
           var right = left + 1;
           counter++;
           if( myArr[left] > myArr[right] ){
             swap(myArr, left, right);
           }
         }
       }
       console.log('Bubble Sort: ', counter );
       return myArr;
    }
       
    function selectionSort( myArr ){
       var size = myArr.length;
       counter = 0;
       
       for( var slot = 0; slot < size -1; slot ++ ){ // outer loop
         var smallest = slot;
         for( var check = slot + 1; check < size; check++ ){ // inner loop
           counter++;
           if( myArr[check] < myArr[smallest] ){
             smallest = check;
           }
         }
         swap( myArr, smallest, slot );
       }
       console.info( 'Selection  Sort: ', counter );
       return myArr;
    }
       
    function insertionSort( vector ) {
       var innerCounter = 0;
       counter = 0;
       for (var i=1; i < vector.length; i++) {
         var temp = vector[i];
         var j = i-1;
         counter++;
         while (j >= 0 && vector[j] > temp) {
           innerCounter++;
           vector[j + 1] = vector[j];
           j--;
         }
         vector[j+1] = temp;
       }
       console.info('Insertion Sort: ', innerCounter || counter );
       return vector;
    };


    El contador de la función insertionSort es diferente a los otros dos ya que aquí puede darse el caso (improbable) de que no se entre en el bucle interno. Esto pasaría, efectivamente, si la lista que manejáramos correspondiese a la que hemos etiquietado como el ‘mejor caso’; es decir, donde todos sus elementos estuviesen ya ordenados.

    Con nuestros contadores ya preparados, solo tenemos que ejecutar los algoritmos de ordenación sobre cada uno de los arrays que hemos preparado antes. El resultado que obtenemos es el siguiente:
    Code
    bubbleSort( sortedArr ); // 499500
    bubbleSort( reverseArr ); // 499500
    bubbleSort( randomArr ); // 499500
       
    selectionSort( sortedArr ); // 499500
    selectionSort( reverseArr ); // 499500
    selectionSort( randomArr ); // 499500
       
    insertionSort( sortedArr ); // 999
    insertionSort( reverseArr ); // 499500
    insertionSort( randomArr ); // 257994


    Tenemos varios datos interesantes en estas mediciones:
  • La ordenación por burbuja y por selección relaizan siempre el mismo número de comparaciones.
  • El número de comparaciones que requieren la ordenación por burbujas y por selección es independiente del estado de los datos de entrada.
  • El número de comparaciones requeridas por el algoritmo de inserción es muy sensible al estado inicial de los datos. En el peor de los casos, requiere el mismo número de comparaciones que los otros; en el mejor, le basta con una iteración menos que el número total de elementos que contiene el array.

    Lo más importante de los datos anteriores es que tanto la burbuja como la selección son insensibles al estado de los datos. Pueden considerarse así como algoritmos de “fuerza bruta” en oposición a la inserción que puede describirse como adaptable: si precisa menos trabajo, realiza menos trabajo.

    Conclusión
    Tras los datos arrojados por los métodos anteriores, podemos hacernos una idea de como rinden estos métodos básicos que hemos presentado. Sin embargo, hay que tener cuidado con no extraer más conclusiones de la cuenta.

    Para realmente conocer la diferencia entre sus comportamientos, deberíamos también medir diferentes escenarios como cuánto afecta el número de objetos que componen cada lista de forma precisa (esto sería la escalabilidad) y el tiempo de ejecución real de cada sistema de ordenación (el coste de CPU).

    Como idea final, podemos obtener que, por lo general, un algoritmo de inserción realiza, como mínimo, un trabajo similar al de la burbuja o la selección. Para la gran mayoría de escenarios, sin embargo, su rendimiento se demuestra muy superior y, por tanto, resulta una opción mejor.

    Para la segunda parte de este artículo, estudiaremos algoritmos avanzados como el shellsort, el célebre quicksort o el potente mergesort. Al igual que con los básicos, realizaremos métricas sobre su rendimiento para tener una primera impresión sobre cuál es el método más adecuado para cada uno de los posibles escenarios que pueden presentarse.


    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
  • GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 133 | 6:33 PM
    Estudiando el diseño de jQuery paso a paso


    Introducción
    Hace tiempo se repasasó algunos de los patrones de diseño modulares más importantes que podemos encontrar actualmente en Javascript. Vimos el patrón del módulo tradicional, el revelado, el proxy y algunas variaciones.

    Todas estas estructuras tienen como fin el agrupar una serie de bloques de código con funcionalidades compartidas permitiendo así su reutilización y portabilidad entre proyectos. Es por ejemplo el sistema con el que se articulan bibliotecas como jQuery, ZeptoJS o Mootools por ejemplo.

    Gracias a estos patrones, podemos crear nuestros propios frameworks o aplicaciones cuyo código no interfiera con el de terceros. Se trata en definitiva de buenas prácticas que siempre es conveniente conocer.

    Como cualquier otro patrón de diseño, la definición de estos módulos está sujeta a continua revisión y resulta frecuente encontrar variantes interesantes que mejoran su arquitectura base, su legibilidad, el rendimiento o cualquier otro parámetro ya sea mesurable o simplemente estético.

    En esta ocasión, buscando nuevas reformulaciones, vamos a analizar el sistema que articula a la que posiblemente sea la biblioteca Javascript más popular en la actualidad: jQuery.

    NOTA: A continuación analizaremos el código de la versión 1.6.3 de jQuery la cual es, durante la redacción de este artículo, la última disponible.

    El patrón de módulo jQuery
    Actualmente, jQuery utiliza la siguiente estructura del código:
    Code
    (function( window, undefined ) {
       
       var jQuery = (function() {
         // Code goes here...
       })();
       
       window.jQuery = window.$ = jQuery;
       
    })(window);


    Pasemos a diseccionarla paso a paso para ver cómo funciona:

    El marco de trabajo principal
    La estructura se enmarca en una función autoejecutable que crea un namespace propio. Ésto, permite encapsular todo el contenido y aislarlo de cualquier otro script para evitar problemas de colisión o sobreescritura de variables:
    Code
    (function( window, undefined ) {
       // ...
    })(window);


    Aquí lo importante es que a la función autoejecutable se le pasa un solo argumento (window) mientras que recibe dos (el mismo window y undefined). El porqué de esto responde a una cuestión de rendimiento en el primer caso y a una de seguridad en el segundo: cachear el objeto window en el interior de nuestro script permite que cada vez que lo necesitemos, el intérprete no tiene que subir varios niveles hasta alcanzarlo. Con respecto a undefined, al no recibir ningún argumento, su valor se establece efectivamente como tal (sin definir) previniéndonos contra una hipotética sobreescritura anterior de esta primitiva.

    Yendo un poco más lejos, en nuestro script es muy posible que en algún momento queramos interactuar con el DOM, conocer la versión del navegador para algún tipo de filtrado, o incluso extraer toda la información posible relativa a la URL del documento que ejecuta el script. Para facilitar el acceso a estos datos, jQuery los almacena en forma de variables para poder acceder rápidamente a su contenido en cualquier momento:
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
    })(window);


    Con esto, cuando necesitemos utilizar alguno de los objetos anteriores, el intérprete dispondrá de ellos rápidamente sin la necesidad de ascender niveles o volver a recorrer al objeto padre.

    Definiendo el core
    Una vez creado el marco general y con algunas variables útiles ya declaradas, lo siguiente es crear la función principal que contendrá el núcleo o core de nuestro script. Para ello, utilizaremos una función declarada cuyo nombre se corresponderá con el de la biblioteca en la que trabajamos:
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
       var jQuery = (function(){
         // Core goes here...
       })();
       
    })(window);


    Dentro de esta función es donde se definirán los métodos públicos (la API pública) que tendremos disponibles tras su inicialización. Estos métodos deben definirse a su vez en un objeto interno que debe ser devuelto mediante el comando return al ámbito de nuestra biblioteca. Llamaremos a este objeto intermedio core:
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
       var jQuery = (function(){
       
         var core = {
           // Public methods goes here...
         };
       
         return core;
       
       })();
       
    })(window);


    Ese nuevo objeto core, como hemos comentado más arriba, guardará los métodos públicos de nuestra biblioteca mediante una notación simple de nombre y función a ejecutar:
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
       var jQuery = (function(){
       
         var core = {
       
           publicMethod : function( subject ){
             // publicMethod action goes here...
           }
       
         };
       
         return core;
       
       })();
       
    })(window);


    Con esta estructura, conseguimos que el objeto jQuery devuelto por return, implemente la definición de los métodos que hemos declarado.

    Creando los métodos de nuestra biblioteca
    Para dar cierta funcionalidad a nuestra biblioteca, incluyamos dentro del core un método trim para eliminar los espacios en blanco a izquierda y derecha de una cadena dada:
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
       var jQuery = (function(){
       
         var core = {
       
           trim : function( subject ){
             return subject.replace(/^\s+|\s+$/g, '');
           }
       
         };
       
         return core;
       
       })();
       
    })(window);


    En el código anterior, dentro de la variable jQuery tendremos ahora un objeto con nuestro nuevo método. Para poder utilizarlo, necesitaríamos devolver dicho objeto jQuery al ámbito global.

    Salvado ese punto, solo sería cuestión de añadir más métodos al core hasta cubrir todas las necesidades o especificaciones de la aplicación.

    Devolviendo la biblioteca al ámbito global
    Como hemos comentado en el último ejemplo, la variable jQuery contiene el objeto con los métodos que hemos definido por lo que, si queremos asociar ese objeto al contexto global, únicamente necesitamos añadirlo al window (que siempre se corresponde con el nivel o ámbito más alto):
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
       var jQuery = (function(){
       
         var core = {
       
           trim : function( subject ){
             return subject.replace(/^\s+|\s+$/g, '');
           }
       
         };
       
         return core;
       
       })();
       
       window.jQuery = jQuery;
       
    })(window);


    Ahora, el contexto global (window) cuenta con una nueva variable que en realidad contiene al objeto que hemos creado anteriormente. Como tal, posee aquellos métodos que definimos en el core y que son accesibles de forma pública mediante la notación tradicional:
    Code
    jQuery.trim( '  Hello World    '); // "Hello World"


    Nuestra biblioteca funciona como se espera; no ha sido tan difícil! Pero como observación, rápidamente vemos que todos sus métodos son públicos. ¿Cómo podemos implementar métodos privados dentro de este esquema?

    Métodos privados en el patrón jQuery
    Para crear métodos que solo sean visibles (accesibles) desde el interior de nuestra biblioteca, tenemos que definirlos fuera del objeto core.
    Implementemos en nuestra biblioteca el sistema para comprobar: la función toType:
    Code
    var toType = function(obj) {
       return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
    }


    Si queremos que esta utilidad solo sea accesible por los métodos de nuestra biblioteca sin que pertenezca a la API pública, podemos crear un nuevo objeto private que la contenga:
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
       var private = {
         toType : function(obj) {
           return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
         }
       }
       
       var jQuery = (function(){
       
         var core = {
       
           trim : function( subject ){
             return subject.replace(/^\s+|\s+$/g, '');
           }
       
         };
       
         return core;
       
       })();
       
       window.jQuery = jQuery;
       
    })(window);


    Como este nuevo objeto está fuera del jQuery, no se asocia al window y, por tanto, no llega nunca al ámbito global: permanecerá así como un método privado de nuestra biblioteca.

    Para utilizar sus métodos dentro de nuestro script, bastará con llamarlo del modo tradicional ya que comparten scope:
    Code
    (function( window, undefined ) {
       
       var document  = window.document,
           navigator = window.navigator,
           location  = window.location;
       
       var private = {
         toType : function(obj) {
           return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
         }
       }
       
       var jQuery = (function(){
       
         var core = {
       
           trim : function( subject ){
             if( private.toType( subject ) == 'string' )
               return subject.replace(/^\s+|\s+$/g, '');
             else
               return 'Object must be a String!';
           }
       
         };
       
         return core;
       
       })();
       
       window.jQuery = jQuery;
       
    })(window);


    Lo comprobamos rápidamente:
    Code
    console.log( jQuery.trim( '   Hello World  ' ) ); // "Hello World"
    console.log( jQuery.trim( [1,2] ) ); // Object must be a String!
    console.log( jQuery.toType( [1,2] ) ); // TypeError: jQuery.toType is not a function


    Como podemos ver, toType funciona cuando se llama desde el interior de la biblioteca pero lógicamente devuelve error si tratamos de acceder desde fuera. Hemos conseguido así restringir su visibilidad y limitar su acción exclusivamente al interior del script.

    Asociando un álias
    Finalmente, jQuery permite utilizar el caracter $ como un álias para invocar sus métodos:
    Code
    jQuery.trim('foo');
    $.trim('foo');


    Ambas formas son idénticas. Para asociar un álias a nuestra biblioteca, basta con añadir el nombre escogido al objeto window apuntando al valor al de la biblioteca en sí. Cambiamos únicamente la última parte de nuestro patrón:
    Code
    window.jQuery = window.$ = jQuery;


    Con este último paso, tenemos lista y funcional nuestra biblioteca utilizando una estructura similar a la que presenta jQuery.

    Conclusión
    En el desarrollo moderno de aplicaciones Javascript, es frecuente recurrir a los patrones de diseño para garantizar una arquitectura sólida y fiable.
    Profundizando en estos ejemplos, jQuery ha desarrollado un patrón propio que ha demostrado un alto rendimiento con una elegante estructura. En definitiva, se trata de una función autoejecutable que en último término asocia un nuevo objeto al contexto global del entorno de ejecución. Dicho objeto cuenta con todos los métodos públicos (el API) que queremos ofrecer al usuario (o a terceros) permitiéndonos además, restringir cómodamente la visibilidad de aquellas funcionalidades que queramos definir como privadas.

    Un patrón sin duda muy interesante que bien vale un estudio.


    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 134 | 6:37 PM
    (II Parte)


    Aplicando métodos por referencia
    Uno de los aspectos más interesantes en el uso de jQuery es la aplicación de sus métodos por referencia. Nosotros, en el ejercicio anterior, habíamos creado un objeto donde, para aplicar una funcionalidad concreta a una cadena, ésta se pasaba como argumento del correspondiente método:
    Code
    $.trim('   Hola Mundo '); // Hola Mundo


    Sin embargo, a la hora de trabajar con la API pública de nuestra biblioteca, resulta mucho más cómodo cuando la funcionalidad se aplica sobre un argumento asociado al objeto y no al método. Siguiendo el ejemplo anterior, la nueva propuesta de sintaxis sería:
    Code
    $('  Hola Mundo   ').trim();


    De este modo, ganamos en legibilidad a la vez que abrimos las puertas a otros comportamientos interesantes que veremos más adelante.

    Para permitir este tipo de construcciones, tenemos que realizar varios cambios en nuestra biblioteca; modificaciones que van en la línea de lo que hacen otros frameworks y que nos permitirá conocer un poco mejor estas estructuras relativamente complejas del lenguaje.

    Lo veremos a continuación en detalle pero, para ir poniéndonos sobre la pista, la idea general es permitir que nuestro objeto se comporte bien como una función o bien como un objeto tradicional según la forma en que sea invocado.

    El nuevo patrón
    Para este ejemplo, vamos a renombrar nuestro framework como Utils evitando así posibles colisiones con la biblioteca jQuery genuina. Por el mismo motivo, cambiaremos también el álias y utilizaremos $$ (doble símbolo de dólar) como método abreviado para llamarla.

    La estructura básica quedaría como sigue:
    Code
    (function (undefined) {
       
       var utils = (function () {
       
       })();
       
       window.utils = window.$$ = utils;
       
    })();


    Por el momento no hemos realizado ningún cambio; recurrimos al patrón de módulo modificado donde asociamos directamente el objeto creado al ámbito global representado por window.

    Ahora, para que los métodos que tengamos en nuestro framework puedan trabajar directamente con los argumentos del objeto general, tenemos que observar un detalle importante que se ve más claro cuando aislamos un caso de uso:
    Code
    $$('Hola Mundo');


    Nuestra biblioteca, así invocada, está funcionando realmente como una función a la que se le asigna un argumento, no como un objeto en el que buscamos un método ($$.myMethod()). Por lo tanto, nuestro framework tiene que comportarse como una función o como un objeto según sea el caso.

    Para conseguir el primer objetivo, el que utils responda al comportamiento de una función, crearemos una en su interior que nos servirá de contenedor y que permitirá pasar los argumentos a los métodos que sean llamados a continuación. A esta nueva función la llamaremos core (núcleo) y la implementamos paso a paso de la siguiente forma:
    Code
    (function (undefined) {
       
       var utils = (function () {
       
         var core = function ( args ) {
           /* ... */
         };
       
         // Methods goes here
       
         // Return
         return core;
       
       })();
       
       window.utils = window.$$ = utils;
       
    })();


    Tenemos ahora un núcleo general
    Hemos creado un nuevo objeto, en realidad una función, que puede recibir sus correspondientes argumentos (en este caso de momento solo args). Si avanzamos hasta el final, vemos un return que devuelve directamente dicho objeto/función. De esta forma estamos haciendo que al escribir,
    Code
    $$('Hola Mundo');


    nuestro framework se comporte como una función normal que recoge parámetros (‘Hola Mundo’). Tenemos ya una parte importante adelantada!
    El siguiente paso es sencillo: como sabemos que el flujo de nuestro framework pasa ahora por core cuando utilizamos la fórmula anterior, podemos almacenar sus argumentos en una propiedad del objeto para recuperarla más adelante en los métodos.

    El código para conseguir este paso puede parecer complejo a priori pero, una vez analizado con detenimiento, es en realidad muy simple:
    Code
    (function (undefined) {
       
       var utils = (function () {
       
         var core = function ( args ) {
           return new core.fn.init( args );
         };
       
         core.fn = core.prototype = {
           init: function ( args ) {
             core._args = args;
             return core;
           }
         };
       
         // Methods goes here
       
         // Return
         return core;
       
       })();
       
       window.utils = window.$$ = utils;
       
    })();


    La jugada es devolver desde core, con return, una nueva función que definimos un poco más adelante. Al utilizar la palabra reservada new, hay que recordar que estamos utilizando dicha función como constructor y que, en realidad, estamos creando un nuevo objeto con los atributos que la componen. De este modo, hemos convertido nuestra función inicial en un objeto que ahora acepta métodos.

    En esta estructura, init nos sirve como inicializador mejorado del objeto final: desde aquí, podemos pasar tantos argumentos como necesitemos para, por ejemplo, preconfigurar varios atributos de nuestro objeto final. En este caso, para simplificar el ejercicio, solo pasamos aquello que nos está llegando desde la API pública ( es decir, lo que un usuario haya especificado mediante una sintaxis del tipo $$(‘my string’).myMethod()).

    init coge los argumentos y los asocia (guarda) en el mismo core como una nueva propiedad (_args) que será la que usaremos más adelante cuando tratemos los métodos. Finalmente, devuelve el mismo objeto pero ya modificado y listo para añadirle funcionalidad.

    NOTA: Al nombre de la propiedad le hemos añadido un guión bajo para indicar que se trata de un método privado (no accesible desde la API pública); una convención útil cuando trabajamos con objetos grandes.

    Los métodos de la API pública
    Con nuestros elementos ya accesibles, solo tenemos que comenzar a añadir métodos que los recojan y modifiquen de alguna manera. Como ejemplo, retomaremos de los ejercicios anteriores nuestra función trim() para eliminar los espacios al pricipio y final de una cadena dada.

    NOTA: Ya que el código necesario para llevar a cabo esta funcionalidad es muy sencillo, permite que nos concentremos mejor en cómo se implementa en lugar de en cómo trabaja.

    Para que los métodos sean accesibles éstos deben ser ahora parte del core, por lo que únicamente tenemos que extender dicho objeto usando el sistema tradicional:
    Code
    (function (undefined) {
       
       var utils = (function () {
       
          var core = function ( args ) {
           return new core.fn.init( args );
         };
       
         core.fn = core.prototype = {
           init: function ( args ) {
             core._args = args;
             return utils;
           }
         };
       
         // Methods goes here
         core.trim = function (str) {
           core._args && (str = core._args);
           return str.replace(/^\s+|\s+$/g, '');
         };
       
         // Return
         return core;
       
       })();
       
       window.utils = window.$$ = utils;
       
    })();


    Como vemos, la idea es que cada método que implementemos extienda al núcleo con una nueva función. En este caso, es interesante observar que podemos recoger un argumento. Esto es así para conservar la compatibilidad con la forma anterior. Es decir, que podemos obtener el mismo resultado tanto pasándole un argumento al objeto general como al método en particular:
    Code
    console.log( $$.trim( '  Hola Mundo  ') ) ;  // Retrocompatibilidad con la forma anterior.
    console.log( $$('  Hola Mundo  ').trim() ) ; // Nueva invocación por declaración.

    Para que el framework sepa de dónde tomar el parámetro, hemos añadido un condicional:
    Code
    core._args && (str = core._args);


    Esto lo que hace es preguntar si existen argumentos ya cacheados. En caso de que existan, los tomamos como argumentos; si no, buscamos aquellos pasados directamente al método trim().

    La línea de código anterior, aunque parece compleja, es un simple shotcut de las siguientes:
    Code
    if( core._args ){
       str = core._args
    }


    La sintaxis propuesta funciona porque, como hemos mencionado en varias ocasiones, Javascript es un lenguaje de circuito corto (o cortocircuito). Esto quiere decir que cuando realizamos comparaciones lógicas (booleanas), los términos se evalúan de izquierda a derecha rompiéndose inmediatamente la secuencia tras la primera disconformidad. En este condicional, si la primera parte de la expresión es correcta (si existe core._args), se evalúa el siguiente término. Dicho término (str = core._args) es una expresión, por lo que será ejecutada sin más. Es una forma elegante de ahorrarnos un if y aligerar (aunque sea de forma virtual) la complejidad ciclomática del código.

    Sin embargo, falta un paso más para que esto funcione: en caso de que el usuario haya utilizado la forma anterior de enviar su argumento asociado al método, tenemos que decirle a nuestro código que lo coja de ahí. También es necesario borrar el argumento cacheado tras su uso para que a la siguiente invocación del método, si no hemos asignado ningun elemento sobre el que actuar, no se utilice el que teníamos guardado de la vez anterior.

    Por lo tanto, para llevar a cabo estas dos modificiaciones, necesitamos un par de líneas nuevas justo detrás de la que acabamos de explicar:
    Code
    core._args && (str = core._args);
    str || (str = '');
    core._args = '';


    De nuevo se comprueba si str se corresponde con un valor nulo o indefinido en cuyo caso, lo reasignamos como cadena vacía.

    La siguiente línea únicamente borra cualquier valor almacenado en el atributo core._args para que no sea reutilizado la proxima vez que se utilice la biblioteca.
    Como mejora rápida, para aligerar un poco el código, las dos primeras líneas que hemos indicado pueden refactorizarse utilizando el mismo principio del cortocircuito anterior. Quedaría como sigue:
    Code
    str = core._args || str || '';
    core._args = '';


    Si lo unimos todo, nuestro código tiene ahora el siguiente aspecto:
    Code
    (function (undefined) {
       
       var utils = (function () {
          var core = function ( args ) {
           return new core.fn.init( args );
         };
       
         core.fn = core.prototype = {
           init: function ( args ) {
             core._args = args;
             return utils;
           }
         };
       
         // Methods goes here
         core.trim = function (str) {
           core._args && (str = core._args);
           str || (str = '');
           core._args = '';
           return str.replace(/^\s+|\s+$/g, '');
         };
       
         // Return
         return core;
       
       })();
       
       window.utils = window.$$ = utils;
       
    })();


    Bien! Ahora toca probarlo para ver si funciona como se espera:
    Code
    var sample1 = '  Hello World  ';
    var sample2 = '   Good bye Lenin    ';
       
    console.log( '1', $$.trim( sample1 ) ); // 'Hello World'
    console.log( '2', $$.trim( sample2 ) ); // 'Good bye Lenin'
    console.log( '3', $$( sample1 ).trim() ); // 'Hello World'
    console.log( '4', $$( sample2 ).trim() ); // 'Good bye Lenin'
    console.log( '5', $$.trim( sample2 ) ); // 'Good bye Lenin'
    console.log( '6', $$.trim() ); // ''
    console.log( '7', $$().trim() ); // ''
    console.log( '8', $$.trim() ); // ''
    console.log( '9', $$( sample1).trim( sample2 ) ); // 'Hello World'
    console.log( '10', $$().trim() ); // ''
    console.log( '11', $$( sample1 ).trim( sample2 ) ); // 'Hello World'
    console.log( '12', $$.trim() ); // ''
    console.log( '13', $$( sample1 ).trim( sample2 ) ); // 'Hello World'
    console.log( '14', $$().trim() ); // ''
    console.log( '15', $$( sample1 ).trim( sample2 ) ); //'Hello World'


    Mejorando un poco el patrón
    Llegados a este punto, con nuestra estructura básica ya completa y con uno de sus posibles métodos ya implementados, podríamos decir que nuestro framework es funcional: los resultados son los esperados y el código resulta sencillo de extender y mantener. Sin embargo, como desarrolladores, podemos estar ya pensando en varias mejoras que complementen el trabajo realizado hasta ahora. Por ejemplo:
    - Una fuerte comprobación de tipos en la entrada de argumentos.
    - Un robusto sistema de manejo de excepciones para casos inesperados.
    - Implementar un motor tipo Sizzle para ofrecer así soporte completo al API DOM.
    - …

    Aunque todo lo anterior podría resultar un buen ejercicio para comprobar si nos manejamos bien con esta estructura, quedaría pendiente una feature muchos más interesante: implementar un patrón de diseño encadenado que permita enlazar varios métodos sobre una misma referencia/entrada.
    La finalidad de esta mejora sería conseguir una sintaxis similar a:
    Code
    $$('  Hello World  ').trim().method2().method3(); // And so on...


    En una próxima entrega, veremos qué cambios tenemos que realizar en nuestro framework para conseguir este comportamiento, las ventajas que presenta y también sus inconvenientes en lo que a calidad de código se refiere. En relación a esto último, haremos alusión a la conocida Ley de Demeter y a cómo la enfrentan otras bibliotecas similares.

    Conclusión
    En este artículo hemos visto como, partiendo del patrón tipo jQuery que presentamos en otro artículo, podemos conseguir una arquitectura mejorada de gran flexibilidad a la hora de aplicar distintas funcionalidades sobre aquellos elementos en los que lo necesitemos.

    Finalmente, hemos presentado una mejora importante (aún sin implementar) como es la que ofrece el patrón encadenado (chaining pattern) gracias a la cual, podremos aplicar varios métodos (funciones) sobre un mismo argumento en lo que resulta una sintaxis muy clara y legible.

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    GUARAGUAO
    Mensajes: 2362
    Reputación: 81
    Mensaje Nº 135 | 6:58 PM
    jQuery: Scroll animado hasta un anclaje


    La siguiente función permite crear un agradable efecto de scroll para desplazarse hasta un anclaje. Tan sólo hay que añadir la clase toplink"

    Code
        $("a.toplink").click(function() {   
             $("html, body").animate({   
                 scrollTop: $($(this).attr("href")).offset().top + "px"   
             }, {   
                 duration: 1000,   
                 easing: "swing"   
             });   
             return false;   
         });  


    Ver ejemplo en funcionamiento » »

    Las vírgenes tienen muchas navidades pero ninguna Nochebuena.
    Búscar: