Last active
August 29, 2015 14:08
-
-
Save chrisege/8254ccfd17c8c0bdd8db to your computer and use it in GitHub Desktop.
Food Quiz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html class="no-js" lang=""> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title></title> | |
<meta name="description" content=""> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel='stylesheet' type='text/css' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css'></link> | |
</head> | |
<body class="container"> | |
<script type="text/template" id="quizTemplate"> | |
<h1 class="title"> | |
<%= title %> | |
</h1> | |
<h2 class="subtitle"> | |
<%= subtitle %> | |
</h2> | |
<div class="well" id="questionBox"> | |
<div class="row"> | |
<div class="col-sm-10"> | |
<!--<button class="intro startQuiz btn btn-primary">Start the quiz!</button>--> | |
</div> | |
<div class="scores col-sm-2"> | |
<h4>Score: <span id="score"><%= score %></span> / <span id="possibleScore"><%= possibleScore %></span></h4> | |
</div> | |
</div> | |
<div class="question row"> | |
</div> | |
</div> | |
</script> | |
<script type="text/template" id="questionTemplate"> | |
<h3 class="title"> | |
<%= title %> | |
</h3> | |
<div class="row"> | |
<div class="col-sm-4 firstColumn"> | |
<ul> | |
<% _.each( firstColumn, function( item ){ %> | |
<li><%= item %></li> | |
<% }); %> | |
</ul> | |
</div> | |
<div class="col-sm-4"> | |
<div class="secondColumn"></div> | |
<div class="buttons"> | |
<button class="checkResults btn btn-primary">Check Results</button> | |
<button class="nextQuestion btn btn-primary" style="display:none;">Next Question</button> | |
</div> | |
</div> | |
</div> | |
</script> | |
<script type="text/template" id="multiQuestionTemplate"> | |
<h3 class="title"> | |
<%= title %> | |
</h3> | |
<div class="col-sm-4"> | |
<%= question %> | |
<div class="questionCtn"> | |
<% _.each( options, function( option ){ %> | |
<div class="radio"> | |
<label> | |
<input type="radio" name="options" value="<%= option %>"> | |
<%= option %> | |
</label> | |
</div> | |
<% }); %> | |
</div> | |
<div class="answerCtn" style="display:none;"> | |
<h3 class="status"></h3> | |
<p><%= explanation %></p> | |
</div> | |
<div class="buttons"> | |
<button class="checkResults btn btn-primary">Check Answer</button> | |
<button class="nextQuestion btn btn-primary" style="display:none;">Next Question</button> | |
</div> | |
</div> | |
<div class="col-sm-4"> | |
<div class="imgCtn"><img src="<%= image %>" alt="<%= image_alt %>" /></div> | |
</div> | |
</script> | |
<script type="text/template" id="answerTemplate"> | |
<% _.each( shuffledItems, function( item ){ %> | |
<li><%= item %></li> | |
<% }); %> | |
</script> | |
<script type="text/template" id="finalScoreTemplate"> | |
<h3>Your final score is:</h3> | |
<h1><span id="score"><%= score %></span> / <span id="possibleScore"><%= possibleScore %></span></h1> | |
<h2><%= quote %></h2> | |
<p><a href="<%= fb_link %>">Share on Facebook</a></p> | |
</script> | |
<div class="row"> | |
<div id="quiz" class="col-sm-12"> | |
</div> | |
<div id="question" class="col-sm-12"> | |
</div> | |
</div> | |
<script src='https://code.jquery.com/jquery-1.11.1.min.js'></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script> | |
<script src="quiz.js"></script> | |
<script> | |
window.fbAsyncInit = function() { | |
FB.init({ | |
appId : '120005534692936', | |
xfbml : true, | |
version : 'v2.1' | |
}); | |
}; | |
(function(d, s, id){ | |
var js, fjs = d.getElementsByTagName(s)[0]; | |
if (d.getElementById(id)) {return;} | |
js = d.createElement(s); js.id = id; | |
js.src = "//connect.facebook.net/en_US/sdk.js"; | |
fjs.parentNode.insertBefore(js, fjs); | |
}(document, 'script', 'facebook-jssdk')); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var quizApp = quizApp || {}; | |
quizApp.Quiz = Backbone.Model.extend({ | |
defaults: { | |
title: '', | |
subtitle: '', | |
questions: [], | |
score: 0, | |
possibleScore: 0, | |
currentQuestion: 0 | |
}, | |
incrementScores: function(score){ | |
this.set('score', (this.get('score') + score )); | |
this.trigger('change'); | |
}, | |
prepFinalScore: function(){ | |
var resultsRange = this.get('resultsRange'), | |
score = this.get('score'), | |
result; | |
_.each( _.keys(resultsRange).map(function(key){return +key}), function(key){ | |
if (score <= key) { | |
result = key; | |
return false; | |
} | |
}); | |
this.set('quote', resultsRange[result]); | |
this.setFbLink(); | |
return this; | |
}, | |
setFbLink: function(){ | |
//https://www.facebook.com/dialog/feed?app_id=692446294161510&display=popup&link=http://www.clickhole.com/quiz/how-many-these-thoughts-have-you-had-1357&name=I got: You’re A Junior Thinker - How Many Of These Thoughts Have You Had?&description=Think you’ve thought all the thoughts? Take this quiz and find out.&image=http://chimg.onionstatic.com/5346/original/600.jpg&redirect_uri=http://www.clickhole.com/shared?s=fb-shared | |
var quote = this.get('quote'), | |
title = this.get('subtitle'), | |
name = "I got "+ quote + " " +title, | |
link; | |
link = 'https://www.facebook.com/dialog/feed?app_id=120005534692936&display=popup'+ | |
'&link='+ 'http://interactive.wttw.com/where-in-chicago=' + //document.URL+ | |
'&name='+name+ | |
'&description='+'How well do you know Chicago? Take Geoffrey Baer\'s Where in Chicago quiz and find out!'+ | |
'&redirect_uri='+ 'http://interactive.wttw.com/where-in-chicago/' //document.URL | |
this.set('fb_link', link); | |
} | |
}); | |
quizApp.Question = Backbone.Model.extend({ | |
defaults: { | |
title: "", | |
possibleScore: 1 | |
} | |
}); | |
quizApp.multiQuestion = Backbone.Model.extend({ | |
defaults: { | |
title: "", | |
} | |
}); | |
quizApp.Answer = Backbone.Model.extend({ | |
defaults: { | |
items: [], | |
}, | |
initialize: function(){ | |
this.shuffle(); | |
}, | |
shuffle: function(){ | |
this.set('shuffledItems', _.shuffle(this.get('items'))); | |
}, | |
score: function(){ | |
return this.compareArrays(this.get('items'), this.get('shuffledItems')); | |
}, | |
compareArrays: function(arr1, arr2){ | |
var compared = _.map(arr1, function(value, key){ | |
return arr2[key] == value; | |
}); | |
var score = _.reduce(compared, function(memo,val){ | |
return val == true ? memo + 1 : memo; | |
},0); | |
return { | |
score: score, | |
key: compared, | |
items: this.get('items') | |
} | |
}, | |
}); | |
quizApp.QuizView = Backbone.View.extend({ | |
tagName: 'div', | |
template: $("#quizTemplate").html(), | |
questionIndex: 0, | |
questionCount: 0, | |
events: { | |
'click .startQuiz': 'startQuiz', | |
'click .shareFb': 'shareFb' | |
}, | |
initialize: function(){ | |
// create a question collection. | |
// get the questions array, and loop through it | |
// assign the question's array index as its id | |
// and add it to the collection | |
this.questions = new quizApp.QuestionCollection(); | |
_.each(this.model.get('questions'), function(question, index){ | |
question.id = index; | |
this.questions.add(question); | |
this.questionCount += 1; | |
}.bind(this)); | |
this.model.set('possibleScore', this.questions.getPossibleScore()); | |
}, | |
render: function(){ | |
var tmpl = _.template(this.template); | |
this.$el.append(tmpl(this.model.toJSON())); | |
this.startQuiz(); | |
return this; | |
}, | |
renderQuestion: function(){ | |
var question = this.questions.get(this.questionIndex); | |
switch (question.get('type')) { | |
case 'match': | |
this.currentQuestion = new quizApp.QuestionView({ | |
model: question, | |
el: this.$el.find('.question'), | |
}); | |
break; | |
case 'multi': | |
this.currentQuestion = new quizApp.MultiQuestionView({ | |
model: question, | |
el: this.$el.find('.question'), | |
}); | |
break; | |
} | |
this.currentQuestion.model.set('parentView', this); | |
this.currentQuestion.model.set('parentModel', this.model); | |
this.currentQuestion.render(); | |
this.listenTo(this.currentQuestion.model, 'change', this.updateScore); | |
this.listenTo(this.currentQuestion, 'nextQuestion', this.nextQuestion); | |
}, | |
renderFinalScore: function(){ | |
this.$el.find('.scores').remove(); | |
this.model.prepFinalScore(); | |
var tmpl = _.template($('#finalScoreTemplate').html()); | |
this.$el.find('.question').html(tmpl(this.model.toJSON())); | |
}, | |
startQuiz: function(){ | |
this.$el.find('.intro').fadeOut(); | |
this.renderQuestion(); | |
}, | |
updateScore: function(){ | |
this.model.incrementScores( | |
this.currentQuestion.model.get('score') | |
); | |
this.$el.find('#score').html(this.model.get('score')); | |
this.$el.find('#possibleScore').html(this.model.get('possibleScore')); | |
}, | |
nextQuestion: function(){ | |
this.questionIndex += 1; | |
this.currentQuestion.close(); | |
if (this.questionIndex >= this.questionCount) { | |
this.renderFinalScore(); | |
} else { | |
this.renderQuestion(); | |
} | |
} | |
}); | |
quizApp.QuestionView = Backbone.View.extend({ | |
tagName: 'div', | |
template: $("#questionTemplate").html(), | |
initialize: function(){ | |
this.answerModel = new quizApp.Answer({'items': this.model.get('secondColumn')}); | |
this.answerView = new quizApp.AnswerView({model: this.answerModel}); | |
}, | |
events: { | |
'sortupdate':'updateAnswer', | |
'click .checkResults': 'checkResults', | |
'click .nextQuestion': 'nextQuestion' | |
}, | |
render: function(){ | |
var parent = this; | |
var tmpl = _.template(this.template); | |
this.answerView.render(); | |
this.$el.append(tmpl(this.model.toJSON())); | |
this.$('.secondColumn').append(this.answerView.el); | |
this.$('.secondColumn ul').sortable(); | |
return this; | |
}, | |
// method to be run when jQueryUI fires a sortupdate event. | |
// sets answerModel's shuffledItems array to whatever order | |
// the user has put them in. | |
updateAnswer: function(){ | |
var newOrder = []; | |
this.$el.find('.secondColumn li').each(function(){ | |
newOrder.push($(this).html()); | |
}); | |
this.answerModel.set('shuffledItems', newOrder); | |
}, | |
checkResults: function(){ | |
//run the answerModel.score() method and store value locally | |
var score = this.answerModel.score(); | |
// set this.model score and possibleScore values | |
this.model.set({ | |
score: score.score, | |
possibleScore: score.key.length | |
}); | |
// mark the matching responses as true or false, | |
// if false, add the correct answer here | |
// TODO: make "correct answer" show left column value instead? | |
this.$el.find('.secondColumn li').each(function(index, element){ | |
var thisScore = score.key[index].toString(); | |
$(element).removeClass().addClass(thisScore); | |
if (thisScore === 'false') { $(element).append(' ('+score.items[index]+')'); } | |
}); | |
// hide the check results button, show the next question button | |
this.$el.find('.buttons button').each(function(){ | |
$(this).toggle(); | |
}); | |
}, | |
nextQuestion: function(){ | |
this.trigger('nextQuestion'); | |
}, | |
//use instead of remove() because it empties $el instead of removing it. | |
close: function(){ | |
this.unbind(); | |
this.undelegateEvents(); | |
this.stopListening(); | |
this.$el.empty(); | |
}, | |
}); | |
quizApp.MultiQuestionView = Backbone.View.extend({ | |
tagName: 'div', | |
template: $("#multiQuestionTemplate").html(), | |
initialize: function(){ | |
}, | |
events: { | |
'click .checkResults': 'checkResults', | |
'click .nextQuestion': 'nextQuestion' | |
}, | |
render: function(){ | |
var tmpl = _.template(this.template); | |
this.$el.append(tmpl(this.model.toJSON())); | |
return this; | |
}, | |
checkResults: function(){ | |
var selected = this.$el.find('input:radio:checked').val(); | |
var score = (selected === this.model.get('answer') ? 1 : 0); | |
this.model.set({ | |
score: score, | |
possibleScore: 1 | |
}); | |
this.$el.find('.questionCtn').remove(); | |
this.$el.find('.status').html(score === 1 ? 'Correct!' : 'Incorrect!'); | |
this.$el.find('.answerCtn').fadeIn(); | |
this.$el.find('.buttons button').each(function(){ | |
$(this).toggle(); | |
}); | |
}, | |
nextQuestion: function(){ | |
this.trigger('nextQuestion'); | |
}, | |
//use instead of remove() because it empties $el instead of removing it. | |
close: function(){ | |
this.unbind(); | |
this.undelegateEvents(); | |
this.stopListening(); | |
this.$el.empty(); | |
}, | |
}); | |
quizApp.AnswerView = Backbone.View.extend({ | |
tagName: 'ul', | |
template: $("#answerTemplate").html(), | |
render: function(){ | |
var tmpl = _.template(this.template); | |
this.$el.append(tmpl(this.model.toJSON())); | |
return this; | |
} | |
}); | |
quizApp.QuestionCollection = Backbone.Collection.extend({ | |
model: quizApp.Question, | |
getPossibleScore: function(){ | |
var possibleScore = 0; | |
this.each(function(model){ | |
possibleScore += model.get('possibleScore'); | |
}); | |
return possibleScore; | |
} | |
}); | |
var fullQuizMulti = { | |
'title': 'Test Your Knowledge', | |
'subtitle': 'Where in Chicago Food Quiz', | |
'hideIntro': true, | |
'resultsRange': { | |
"0": "Terrible! (zero)", | |
"3": "Not great. (1-3)", | |
"5": "Acceptable. (4-5)", | |
"8": "Pretty good! (6-8)", | |
"10": "Excellent! (9-10)" | |
}, | |
'questions': [ | |
{ | |
'type': 'multi', | |
'question': 'Which of these confections is NOT originally from Chicago?', | |
'image': 'http://lorempixel.com/640/360/?1', | |
'image_alt': 'confections picture', | |
'options': [ | |
'Snickers', | |
'Hershey’s Kisses', | |
'Juicy Fruit Gum', | |
'Milk Duds' | |
], | |
'answer': 'Hershey’s Kisses', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'Authentic African-American southern barbecue served in Chicago is traditionally topped with what?', | |
'image': 'http://lorempixel.com/640/360/?2', | |
'image_alt': 'BBQ picture', | |
'options': [ | |
'A slice of white bread', | |
'Cole Slaw', | |
'Okra', | |
'Onion Rings' | |
], | |
'answer': 'A slice of white bread', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'Which of these food companies was founded in Chicago?', | |
'image': 'http://lorempixel.com/640/360/?3', | |
'image_alt': 'Grocery store shelves', | |
'options': [ | |
'Quaker Oats', | |
'Nabisco', | |
'Kraft', | |
'All of the above' | |
], | |
'answer': 'All of the above', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'Which of these dishes was NOT invented in Chicago?', | |
'image': 'http://lorempixel.com/640/360/?4', | |
'image_alt': 'Table setting with no food yet served', | |
'options': [ | |
'Italian Beef', | |
'Flaming Saganaki', | |
'Chicken Vesuvio', | |
'Chop Suey' | |
], | |
'answer': 'Chop Suey', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'What year was the first Taste of Chicago?', | |
'image': 'http://lorempixel.com/640/360/?5', | |
'image_alt': 'Taste of Chicago', | |
'options': [ | |
'1972', | |
'1980', | |
'1984', | |
'1989' | |
], | |
'answer': '1980', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'When Prohibition ended, which Chicago restaurant was the first in the city to receive a liquor license?', | |
'image': 'http://lorempixel.com/640/360/?6', | |
'image_alt': 'Prohibition', | |
'options': [ | |
'The Berghoff', | |
'Edgewater Beach Hotel', | |
'Tip Top Tap', | |
'Pizzeria Uno' | |
], | |
'answer': 'The Berghoff', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'What year did the Union Stockyards Close?', | |
'image': 'http://lorempixel.com/640/360/?7', | |
'image_alt': 'Stockyards', | |
'options': [ | |
'1953', | |
'1964', | |
'1982', | |
'1971' | |
], | |
'answer': '1971', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'In which suburb did Ray Kroc build the first McDonald’s franchise in 1955 (it’s now a museum)?', | |
'image': 'http://lorempixel.com/640/360/?8', | |
'image_alt': 'McDonalds', | |
'options': [ | |
'Des Plaines', | |
'Oak Brook', | |
'Romeoville', | |
'Homewood' | |
], | |
'answer': 'Des Plaines', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'Invented in Chicago, the “autodoner” is…', | |
'image': 'http://lorempixel.com/640/360/?9', | |
'image_alt': 'Restaurant Kitchen', | |
'options': [ | |
'A machine that mixes milkshakes', | |
'A hand-held food processor', | |
'A device used to cook gyros', | |
'A machine that stuffs hot dogs into casings' | |
], | |
'answer': 'A device used to cook gyros', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
{ | |
'type': 'multi', | |
'question': 'A jibarito sandwich, invented in Chicago, is served on what in place of bread?', | |
'image': 'http://lorempixel.com/640/360/?10', | |
'image_alt': 'Borinquen Restaurant', | |
'options': [ | |
'Romaine lettuce', | |
'Flattened fried plantains', | |
'Newspaper', | |
'Pie crust' | |
], | |
'answer': 'Flattened fried plantains', | |
'explanation': 'Lorem ipsum dolor sit amet.' | |
}, | |
] | |
} | |
var quiz = new quizApp.Quiz(fullQuizMulti); | |
var quizView = new quizApp.QuizView({model: quiz, el:$('#quiz')}); | |
quizView.render(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment