Crear una aplicación aleatoria de sorteos con jQuery

¡El primer sorteo de Tutorialzine ha terminado! Ha llegado el momento de sortear a los ganadores. Pero, como este es un blog de desarrollo web, no podemos simplemente ejecutar un ORDER BY RAND() Consulta MySQL en phpMyAdmin. Además, se deben otorgar tres conjuntos diferentes de premios. Esto requiere un enfoque un poco más elegante:una aplicación jQuery de aleatorización dedicada, especialmente diseñada para elegir ganadores en concursos y sorteos.

La aplicación se divide en tres pasos:en el paso uno, proporciona una lista del nombre y el correo electrónico de los concursantes, divididos por una coma (cada concursante en una línea separada). En el segundo paso, proporciona un nombre de premio y un número, lo que significa la cantidad de copias que se han ofrecido. En el último paso, obtienes una lista aleatoria de concursantes y sus premios.

El HTML

Como de costumbre, comenzamos con el marcado HTML y el nuevo doctype. Después de esto, continuamos con las hojas de estilo. La primera hoja de estilo es generada por el increíble generador de tipos de letra en fontsquirrel. Nos permitirá usar la fuente LeagueGothic no segura para la web en todos los navegadores. Los archivos de fuentes residen en la carpeta LeagueGothic en la demostración.

aleatorizador.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Making a Giveaway Randomizer App w/ jQuery | Tutorialzine Demo</title>

<link rel="stylesheet" type="text/css" href="LeagueGothic/fontface.css" />
<link rel="stylesheet" type="text/css" href="styles.css" />

</head>

<body>

<div class="step" id="step1">
    <div class="section">
        <h1>Step 1</h1>
        <h2>Paste a CSV Formatted List of All The Contestants</h2>

        <textarea></textarea>
        <a href="#" class="button">Next</a>
    </div>
</div>

<div class="step" id="step2">
    <div class="section">
        <h1>Step 2</h1>
        <h2>Paste a CSV Formatted List of All The Prizes</h2>
        <textarea></textarea>
        <a href="#" class="button back">Back</a>
        <a href="#" class="button finish">Finish!</a>
    </div>
</div>

<div class="step" id="step3">
    <div class="section">
        <h1>Step 3</h1>
        <h2>Congratulations to the Winners!</h2>
        <div class="results"></div>
        <a href="#" class="button again">Again</a>
    </div>
</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="md5.js"></script>
<script src="script.js"></script>
</body>
</html>

Como verá en un momento, estamos aplicando una serie de estilos al elemento del cuerpo y lo usamos como un contenedor de bloques normal. En su interior tenemos los tres .paso divs, que contienen su propio conjunto de encabezados, áreas de texto y botones.

Como verá en la siguiente sección del tutorial, estamos haciendo el cuerpo tres veces más ancho que la ventana del navegador, y cada div de sección es exactamente el 33,333 % de su ancho. Esto hace que las secciones sean tan anchas como el navegador (esto sigue siendo así incluso si cambia el tamaño de la ventana).

Por último, incluimos la biblioteca jQuery, nuestro script.js archivo, y otro - md5.js . JavaScript no proporciona medios para calcular hashes md5, por lo que estamos incluyendo una implementación de JavaScript puro del md5() Función PHP, creada por el proyecto php.js. Vamos a necesitar esto en el paso final, donde estamos extrayendo los avatares de los comentaristas de Gravatar, usando sus direcciones de correo electrónico.

El CSS

El siguiente paso en la creación de la aplicación es establecer el CSS. Aquí sólo se presentan los estilos más interesantes. Puede ver el resto en estilos.css en el archivo de descarga.

estilos.css - Parte 1

html{

   /**
    *   The background of the HTML element is
    *   visible as the top and bottom dark strips.
    */

    background-color:#424242;
}

body{
    font-size:13px;
    color:#fff;
    font-family:Arial, Helvetica, sans-serif;

   /**
    *   Using the body element as a
    *   container for the animation
    */

    left:0;
    position:fixed;
    top:5px;
    bottom:5px;
    width:300%;
}

.step{
    /* Each step takes one third of the width */

    float:left;
    height:100%;
    width:33.3333%;
    overflow:hidden;
    position:relative;
}

/* Step 1 */

#step1{ background:url('img/bg_1.jpg') no-repeat center center #6f7c18;}

#step1 textarea{
    -moz-box-shadow:-7px 7px 0 #637018;
    -webkit-box-shadow:-7px 7px 0 #637018;
    box-shadow:-7px 7px 0 #637018;
}

#step1 a.button{
    -moz-box-shadow:-4px 4px 0 #637018;
    -webkit-box-shadow:-4px 4px 0 #637018;
    box-shadow:-4px 4px 0 #637018;
}

#step1 a.button:active{

    /* The pressed state of the button */

    -moz-box-shadow:-2px 2px 0 #637018;
    -webkit-box-shadow:-2px 2px 0 #637018;
    box-shadow:-2px 2px 0 #637018;
}

#step1 h1{ background-color:#4a5310;}

Lo que está sucediendo aquí es que estamos usando el elemento del cuerpo como un contenedor regular y le aplicamos un posicionamiento fijo. Esto mantiene el marcado de la página al mínimo y demuestra que el cuerpo no es diferente de los demás elementos de la página. Estamos haciendo el cuerpo tres veces el ancho de la ventana del navegador. Como todos los tamaños se dan en porcentajes, todo se escalará incluso si cambia el tamaño del navegador.

Observe que hemos aplicado un color de fondo al elemento html. Esto se ve como dos franjas más oscuras en la parte superior e inferior de la aplicación.

Los tres pasos flotan a la izquierda y son el 33,333% del ancho del elemento del cuerpo, lo que hace que llenen perfectamente el ancho de la pantalla. Cada paso tiene un conjunto individual de reglas aplicadas (gracias a los ID de las clases de paso), como una imagen de fondo, diferentes colores para las sombras del cuadro y el encabezado h1. Aquí solo se dan las clases del primer paso, el paso 2 y el paso 3 siguen la misma idea.

estilos.css - Parte 2

/* Each step contains a section, centered in the page */

.section{
    height:550px;
    left:50%;
    margin:-275px 0 0 -328px;
    position:absolute;
    top:50%;
    width:655px;
}

h1{
    /* The step text */

    font-family:'LeagueGothicRegular',Arial,Helvetica,sans-serif;
    font-size:60px;
    position:absolute;
    right:488px;
    text-align:right;
    top:0;
    width:5000px;
    padding:20px 70px 20px 20px;
    font-weight:normal;
}

h2{
    /* The instruction text */
    position:absolute;
    right:0;
    top:50px;
    font-weight:normal;
    font-style:italic;
}

h2,a.button{
    font-family:'Myriad Pro', Corbel, Arial, Helvetica, sans-serif;
}

.section textarea,
.section .results{
    background-color:#fcfcfc;
    border:0;
    bottom:100px;
    color:#888888;
    font-family:Arial,Helvetica,sans-serif;
    font-size:12px;
    height:230px;
    padding:20px;
    position:absolute;
    width:615px;

    outline:none;
    resize:none;
    overflow:auto;
}

Dentro de cada paso div hay un elemento con una .sección clase. Se centra horizontal y verticalmente en la página con CSS. Todos los encabezados, cuadros de texto y botones están posicionados en relación con la sección y también están perfectamente centrados.

La parte más interesante es probablemente el encabezado h1, que siempre se muestra en la parte izquierda de la pantalla (sin importar el tamaño de la ventana) y se detiene precisamente a 488px del borde derecho de la sección. También usa LeagueGothicRegular , la fuente incrustada de fontface, cuya definición puede encontrar definida en LeagueGothic/fontface.css

JQuery

Ahora es el momento de hacer que esta pequeña aplicación funcione. ¡Enciendan sus motores, es hora de jQuery!

script.js - Parte 1

$(document).ready(function(){

    /* An object with element selectors and margin values */

    var buttonMargins = {
        '#step1 a.button'   : '-100%',
        '#step2 a.finish'   : '-200%',
        '#step2 a.back'     : 0,
        '#step3 a.again'    : 0
    }

    var b = $('body');

    // Adding a click event listener to
    // every element in the object:

    $.each(buttonMargins,function(key,val){
        $(key).click(function(){
            b.animate({marginLeft:val});
            return false;
        });
    });

    // An additional click handler for the finish button:

    $('#step2 a.finish').click(function(){

        var resultsDiv = $('#step3 .results');

        // Catching the errors with a try / catch statement:

        try{

            resultsDiv.empty();

            var contestants = parseCSV($('#step1 textarea').val(),'contestants'),
                prizes      = parseCSV($('#step2 textarea').val(),'prizes'),
                allPrizes   = [];

            // The second element of the prizes CSV is
            // the number of copies of the prize

            $.each(prizes, function(){
                for(var i=0;i<this.col2;i++){

                    // The allPrizes array contains
                    // one entry for each prize.

                    allPrizes.push(this.col1);
                }
            });

            if(allPrizes.length > contestants.length){
                throw 'There are more prizes than contestants!';
            }

            // Randomizing both the contestants and the prizes:

            contestants = contestants.shuffle();
            allPrizes   = allPrizes.shuffle();

            // Using Gravatar
            var gravatarURL =   'http://www.gravatar.com/avatar/-REPLACE-?size=50&default='+
                                encodeURIComponent('http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size=50');

            // Generating the markup:
            for(var i=0;i<allPrizes.length;i++){
                var result = $('<div>',{className:'result'});

                // Using a pure JavaScript md5 implementation to generate the hash
                // of the email so we can fetch the avatar from Gravatar:

                result.append($('<img>',{
                    src: gravatarURL.replace('-REPLACE-',md5(contestants[i].col2.toLowerCase()))
                }));

                result.append($('<p>',{
                    className   : 'info',
                    title       : contestants[i].col1 + ', ' +contestants[i].col2,
                    html        : contestants[i].col1 + '<i>'+allPrizes[i]+'</i>'
                }));

                resultsDiv.append(result);
            }

        }
        catch (e){
            // Dispaly the error message:
            resultsDiv.append($('<p>',{className:'error',html:e}));
        }
    });

El script está incluido en la función de escucha de eventos document.ready. Lo primero que hace el script es adjuntar un conjunto de eventos a los botones. Estos crean un movimiento animado del cuerpo a través de un valor de margen negativo y muestran los diferentes pasos. Para evitar que tengamos que escribir los detectores de eventos individualmente, la secuencia de comandos recorre el buttonMargins objeto y adjunta los oyentes para nosotros.

El final El botón recibe un tratamiento especial, ya que cuando se hace clic en él, los datos en formato CSV en las áreas de texto deben analizarse y combinarse aleatoriamente para producir los ganadores. Observe cómo usamos la función md5 que incluimos anteriormente para calcular el hash de correo electrónico en la línea 74, que se usa para obtener el avatar de los concursantes de Gravatar.

script.js - Parte 2

  function parseCSV(str, name){

        // A simple function for parsing CSV formatted text

        var arr = str.split('\n');

        if(!arr.length){
            throw 'The '+name+' list cannot be empty!';
        }

        var tmp = [];
        var retArr = [];

        for(var i=0;i<arr.length;i++){

            if(!arr[i]) continue;

            tmp = arr[i].split(',');

            if(tmp.length!=2){
                throw 'The '+name+' list is malformed!';
            }

            retArr.push({
                col1 : $.trim(tmp[0]),
                col2 : $.trim(tmp[1])
            })
        }

        return retArr;
    }

    // A method for returning a randomized array:
    Array.prototype.shuffle = function(deep){
        var i = this.length, j, t;
        while(i) {
            j = Math.floor((i--) * Math.random());
            t = deep && typeof this[i].shuffle!=='undefined' ? this[i].shuffle() : this[i];
            this[i] = this[j];
            this[j] = t;
        }
        return this;
    };

});

En la segunda parte de script.js , puedes ver el simple parseCSV() función. Está diseñado para analizar el contenido de las dos áreas de texto y devolver una matriz de objetos. Cada objeto contiene un col1 y col2 propiedades, que corresponden a los datos en las áreas de texto. Esto se usa luego para producir las combinaciones de nombre/premio.

Además, observe la reproducción aleatoria método, que se define en el prototipo de matriz . Definirlo de esta manera lo hace disponible para cualquier matriz en el script. Lo usamos para barajar a los concursantes y los premios, para que todos tengan una oportunidad justa de ganar.

¡Con esto, nuestra sencilla aplicación aleatoria está lista!

Uso de la aplicación

Para concursos más pequeños, puede completar manualmente la lista de concursantes y premios, pero para los más grandes, esto está fuera de discusión (por ejemplo, en el sorteo de Tzine hay más de 200 concursantes). Aquí es donde la siguiente consulta es útil:

SELECT DISTINCT comment_author,comment_author_email FROM wp_comments WHERE comment_post_ID = 1132 AND comment_approved = 1

Selecciona el nombre y el correo electrónico de todas las personas que dejaron un comentario en el sorteo (recuerda reemplazar el valor comment_post_ID). Después de ejecutar esta consulta en phpMyAdmin, simplemente haga clic en exportar y elija CSV (recuerde dejar el campo delimitador vacío). Luego simplemente copie y pegue la lista CSV creada en la aplicación.

¡Comparta sus sugerencias y pensamientos sobre la aplicación en la sección de comentarios a continuación!