diff -r 539c9bee5372 -r 7623f9af9272 src/widgets/Quiz.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widgets/Quiz.js Fri Oct 02 11:27:17 2015 +0200
@@ -0,0 +1,388 @@
+IriSP.Widgets.Quiz = function(player, config) {
+ IriSP.Widgets.Widget.call(this, player, config);
+}
+
+IriSP.Widgets.Quiz.prototype = new IriSP.Widgets.Widget();
+
+IriSP.Widgets.Quiz.prototype.defaults = {
+ // annotation_type: "at_quiz",
+ quiz_activated: true,
+ api_serializer: "ldt_annotate",
+ analytics_api: "",
+ api_method: "POST",
+ user: "",
+ userid:""
+}
+
+IriSP.Widgets.Quiz.prototype.template = '
'
+ + ''
+ + '
'
+ + '
{{question}}
'
+ + '
'
+ + '
'
+ + '
'
+ + ''
+ + '
';
+
+IriSP.Widgets.Quiz.prototype.annotationTemplate = '';
+
+IriSP.Widgets.Quiz.prototype.update = function(annotation) {
+ var _this = this;
+
+ if (this.quiz_activated &&
+ this.correct[annotation.id] != 1 &&
+ this.correct[annotation.id] != 0) {
+
+ _this.quiz_displayed = true;
+
+ //Pause the current video
+ this.media.pause();
+
+ this.annotation = annotation;
+
+ var question = annotation.content.data.question;
+ var answers = annotation.content.data.answers;
+ var resource = annotation.content.data.resource;
+
+ $(".Ldt-Quiz-Votes").hide();
+ $(".Ldt-Pause-Add-Question").hide();
+ $(".Ldt-Quiz-Container .Ldt-Quiz-Title").html(question);
+
+ var i = 0;
+
+ var score = Mustache.to_html('{{ correctness.0 }} / {{ correctness.1 }}', { correctness: this.globalScore() });
+ $(".Ldt-Quiz-Index").html(Mustache.to_html("Q{{index}}/{{total}}", { index: annotation.number + 1,
+ total: this.totalAmount }));
+ $(".Ldt-Quiz-Score").html(score);
+ this.question = new IriSP.Widgets.UniqueChoiceQuestion(annotation);
+ this.resource = new IriSP.Widgets.UniqueChoiceQuestion(resource);
+
+ if (annotation.content.data.type == "multiple_choice") {
+ this.question = new IriSP.Widgets.MultipleChoiceQuestion(annotation);
+ this.resource = new IriSP.Widgets.MultipleChoiceQuestion(resource);
+ }
+ else if (annotation.content.data.type == "unique_choice") {
+ this.question = new IriSP.Widgets.UniqueChoiceQuestion(annotation);
+ this.resource = new IriSP.Widgets.UniqueChoiceQuestion(resource);
+ }
+
+ var output = "";
+ for (i = 0; i < answers.length; i++) {
+ output += '' + this.question.renderQuizTemplate(answers[i], i) + ''+ answers[i].content + '
';
+ }
+
+
+ var QR = '';
+ //If there is an attached resource, display it on the resources overlay
+ if (resource != null) {
+ QR = '' + resource + '
';
+ };
+ $(".Ldt-Quiz-Questions").html(QR + output);
+ $(".Ldt-Quiz-Overlay").fadeIn();
+
+ $(".Ldt-Quiz-Submit").fadeIn();
+
+ //Let's automatically check the checkbox/radio if we click on the label
+ $(".quiz-question-label").click(function() {
+ var input = $(this).siblings("input");
+ if (input.prop('checked') && input.prop('type') == 'radio') {
+ // Already checked. Consider a double click on unique question as a validation.
+ _this.answer();
+ } else {
+ input.prop('checked', !input.prop('checked'));
+ }
+ });
+
+ //In case we click on the first "Skip" link
+ $(".Ldt-Quiz-Submit-Skip-Link").click({media: this.media}, function(event) {
+ _this.hide();
+ _this.player.trigger("QuizCreator.skip");
+ event.data.media.play();
+ });
+ }
+};
+
+IriSP.Widgets.Quiz.prototype.hide = function() {
+ var _this = this;
+
+ $(".Ldt-Quiz-Votes").hide();
+ $(".Ldt-Quiz-Overlay").hide();
+ $(".Ldt-Pause-Add-Question").hide();
+ _this.quiz_displayed = false;
+}
+
+IriSP.Widgets.Quiz.prototype.answer = function() {
+ var _this = this;
+
+ function insert_timecode_links (s) {
+ return (s || "").replace(/\s(\d+:\d+)/, function (match, timecode) {
+ return ' ' + timecode + '';
+ });
+ };
+
+ var answers = _this.annotation.content.data.answers;
+
+ // Augment answers with the correct feedback
+ var i = 0;
+ var wrong = 0;
+ // Signature is an array giving the answers signature: 1 for checked, 0 for unchecked
+ // We cannot simply store the right answer index, since there may be multiple-choice questions
+ var signature = [];
+ _this.$.find(".Ldt-Quiz-Question-Check").each( function (code) {
+ var checked = $(this).is(":checked");
+ signature.push(checked ? 1 : 0);
+ var ans = answers[i];
+ if ((ans.correct && !checked)
+ || (!ans.correct && checked)) {
+ wrong += 1;
+ IriSP.jQuery(this).parents(".quiz-question-block").append(''+ insert_timecode_links(ans.feedback) +'
');
+ } else {
+ IriSP.jQuery(this).parents(".quiz-question-block").append(''+ insert_timecode_links(ans.feedback) +'
');
+ }
+ i++;
+ });
+
+ if (wrong) {
+ $(".Ldt-Quiz-Result").html("Mauvaise réponse");
+ $(".Ldt-Quiz-Result").css({"background-color" : "red"});
+ this.correct[this.annotation.id] = 0;
+ } else {
+ $(".Ldt-Quiz-Result").html("Bonne réponse !");
+ $(".Ldt-Quiz-Result").css({"background-color" : "green"});
+ this.correct[this.annotation.id] = 1;
+ }
+
+ $(".Ldt-Quiz-Result").animate({height:"100%"},500, "linear", function() {
+ $(".Ldt-Quiz-Result").delay(2000).animate({ height:"0%" }, 500);
+ });
+
+ var question_number = this.annotation.number + 1;
+ var correctness = this.globalScore();
+ var score = "";
+ score += '' + correctness[0] +' / ' + correctness[1] + '';
+ $(".Ldt-Quiz-Index").html("Q"+ question_number + "/" + this.totalAmount);
+ $(".Ldt-Quiz-Score").html(score);
+
+ this.submit(this.user, this.userid, this.annotation.id, wrong ? 'wrong_answer' : 'right_answer', signature.join(""));
+
+ //Hide the "Validate" button and display the UI dedicated to votes
+ $(".Ldt-Quiz-Submit").fadeOut(400, function () {
+ $(".Ldt-Quiz-Votes").show();
+ });
+};
+
+IriSP.Widgets.Quiz.prototype.globalScore = function() {
+ // Return 2 variables to know how many right and wrong answers there are
+ var values = _.values(this.correct);
+ var ok = values.filter( function (s) { return s == 1; }).length;
+ var not_ok = values.filter( function (s) { return s == 0; }).length;
+ return [ok, not_ok];
+};
+
+IriSP.Widgets.Quiz.prototype.refresh = function() {
+ var _annotations = this.getWidgetAnnotations().sortBy(function(_annotation) {
+ return _annotation.begin;
+ });
+
+ var _this = this;
+
+ _this.totalAmount = _annotations.length;
+ _this.number = 0;
+ _this.correct = {};
+ _this.keys = {};
+
+ _annotations.forEach(function(_a) {
+ //Fix each annotation as "non-answered yet"
+ _this.correct[_a.id] = -1;
+ _this.keys[_this.number] = _a.id;
+ _a.number = _this.number++;
+ });
+
+}
+
+IriSP.Widgets.Quiz.prototype.draw = function() {
+ var _this = this;
+ _this.quiz_displayed = false;
+ this.onMediaEvent("enter-annotation", function (annotation) {
+ var an = _this.getWidgetAnnotations().filter( function (a) { return a === annotation; });
+ if (an.number === undefined) {
+ _this.refresh();
+ }
+ if (an.length) {
+ _this.update(an[0]);
+ };
+ });
+ this.onMdpEvent("Quiz.activate", function() {
+ _this.quiz_activated = true;
+ });
+
+ this.onMdpEvent("Quiz.deactivate", function() {
+ _this.quiz_activated = false;
+ _this.hide();
+ });
+
+ this.onMdpEvent("Quiz.hide", function() {
+ _this.hide();
+ });
+
+ this.onMdpEvent("Quiz.refresh", function() {
+ _this.refresh();
+ });
+
+ this.onMediaEvent("pause", function() {
+ if (! _this.quiz_displayed) {
+ $(".Ldt-Pause-Add-Question").show();
+ }
+ });
+
+ this.onMediaEvent("play", function() {
+ $(".Ldt-Pause-Add-Question").hide();
+ });
+
+ // Add Ldt-Quiz-Overlay widget on top of video player
+ _this.overlay = $("").appendTo($('#' + _this.container));
+ _this.PauseAddQuestion = $("")
+ .on("click", function() { _this.player.trigger("QuizCreator.create"); })
+ .appendTo($('#' + _this.container));
+ _this.overlay.html(this.template);
+
+ $(".Ldt-Quiz-Overlay").hide();
+
+ $(".Ldt-Quiz-Submit input").click(function() {
+ _this.answer();
+ });
+
+ //In case we click on the first "Skip" link
+ $(".Ldt-Quiz-Submit-Skip-Link").click({ media: this.media }, function(event) {
+ _this.submit(_this.user, _this.userid, _this.annotation.id, "skipped_answer", 0);
+ _this.hide();
+ _this.player.trigger("QuizCreator.skip");
+ event.data.media.play();
+ });
+
+ $(".Ldt-Quiz-Votes-Buttons input[type=\"button\"], .Ldt-Quiz-Votes-Buttons a").click({media: this.media}, function(event) {
+ var vote_prop, vote_val;
+
+ if ($(this).hasClass("Ldt-Quiz-Vote-Useful")) {
+ vote_prop = "useful";
+ vote_val = 1;
+ } else if ($(this).hasClass("Ldt-Quiz-Vote-Useless")) {
+ vote_prop = "useless";
+ vote_val = -1;
+
+ $(".Ldt-Ctrl-Quiz-Create").addClass("button_highlight").delay(5000).queue(function() {
+ $(this).removeClass("button_highlight").dequeue();
+ });
+ }else{
+ vote_prop = "skipped_vote";
+ vote_val = 0;
+ }
+
+ _this.submit(_this.user, _this.userid, _this.annotation.id, vote_prop, vote_val);
+
+ //Resume the current video
+ event.data.media.play();
+
+ _this.hide();
+ $(".Ldt-Pause-Add-Question").hide();
+
+ _this.player.trigger("QuizCreator.skip");
+ });
+
+ _this.refresh();
+};
+
+//Generates uid
+//source : http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
+IriSP.Widgets.Widget.prototype.generateUid = function () {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
+ return v.toString(16);
+ });
+}
+
+//UniqueChoice Question
+IriSP.Widgets.UniqueChoiceQuestion = function(annotation) {
+ this.annotation = annotation;
+}
+
+IriSP.Widgets.UniqueChoiceQuestion.prototype = new IriSP.Widgets.Widget();
+
+IriSP.Widgets.UniqueChoiceQuestion.prototype.renderQuizTemplate = function(answer, identifier) {
+ return '';
+}
+
+IriSP.Widgets.UniqueChoiceQuestion.prototype.renderTemplate = function(answer, identifier) {
+ var id = this.generateUid();
+ return '';
+}
+
+IriSP.Widgets.UniqueChoiceQuestion.prototype.renderFullTemplate = function(answer, identifier) {
+ var correct = (answer && answer.correct) ? "checked" : "";
+ var id = this.generateUid();
+ return '';
+}
+
+
+//MultipleChoice Question
+IriSP.Widgets.MultipleChoiceQuestion = function(annotation) {
+ this.annotation = annotation;
+}
+
+IriSP.Widgets.MultipleChoiceQuestion.prototype = new IriSP.Widgets.Widget();
+
+IriSP.Widgets.MultipleChoiceQuestion.prototype.renderQuizTemplate = function(answer, identifier) {
+ return ' ';
+}
+
+IriSP.Widgets.MultipleChoiceQuestion.prototype.renderTemplate = function(answer, identifier) {
+ var id = this.generateUid();
+ return '';
+}
+
+IriSP.Widgets.MultipleChoiceQuestion.prototype.renderFullTemplate = function(answer, identifier) {
+ var correct = (answer && answer.correct) ? "checked" : "";
+ var id = this.generateUid();
+ return ' ';
+}
+
+IriSP.Widgets.Quiz.prototype.submit = function(user,user_id,question,prop,val) {
+ var _this = this;
+ var _url = Mustache.to_html(this.analytics_api, {id: this.source.projectId}),
+ donnees = {
+ "username": user,
+ "useruuid": user_id,
+ "subject": question,
+ "property": prop,
+ "value": val,
+ "session": _this.session_id
+ };
+
+ IriSP.jQuery.ajax({
+ url: _url,
+ type: this.api_method,
+ contentType: 'application/json',
+ data: JSON.stringify(donnees),
+ success: function(_data) {
+ },
+ error: function(_xhr, _error, _thrown) {
+ IriSP.log("Error when sending annotation", _thrown);
+ }
+ });
+}