Making a Giveaway Randomizer App w/ jQuery

The first Tutorialzine giveaway has finished! Now is the time to draw the winners. But, as this is a web development blog, we cannot just run an ORDER BY RAND() MySQL query in phpMyAdmin. Even more, three different sets of prizes must be awarded. This calls for a bit more stylish approach – a dedicated randomizer jQuery app, especially made for choosing winners in competitions and giveaways.

The app is divided in three steps – in step one you provide a list of the contestants’ name and email, divided by a comma (each contestant on a separate line). In the second step, you provide a prize name and a number, signifying the number of copies that have been offered. In the last step, you get a randomly selected list of contestants and their prizes.

The HTML

As usual, we start with the HTML markup and the new doctype. After this, we continue with the stylesheets. The first stylesheet is generated by the awesome fontface generator at fontsquirrel. It will allow us to use the non web-safe LeagueGothic font in every browser. The font files themselves reside in the LeagueGothic folder in the demo.

randomizer.html

01 <!DOCTYPE html>
02 <html>
03 <head>
04 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
05 <title>Making a Giveaway Randomizer App w/ jQuery | Tutorialzine Demo</title>
06
07 <link rel="stylesheet" type="text/css" href="LeagueGothic/fontface.css" />
08 <link rel="stylesheet" type="text/css" href="styles.css" />
09
10 </head>
11
12 <body>
13
14 <div class="step" id="step1">
15 <div class="section">
16 <h1>Step 1</h1>
17 <h2>Paste a CSV Formatted List of All The Contestants</h2>
18
19 <textarea></textarea>
20 <a href="#" class="button">Next</a>
21 </div>
22 </div>
23
24 <div class="step" id="step2">
25 <div class="section">
26 <h1>Step 2</h1>
27 <h2>Paste a CSV Formatted List of All The Prizes</h2>
28 <textarea></textarea>
29 <a href="#" class="button back">Back</a>
30 <a href="#" class="button finish">Finish!</a>
31 </div>
32 </div>
33
34 <div class="step" id="step3">
35 <div class="section">
36 <h1>Step 3</h1>
37 <h2>Congratulations to the Winners!</h2>
38 <div class="results"></div>
39 <a href="#" class="button again">Again</a>
40 </div>
41 </div>
42
44 <script src="md5.js"></script>
45 <script src="script.js"></script>
46 </body>
47 </html>

As you will see in a moment, we are applying a number of styles to the body element and use it as a regular block container. Inside it we have the three .step divs, which contain their own set of headings, textareas and buttons.

As you will see in the next section of the tutorial, we are making the body three times wider than the browser window, and each section div is exactly 33.333% of its width. This makes the sections as wide as the browser (this remains so even if you resize the window).

Lastly we include the jQuery library, our script.js file, and another one – md5.js. JavaScript does not provide means of calculating md5 hashes, so we are including a pure JavaScript implementation of the md5() PHP function, created by the php.js project. We are going to need this in the final step, where we are pulling the commenter’s avatars from Gravatar, using their email addresses.

step1

The CSS

The next step in building the app, is laying down the CSS. Only the more interesting styles are presented here. You can see the rest in styles.css in the download archive.

styles.css – Part 1

01 html{
02
03 /**
04 *   The background of the HTML element is
05 *   visible as the top and bottom dark strips.
06 */
07
08 background-color:#424242;
09 }
10
11 body{
12 font-size:13px;
13 color:#fff;
14 font-family:Arial, Helvetica, sans-serif;
15
16 /**
17 *   Using the body element as a
18 *   container for the animation
19 */
20
21 left:0;
22 position:fixed;
23 top:5px;
24 bottom:5px;
25 width:300%;
26 }
27
28 .step{
29 /* Each step takes one third of the width */
30
31 float:left;
32 height:100%;
33 width:33.3333%;
34 overflow:hidden;
35 position:relative;
36 }
37
38 /* Step 1 */
39
40 #step1{ background:url('img/bg_1.jpg') no-repeat center center #6f7c18;}
41
42 #step1 textarea{
43 -moz-box-shadow:-7px 7px 0 #637018;
44 -webkit-box-shadow:-7px 7px 0 #637018;
45 box-shadow:-7px 7px 0 #637018;
46 }
47
48 #step1 a.button{
49 -moz-box-shadow:-4px 4px 0 #637018;
50 -webkit-box-shadow:-4px 4px 0 #637018;
51 box-shadow:-4px 4px 0 #637018;
52 }
53
54 #step1 a.button:active{
55
56 /* The pressed state of the button */
57
58 -moz-box-shadow:-2px 2px 0 #637018;
59 -webkit-box-shadow:-2px 2px 0 #637018;
60 box-shadow:-2px 2px 0 #637018;
61 }
62
63 #step1 h1{ background-color:#4a5310;}

