Created
January 15, 2020 15:14
-
-
Save SethClydesdale/f27f7222b942ffe6eddd00762d45d752 to your computer and use it in GitHub Desktop.
EZQuiz variant that randomizes the order of questions. First file is for editing/pre-production use, second file is for use in production.
This file contains 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
// # FUNCTIONALITY FOR EXERCISES # | |
(function (window, document) { | |
'use strict'; | |
// primary object for functionality of the quizzes | |
window.EZQuiz = { | |
// exercise statistics | |
stats : { | |
problems : 0, // number of problems to solve in the lesson | |
solved : 0, // number of problems solved | |
mistakes : 0, // number of mistakes made in the lesson | |
score : 0, // the student's score | |
exclude : 0 // answers to exclude, mostly for text-only segments in multi-choice quizzes | |
}, | |
// tells us if it is being used on a local file system so we can append index.html to URLs | |
local : window.location.protocol == 'file:' ? 'index.html' : '', | |
// scroll to the specified element: EZQuiz.scrollTo('#lesson-3') | |
// scrolling can be delayed by passing a value that evaluates to true (true; 1; '.') to the second param; delay | |
// the second param is mostly for script generated content, i.e. the exercises, since there's a small delay before the content is visible | |
scrollTo : function (el, delay) { | |
// check if el is a selector | |
if (typeof el == 'string') { | |
el = document.querySelector(el); | |
} | |
var scroll = function () { | |
document.body.scrollTop = el.offsetTop; | |
document.documentElement.scrollTop = el.offsetTop; | |
}; | |
// scroll immediately or wait 100ms | |
// the latter is for exercises, where there's a slight delay before content is available | |
if (delay) { | |
setTimeout(scroll, 100); | |
} else { | |
scroll(); | |
} | |
}, | |
// To generate a quiz simply pass an object with the necessary data (see vocab-1/index.html and other quiz files for examples) | |
generate : function (o) { | |
var zone = document.getElementById('quiz-zone'), // area where quizzes are inserted | |
quiz = '<div id="quiz-info">' + o.info + '</div><div id="question-list">', | |
answers = '<div id="answer-list">', | |
option = 65, // used for tagging answers as A(65), B(66), C(67).. | |
isAnswer = false, | |
q = o.quiz, | |
i = 0, | |
j = q.length, | |
n; | |
// create individual blocks for each question and hide them until later | |
var qNumber = 0; | |
while (q.length) { | |
i = Math.floor(Math.random() * q.length); | |
quiz += '<div id="quiz-q' + qNumber + '" class="question-block" data-qid="' + (qNumber + 1) + '" style="display:none;"><div class="quiz-multi-question">' + (typeof q[i].question != 'undefined' ? q[i].question + (q[i].image ? '<img class="quiz-image" src="../../../resources/images/test-images/' + q[i].image + '" alt="' + q[i].image + '">' : '') : '<div class="text-passage' + (q[i].vertical ? ' vertical-text' : '') + '" ' + (q[i].text.replace(/<br>/g, '').length < 50 ? 'style="text-align:center;"' : '') + '>' + q[i].text + '</div>' + (q[i].helper || '')) + '</div>'; | |
// ready-only questions contain text only, no answers | |
if (q[i].text) { | |
quiz += '<div class="quiz-multi-row"><button class="quiz-multi-answer next-question" onclick="EZQuiz.progress(this, true);">NEXT</button></div>'; | |
++EZQuiz.stats.exclude; // exclude this block from the overall score | |
} else { // standard question block construction | |
// add answers to the question block | |
while (q[i].answers.length) { | |
n = Math.floor(Math.random() * q[i].answers.length); | |
// answers that begin with "+" are the correct answer. '+True'; | |
if (q[i].answers[n].charAt(0) == '+') { | |
isAnswer = true; | |
q[i].answers[n] = q[i].answers[n].slice(1); | |
} | |
quiz += '<div class="quiz-multi-row"><button class="quiz-multi-answer" data-answer="' + isAnswer + '" data-option="' + String.fromCharCode(option++) + '" onclick="EZQuiz.progress(this);">' + q[i].answers[n] + '</button></div>'; | |
isAnswer = false; | |
q[i].answers.splice(n, 1); | |
} | |
} | |
quiz += '</div>'; // ends the question block | |
option = 65; // resets the option id so the next answers begin with A, B, C.. | |
++EZQuiz.stats.problems; // increment problems number | |
q.splice(i, 1); | |
qNumber++; | |
} | |
// add the multi-choice quiz to the quiz zone | |
zone.innerHTML = quiz + '</div><div id="quiz-progress"><div id="quiz-progress-bar"></div></div>'; | |
// begin the quiz | |
EZQuiz.progress('init'); | |
// exercise timer | |
var timer = new Timer(), | |
clock = document.getElementById('quiz-timer'); | |
clock.innerHTML = '00:00:00'; // placeholder | |
timer.start(); | |
timer.addEventListener('secondsUpdated', function (e) { | |
clock.innerHTML = timer.getTimeValues().toString() | |
}); | |
EZQuiz.timer = timer; | |
// indicate the exercise has been loaded in | |
document.getElementById('exercise').className += ' content-loaded ' + o.type + '-quiz'; | |
// jump to the exercise title | |
EZQuiz.scrollTo('#exercise-title', true); | |
}, | |
// increment the progress bar (for multi-choice quizzes) | |
incrementProgressBar : function () { | |
var bar = document.getElementById('quiz-progress-bar'), | |
progress = Math.floor((EZQuiz.stats.solved+1) / EZQuiz.stats.problems * 100); | |
bar.style.width = progress + '%'; | |
bar.innerHTML = '<span id="quiz-progress-text">' + (EZQuiz.stats.solved+1) + '/' + EZQuiz.stats.problems + '</span>'; | |
}, | |
// show the next question in a multi-choice quiz | |
progress : function (answer, exclude) { | |
if (answer == 'init') { | |
document.getElementById('quiz-q' + EZQuiz.stats.solved).style.display = ''; | |
EZQuiz.incrementProgressBar(); | |
} else { | |
// mark the selected answer for reviews | |
answer.className += ' selected-answer'; | |
// hide NEXT button for read-only questions | |
if (exclude) { | |
answer.parentNode.className += ' hidden-answer'; | |
} | |
// increment mistakes if the chosen answer was wrong and add a class to the parent | |
if (answer.dataset.answer == 'false') { | |
answer.parentNode.parentNode.className += ' wrong-answer'; | |
++EZQuiz.stats.mistakes; | |
} | |
// if there's another question, show it and hide the last one | |
var last = document.getElementById('quiz-q' + EZQuiz.stats.solved++), | |
next = document.getElementById('quiz-q' + EZQuiz.stats.solved); | |
if (next) { | |
next.style.display = ''; // show the next question | |
last.style.display = 'none'; // hide the prior question | |
EZQuiz.incrementProgressBar(); | |
} else { // end the quiz if there's no new question | |
EZQuiz.end(); | |
// show all questions and answers | |
for (var q = document.querySelectorAll('[id^="quiz-q"]'), i = 0, j = q.length; i < j; i++) { | |
q[i].style.display = ''; | |
} | |
// hide the progress bar | |
document.getElementById('quiz-progress').style.display = 'none'; | |
} | |
} | |
}, | |
// ends the quiz | |
end : function () { | |
// calculate the total score based on problems solved and mistakes made | |
var solved = EZQuiz.stats.solved - EZQuiz.stats.exclude, | |
problems = EZQuiz.stats.problems - EZQuiz.stats.exclude; | |
EZQuiz.stats.score = Math.floor((solved - EZQuiz.stats.mistakes) * 100 / problems); | |
EZQuiz.timer.stop(); | |
// hide the timer and store it so we can show the completion time in the results | |
var timer = document.getElementById('quiz-timer'), | |
wrong = 'The answers you selected that were wrong are outlined in <span class="t-red">red</span>. The correct answers are outlined in <span class="t-blue">blue</span>. Review these problems before trying again.'; | |
timer.style.display = 'none'; | |
// show the student their results | |
document.getElementById('quiz-result').innerHTML = | |
'<div id="complete-banner" class="center">Quiz Complete!</div>'+ | |
'<div id="result-list">'+ | |
'<div class="result-row"><span class="result-label">Problems Solved:</span>' + problems + '</div>'+ | |
'<div class="result-row"><span class="result-label">Answers Wrong:</span>' + EZQuiz.stats.mistakes + '</div>'+ | |
'<div class="result-row"><span class="result-label">Score:</span>' + EZQuiz.stats.score + '%</div>'+ | |
'<div class="result-row"><span class="result-label">Completion Time:</span>' + timer.innerHTML + '</div>'+ | |
'<div class="result-row center">'+ | |
( // depending on the score, a specific message will show | |
EZQuiz.stats.score == 100 ? 'PERFECT! Great Job, you have mastered this quiz! Feel free to move on or challenge yourself by trying to beat your completion time.' : | |
EZQuiz.stats.score > 70 ? 'Nice work! ' + wrong : | |
'Keep studying! ' + wrong | |
)+ | |
'<div class="center">'+ | |
'<a href="./' + EZQuiz.local + '" class="button">Try Again</a>'+ | |
'<a href="' + document.getElementById('home-link').href + '" class="button">Back to Index</a>'+ | |
'</div>'+ | |
'</div>'+ | |
'</div>'; | |
// this class will indicate the quiz is over so post-test styles can be applied | |
document.getElementById('exercise').className += ' quiz-over'; | |
EZQuiz.scrollTo('#complete-banner', true); // jump to the quiz results | |
} | |
}; | |
}(window, document)); |
This file contains 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
!function(e,s){"use strict";e.EZQuiz={stats:{problems:0,solved:0,mistakes:0,score:0,exclude:0},local:"file:"==e.location.protocol?"index.html":"",scrollTo:function(e,t){"string"==typeof e&&(e=s.querySelector(e));var i=function(){s.body.scrollTop=e.offsetTop,s.documentElement.scrollTop=e.offsetTop};t?setTimeout(i,100):i()},generate:function(e){for(var t,i=s.getElementById("quiz-zone"),a='<div id="quiz-info">'+e.info+'</div><div id="question-list">',r=65,l=!1,n=e.quiz,o=0,u=(n.length,0);n.length;){if(a+='<div id="quiz-q'+u+'" class="question-block" data-qid="'+(u+1)+'" style="display:none;"><div class="quiz-multi-question">'+(void 0!==n[o=Math.floor(Math.random()*n.length)].question?n[o].question+(n[o].image?'<img class="quiz-image" src="../../../resources/images/test-images/'+n[o].image+'" alt="'+n[o].image+'">':""):'<div class="text-passage'+(n[o].vertical?" vertical-text":"")+'" '+(n[o].text.replace(/<br>/g,"").length<50?'style="text-align:center;"':"")+">"+n[o].text+"</div>"+(n[o].helper||""))+"</div>",n[o].text)a+='<div class="quiz-multi-row"><button class="quiz-multi-answer next-question" onclick="EZQuiz.progress(this, true);">NEXT</button></div>',++EZQuiz.stats.exclude;else for(;n[o].answers.length;)t=Math.floor(Math.random()*n[o].answers.length),"+"==n[o].answers[t].charAt(0)&&(l=!0,n[o].answers[t]=n[o].answers[t].slice(1)),a+='<div class="quiz-multi-row"><button class="quiz-multi-answer" data-answer="'+l+'" data-option="'+String.fromCharCode(r++)+'" onclick="EZQuiz.progress(this);">'+n[o].answers[t]+"</button></div>",l=!1,n[o].answers.splice(t,1);a+="</div>",r=65,++EZQuiz.stats.problems,n.splice(o,1),u++}i.innerHTML=a+'</div><div id="quiz-progress"><div id="quiz-progress-bar"></div></div>',EZQuiz.progress("init");var d=new Timer,c=s.getElementById("quiz-timer");c.innerHTML="00:00:00",d.start(),d.addEventListener("secondsUpdated",function(e){c.innerHTML=d.getTimeValues().toString()}),EZQuiz.timer=d,s.getElementById("exercise").className+=" content-loaded "+e.type+"-quiz",EZQuiz.scrollTo("#exercise-title",!0)},incrementProgressBar:function(){var e=s.getElementById("quiz-progress-bar"),t=Math.floor((EZQuiz.stats.solved+1)/EZQuiz.stats.problems*100);e.style.width=t+"%",e.innerHTML='<span id="quiz-progress-text">'+(EZQuiz.stats.solved+1)+"/"+EZQuiz.stats.problems+"</span>"},progress:function(e,t){if("init"==e)s.getElementById("quiz-q"+EZQuiz.stats.solved).style.display="",EZQuiz.incrementProgressBar();else{e.className+=" selected-answer",t&&(e.parentNode.className+=" hidden-answer"),"false"==e.dataset.answer&&(e.parentNode.parentNode.className+=" wrong-answer",++EZQuiz.stats.mistakes);var i=s.getElementById("quiz-q"+EZQuiz.stats.solved++),a=s.getElementById("quiz-q"+EZQuiz.stats.solved);if(a)a.style.display="",i.style.display="none",EZQuiz.incrementProgressBar();else{EZQuiz.end();for(var r=s.querySelectorAll('[id^="quiz-q"]'),l=0,n=r.length;l<n;l++)r[l].style.display="";s.getElementById("quiz-progress").style.display="none"}}},end:function(){var e=EZQuiz.stats.solved-EZQuiz.stats.exclude,t=EZQuiz.stats.problems-EZQuiz.stats.exclude;EZQuiz.stats.score=Math.floor(100*(e-EZQuiz.stats.mistakes)/t),EZQuiz.timer.stop();var i=s.getElementById("quiz-timer"),a='The answers you selected that were wrong are outlined in <span class="t-red">red</span>. The correct answers are outlined in <span class="t-blue">blue</span>. Review these problems before trying again.';i.style.display="none",s.getElementById("quiz-result").innerHTML='<div id="complete-banner" class="center">Quiz Complete!</div><div id="result-list"><div class="result-row"><span class="result-label">Problems Solved:</span>'+t+'</div><div class="result-row"><span class="result-label">Answers Wrong:</span>'+EZQuiz.stats.mistakes+'</div><div class="result-row"><span class="result-label">Score:</span>'+EZQuiz.stats.score+'%</div><div class="result-row"><span class="result-label">Completion Time:</span>'+i.innerHTML+'</div><div class="result-row center">'+(100==EZQuiz.stats.score?"PERFECT! Great Job, you have mastered this quiz! Feel free to move on or challenge yourself by trying to beat your completion time.":EZQuiz.stats.score>70?"Nice work! "+a:"Keep studying! "+a)+'<div class="center"><a href="./'+EZQuiz.local+'" class="button">Try Again</a><a href="'+s.getElementById("home-link").href+'" class="button">Back to Index</a></div></div></div>',s.getElementById("exercise").className+=" quiz-over",EZQuiz.scrollTo("#complete-banner",!0)}}}(window,document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment