274 lines
12 KiB
JavaScript
274 lines
12 KiB
JavaScript
/**
|
|
* /sQuiz/sQuiz.js
|
|
* @version 1.4
|
|
* @desc sQuiz main class file
|
|
* @author Fándly Gergő Zoltán (gergo@systemtest.tk, systemtest.tk)
|
|
* @copy 2017 Fándly Gergő Zoltán
|
|
* License:
|
|
sQuiz for creating small jQuery based quizs in an implementable way
|
|
Copyright (C) 2017 Fándly Gergő Zoltán
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
(function($){
|
|
/**
|
|
* sQuiz(element, quiz)
|
|
* @desc Creating a new quiz based on a json file
|
|
* @param $ element Container in which the quiz will be running
|
|
* @param string quiz A JSON string/JSON object containing an sQuiz parameter list
|
|
*/
|
|
$.sQuiz=function(element, quiz){
|
|
this.element=(element instanceof $)?element:$(element);
|
|
this.quiz=(typeof quiz=="object")?quiz:JSON.parse(quiz);
|
|
this.current=-1;
|
|
this.currentQustion;
|
|
this.reg;
|
|
this.countdown;
|
|
this.elapsedPerTest=(this.quiz.timeLimitPerTest>0)?0:-2;
|
|
this.elapsed=(this.quiz.timeLimit>0)?0:-2;
|
|
this.answers=[];
|
|
this.quizDoneCallback;
|
|
this.quizDoneOptions;
|
|
};
|
|
|
|
|
|
$.sQuiz.prototype={
|
|
/**
|
|
* sQuiz.setRegionalization(lang)
|
|
* @desc Assing an Object which has all the needed vars for language (startQuiz, timeRemaining, etc. Full list in /sQuiz/lang.json), or leave it on default for English
|
|
* @param object lang Object storing language settings
|
|
*/
|
|
setRegionalization: function(lang){
|
|
this.reg=lang;
|
|
},
|
|
|
|
/**
|
|
* sQuiz.setQuizDoneCallback(callback)
|
|
* @desc Assign a function to run when the quiz is finished
|
|
* @param function callback Function to call
|
|
*/
|
|
setQuizDoneCallback: function(callback){
|
|
this.quizDoneCallback=callback;
|
|
},
|
|
|
|
/**
|
|
* sQuiz.setQuizDoneOptions(options)
|
|
* @desc Set options to offer when quiz is finished. Set download to true, to offer downloading. Set upload to true, to offer online submit to upload_url. Set custom to a JS function call to do self made stuff. Custom action's label regionalization is customAction.
|
|
* @param object options Object containing the settings
|
|
*/
|
|
setQuizDoneOptions: function(options){
|
|
this.quizDoneOptions=options;
|
|
},
|
|
|
|
/**
|
|
* sQuiz.secToTime(sec)
|
|
* @desc Function for converting seconds to traditional MM:SS format
|
|
* @param int sec Seconds to convert
|
|
* @return string
|
|
*/
|
|
secToTime: function(sec){
|
|
var mins=Math.floor(sec/60);
|
|
var secs=sec%60;
|
|
var minstr=(mins.toString().length==1)?"0"+mins.toString():mins.toString();
|
|
var secstr=(secs.toString().length==1)?"0"+secs.toString():secs.toString();
|
|
var time=minstr+":"+secstr;
|
|
return time;
|
|
},
|
|
|
|
/**
|
|
* sQuiz.quizDone()
|
|
* @desc Function to call when a test is finished
|
|
*/
|
|
quizDone: function(){
|
|
var points=0;
|
|
$.each(this.answers, function(key, val){
|
|
if(val.correct){
|
|
points++;
|
|
}
|
|
});
|
|
|
|
var self=this;
|
|
this.element.slideUp(function(){
|
|
var buttons="<div class=\"sq sq-menu\">";
|
|
if(self.quizDoneOptions.download==true){
|
|
buttons+="<button class=\"sq sq-big\" type=\"button\" id=\"sqDownloadResults\"><i class=\"fa fa-save\"></i>"+self.reg.downloadResults+"</button>";
|
|
}
|
|
if(self.quizDoneOptions.upload==true){
|
|
buttons+="<button class=\"sq sq-big\" type=\"button=\" id=\"sqUploadResults\"><i class=\"fa fa-upload\"></i>"+self.reg.uploadResults+"</button>";
|
|
}
|
|
if(self.quizDoneOptions.custom!=undefined){
|
|
buttons+="<button class=\"sq sq-big\" type=\"button=\" id=\"sqCustomAction\" onclick=\""+self.quizDoneOptions.custom+"\">"+self.reg.customAction+"</button>";
|
|
}
|
|
buttons+="</div>";
|
|
|
|
self.element.html("<h2>"+self.reg.quizFinished+"</h2><hr class=\"sq sq-placeholder\" style=\"height: 10vh\"><div class=\"sq sq-center\"><h3>"+self.reg.resultsGot+": <b>"+points.toString()+"/"+self.quiz.questions.length+"</b></h3><br><br>"+buttons);
|
|
|
|
$("#sqDownloadResults").on("click", function(){
|
|
var json=JSON.stringify(self.answers);
|
|
var send="text/json;charset=utf-8,"+encodeURIComponent(json);
|
|
$("<a href=\"data:"+send+"\" download=\""+self.quiz.name+"_answers_sQuiz.json\"></a>")[0].click();
|
|
});
|
|
$("#sqUploadResults").on("click", function(){
|
|
var json=JSON.stringify(self.answers);
|
|
var submitter=prompt(self.reg.yourname+":");
|
|
$.ajax({
|
|
url: (self.quizDoneOptions.upload_url!=undefined)?self.quizDoneOptions.upload_url:"",
|
|
type: "POST",
|
|
data: {
|
|
"submitResult": json,
|
|
"submitResult_submitter": submitter
|
|
},
|
|
success: function(res){
|
|
alert(self.reg.idForResult+": "+res);
|
|
}
|
|
});
|
|
});
|
|
|
|
self.element.slideDown();
|
|
});
|
|
|
|
if(this.quizDoneCallback!=undefined){
|
|
this.quizDoneCallback(this.answers, this.quiz);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* sQuiz.nextQuestion()
|
|
* @desc Start the next question. Should be called only internally!
|
|
*/
|
|
nextQuestion: function(){
|
|
var self=this;
|
|
this.current++;
|
|
|
|
if(this.current>=this.quiz.questions.length){
|
|
this.quizDone();
|
|
}
|
|
else{
|
|
var type=this.quiz.questions[this.current].type;
|
|
this.element.slideUp(function(){
|
|
var timer="<p id=\"sqTimer\">"+(self.quiz.timeLimit>0?"<b>"+self.reg.timeLeft+":</b> <span id=\"sqTimeLeft\"></span><br>":"")+(self.quiz.timeLimitPerTest>0?"<b>"+self.reg.timeLeftPerTest+":</b> <span id=\"sqTimeLeftPerTest\"></span>":"")+"</p>";
|
|
var submitbutton="<br><br><div class=\"sq sq-center\"><button class=\"sq green sq-big\" id=\"sqSubmitButton\"><i class=\"fa fa-check\"></i>"+self.reg.submit+"</button></div>";
|
|
self.element.html(timer+"<hr class=\"sq-placeholder\"><div id=\"sqTestArea\" style=\"overflow: auto\"></div>"+submitbutton);
|
|
self.element.children("#sqTimeLeft").html(self.secToTime(self.timeLimit));
|
|
self.element.children("#sqTimeLeftPerTest").html(self.secToTime(self.timeLimitPerTest));
|
|
self.currentQuestion=new $["sQuiz_module_"+type](self, self.quiz.questions[self.current]);
|
|
|
|
$("#sqSubmitButton").on("click", function(){
|
|
self.currentQuestion.submit();
|
|
$("#sqSubmitButton").unbind();
|
|
$("#sqSubmitButton").fadeOut(function(){
|
|
$(this).html("<i class=\"fa fa-arrow-right\"></i>"+self.reg.nextQuestion);
|
|
$(this).fadeIn();
|
|
});
|
|
$("#sqSubmitButton").on("click", function(){
|
|
self.nextQuestion();
|
|
});
|
|
});
|
|
|
|
self.currentQuestion.load();
|
|
self.element.slideDown(function(){
|
|
self.startTimer();
|
|
});
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* sQuiz.init()
|
|
* @desc set up styles and so for the container
|
|
*/
|
|
init: function(){
|
|
var self=this;
|
|
|
|
if(this.reg==undefined){
|
|
this.reg={
|
|
"downloadResults":"Download results",
|
|
"uploadResults":"Upload results",
|
|
"customAction":"Custom action name goes here",
|
|
"quizFinished":"Quiz finished!",
|
|
"resultsGot":"You've got the following results",
|
|
"yourname":"Your name",
|
|
"idForResult":"Share this ID with anybody you want to know your results",
|
|
"timeLeft":"Time left for entire quiz",
|
|
"timeLeftPerTest":"Time left for this question",
|
|
"submit":"Submit",
|
|
"nextQuestion":"Next question",
|
|
"startQuiz":"Start quiz",
|
|
"answer":"Answer"
|
|
};
|
|
}
|
|
|
|
this.element.hide();
|
|
this.element.addClass("sq sq-container");
|
|
this.element.html("<hr class=\"sq sq-placeholder\" style=\"height: 20vh\"><h2>"+this.quiz.name+"</h2><p>"+this.quiz.description+"</p><hr><div class=\"sq sq-center\"><button class=\"sq sq-big\" id=\"sqStart\">"+this.reg.startQuiz+"</button></div>");
|
|
$("#sqStart").on("click", function(){
|
|
self.nextQuestion();
|
|
});
|
|
this.element.slideDown();
|
|
},
|
|
|
|
/**
|
|
* sQuiz.startTimer
|
|
* @desc Starts the countdown
|
|
*/
|
|
startTimer: function(){
|
|
if(this.quiz.timeLimitPerTest>0 || this.quiz.timeLimit>0){
|
|
var self=this;
|
|
this.elapsedPerTest=0;
|
|
|
|
if(self.quiz.timeLimitPerTest>0){
|
|
self.elapsedPerTest++;
|
|
self.element.children("#sqTimer").children("#sqTimeLeftPerTest").html(self.secToTime(self.quiz.timeLimitPerTest-self.elapsedPerTest));
|
|
if(self.elapsedPerTest>=self.quiz.timeLimitPerTest){
|
|
$("#sqSubmitButton")[0].click();
|
|
}
|
|
}
|
|
if(self.quiz.timeLimit>0){
|
|
self.elapsed++;
|
|
self.element.children("#sqTimer").children("#sqTimeLeft").html(self.secToTime(self.quiz.timeLimit-self.elapsed));
|
|
if(self.elapsed>=self.quiz.timeLimit){
|
|
$("#sqSubmitButton")[0].click();
|
|
}
|
|
}
|
|
|
|
this.countdown=window.setInterval(function(self){
|
|
if(self.quiz.timeLimitPerTest>0){
|
|
self.elapsedPerTest++;
|
|
self.element.children("#sqTimer").children("#sqTimeLeftPerTest").html(self.secToTime(self.quiz.timeLimitPerTest-self.elapsedPerTest));
|
|
if(self.elapsedPerTest>=self.quiz.timeLimitPerTest){
|
|
$("#sqSubmitButton")[0].click();
|
|
}
|
|
}
|
|
if(self.quiz.timeLimit>0){
|
|
self.elapsed++;
|
|
self.element.children("#sqTimer").children("#sqTimeLeft").html(self.secToTime(self.quiz.timeLimit-self.elapsed));
|
|
if(self.elapsed>=self.quiz.timeLimit){
|
|
$("#sqSubmitButton")[0].click();
|
|
}
|
|
}
|
|
}, 1000, self);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* sQuiz.stopTimer
|
|
* @desc Stops the countdown
|
|
*/
|
|
stopTimer: function(){
|
|
clearInterval(this.countdown);
|
|
}
|
|
}
|
|
}(jQuery));
|