What is happening here, is that we are using the body element as a regular container and apply a fixed positioning on it. This keeps the markup of the page to a minimum and demonstrates that the body is no different from the other elements on the page. We are making the body three times the width of the browser window. As all the sizes are given in percentages, everything is going to scale even if you resize the browser.

Notice that we’ve applied a background color to the html element. This is visible as two darker strips in the top and bottom of the app.

The three steps are floated to the left and are 33.333% of the width of the body element, which makes them perfectly fill the width of the screen. Each step has an individual set of rules applied (thanks to the IDs of the step classes), such as a background image, different colors for the box shadows and the h1 heading. Only the classes of the first step are given here, step2 and step3 follow the same idea.

styles.css – Part 2

01 /* Each step contains a section, centered in the page */
02
03 .section{
04 height:550px;
05 left:50%;
06 margin:-275px 0 0 -328px;
07 position:absolute;
08 top:50%;
09 width:655px;
10 }
11
12 h1{
13 /* The step text */
14
15 font-family:'LeagueGothicRegular',Arial,Helvetica,sans-serif;
16 font-size:60px;
17 position:absolute;
18 right:488px;
19 text-align:right;
20 top:0;
21 width:5000px;
22 padding:20px 70px 20px 20px;
23 font-weight:normal;
24 }
25
26 h2{
27 /* The instruction text */
28 position:absolute;
29 right:0;
30 top:50px;
31 font-weight:normal;
32 font-style:italic;
33 }
34
35 h2,a.button{
36 font-family:'Myriad Pro', Corbel, Arial, Helvetica, sans-serif;
37 }
38
39 .section textarea,
40 .section .results{
41 background-color:#fcfcfc;
42 border:0;
43 bottom:100px;
44 color:#888888;
45 font-family:Arial,Helvetica,sans-serif;
46 font-size:12px;
47 height:230px;
48 padding:20px;
49 position:absolute;
50 width:615px;
51
52 outline:none;
53 resize:none;
54 overflow:auto;
55 }

Inside each step div is an element with a .section class. It is centered horizontally and vertically on the page with CSS. All the headings, textboxes and buttons are positioned in relation with the section and are also perfectly centered.

The most interesting part is probably the h1 heading, which is always shown in the left part of the screen (no matter how large the window is) and stops precisely at 488px from the right border of the section. It also uses LeagueGothicRegular, the fontface embedded font, the definition of which you can find defined in LeagueGothic/fontface.css

The jQuery

Now it is time to actually make this little app work. Fire your engines, it’s jQuery time!

script.js – Part 1

01 $(document).ready(function(){
02
03 /* An object with element selectors and margin values */
04
05 var buttonMargins = {
06 '#step1 a.button' : '-100%',
07 '#step2 a.finish' : '-200%',
08 '#step2 a.back' : 0,
09 '#step3 a.again' : 0
10 }
11
12 var b = $('body');
13
14 // Adding a click event listener to
15 // every element in the object:
16
17 $.each(buttonMargins,function(key,val){
18 $(key).click(function(){
19 b.animate({marginLeft:val});
20 return false;
21 });
22 });
23
24 // An additional click handler for the finish button:
25
26 $('#step2 a.finish').click(function(){
27
28 var resultsDiv = $('#step3 .results');
29
30 // Catching the errors with a try / catch statement:
31
32 try{
33
34 resultsDiv.empty();
35
36 var contestants = parseCSV($('#step1 textarea').val(),'contestants'),
37 prizes      = parseCSV($('#step2 textarea').val(),'prizes'),
38 allPrizes   = [];
39
40 // The second element of the prizes CSV is
41 // the number of copies of the prize
42
43 $.each(prizes, function(){
44 for(var i=0;i<this.col2;i++){
45
46 // The allPrizes array contains
47 // one entry for each prize.
48
49 allPrizes.push(this.col1);
50 }
51 });
52
53 if(allPrizes.length > contestants.length){
54 throw 'There are more prizes than contestants!';
55 }
56
57 // Randomizing both the contestants and the prizes:
58
59 contestants = contestants.shuffle();
60 allPrizes   = allPrizes.shuffle();
61
62 // Using Gravatar
65
66 // Generating the markup:
67 for(var i=0;i<allPrizes.length;i++){
68 var result = $('<div>',{className:'result'});
69
70 // Using a pure JavaScript md5 implementation to generate the hash
71 // of the email so we can fetch the avatar from Gravatar:
72
73 result.append($('<img>',{
74 src: gravatarURL.replace('-REPLACE-',md5(contestants[i].col2.toLowerCase()))
75 }));
76
77 result.append($('<p>',{
78 className   : 'info',
79 title       : contestants[i].col1 + ', ' +contestants[i].col2,
80 html        : contestants[i].col1 + '<i>'+allPrizes[i]+'</i>'
81 }));
82
83 resultsDiv.append(result);
84 }
85
86 }
87 catch (e){
88 // Dispaly the error message:
89 resultsDiv.append($('<p>',{className:'error',html:e}));
90 }
91 });

The script is enclosed in the document.ready event listening function. The first thing the script does is to attach a set of  events to the buttons. These create an animated movement of the body via a negative margin value, and show the different steps. To keep us from having to write the event listeners individually, the script loops through the buttonMargins object and attaches the listeners for us.

The finish button gets special treatment, as when it is clicked, the CSV formatted data in the textareas has to be parsed and randomly combined to produce the winners. Notice how we use the md5 function we included earlier, to calculate the email hash on line 74, which is used to fetch the contestants’s avatar from Gravatar.

step3

script.js – Part 2

01 function parseCSV(str, name){
02
03 // A simple function for parsing CSV formatted text
04
05 var arr = str.split('n');
06
07 if(!arr.length){
08 throw 'The '+name+' list cannot be empty!';
09 }
10
11 var tmp = [];
12 var retArr = [];
13
14 for(var i=0;i<arr.length;i++){
15
16 if(!arr[i]) continue;
17
18 tmp = arr[i].split(',');
19
20 if(tmp.length!=2){
21 throw 'The '+name+' list is malformed!';
22 }
23
24 retArr.push({
25 col1 : $.trim(tmp[0]),
26 col2 : $.trim(tmp[1])
27 })
28 }
29
30 return retArr;
31 }
32
33 // A method for returning a randomized array:
34 Array.prototype.shuffle = function(deep){
35 var i = this.length, j, t;
36 while(i) {
37 j = Math.floor((i--) * Math.random());
38 t = deep && typeof this[i].shuffle!=='undefined' ? this[i].shuffle() : this[i];
39 this[i] = this[j];
40 this[j] = t;
41 }
42 return this;
43 };
44
45 });

In the second part of script.js, you can see the simple parseCSV() function. It is designed to parse the contents of the two textareas and return an array of objects. Each object contains a col1 and col2 properties, which correspond to the data in the textareas. This is later used to produce the name / prize combinations.

Also, notice the shuffle method, which is defined on the Array prototype. Defining it this way makes it available to any array in the script. We use it to shuffle the contestants and the prizes, so that everyone has a fair chance of winning.

With this our simple randomizer app is ready!

Download Demo

Related Posts :

Posted on Wednesday, September 15th, 2010 at 4:10 am | Category: Jquery |

Site Meter