diff -r 02c04d2c8fd8 -r ac1eacb3aa33 src/widgets/Quiz.js --- a/src/widgets/Quiz.js Sun Nov 12 22:07:33 2017 +0100 +++ b/src/widgets/Quiz.js Wed Sep 04 17:32:50 2024 +0200 @@ -1,388 +1,543 @@ -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; +import Mustache from "mustache"; +import quizStyles from "./Quiz.module.css"; +import jQuery from "jquery"; - 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(); +const Quiz = function (ns) { + return class extends ns.Widgets.Widget { + constructor(player, config) { + super(player, config); + } - //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 + ''; - }); + static defaults = { + // annotation_type: "at_quiz", + quiz_activated: true, + api_serializer: "ldt_annotate", + analytics_api: "", + api_method: "POST", + user: "", + userid: "", }; - var answers = _this.annotation.content.data.answers; + static template = + '
' + + '
' + + '
' + + "
" + + '
' + + '

{{question}}

' + + '
' + + "
" + + "
" + + '" + + "
"; + + static annotationTemplate = ""; + + update(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.render( + '{{ correctness.0 }} / {{ correctness.1 }}', + { correctness: this.globalScore() } + ); + $(".Ldt-Quiz-Index").html( + Mustache.render("Q{{index}}/{{total}}", { + index: annotation.number + 1, + total: this.totalAmount, + }) + ); + $(".Ldt-Quiz-Score").html(score); + this.question = new ns.Widgets.UniqueChoiceQuestion(annotation); + this.resource = new ns.Widgets.UniqueChoiceQuestion(resource); + + if (annotation.content.data.type == "multiple_choice") { + this.question = new ns.Widgets.MultipleChoiceQuestion(annotation); + this.resource = new ns.Widgets.MultipleChoiceQuestion(resource); + } else if (annotation.content.data.type == "unique_choice") { + this.question = new ns.Widgets.UniqueChoiceQuestion(annotation); + this.resource = new ns.Widgets.UniqueChoiceQuestion(resource); + } - // 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 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(); + } + ); + } + } + + hide() { + var _this = this; + + $(".Ldt-Quiz-Votes").hide(); + $(".Ldt-Quiz-Overlay").hide(); + $(".Ldt-Pause-Add-Question").hide(); + _this.quiz_displayed = false; + } + + answer() { + 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) +'
'); + if ((ans.correct && !checked) || (!ans.correct && checked)) { + wrong += 1; + 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) +'
'); + 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; - } + 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); - }); + $(".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); + 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(); - }); -}; + this.submit( + this.user, + this.userid, + this.annotation.id, + wrong ? "wrong_answer" : "right_answer", + signature.join("") + ); -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]; -}; + //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.refresh = function() { - var _annotations = this.getWidgetAnnotations().sortBy(function(_annotation) { + globalScore() { + // 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]; + } + + refresh() { + var _annotations = this.getWidgetAnnotations().sortBy(function ( + _annotation + ) { return _annotation.begin; - }); - - var _this = this; + }); - _this.totalAmount = _annotations.length; - _this.number = 0; - _this.correct = {}; - _this.keys = {}; + 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++; - }); + _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; }); + draw() { + 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(); + _this.refresh(); } if (an.length) { - _this.update(an[0]); - }; - }); - this.onMdpEvent("Quiz.activate", function() { - _this.quiz_activated = true; - }); + _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.deactivate", function () { + _this.quiz_activated = false; + _this.hide(); + }); - this.onMdpEvent("Quiz.hide", function() { - _this.hide(); - }); + this.onMdpEvent("Quiz.hide", function () { + _this.hide(); + }); + + this.onMdpEvent("Quiz.refresh", function () { + _this.refresh(); + }); - this.onMdpEvent("Quiz.refresh", function() { - _this.refresh(); - }); + this.onMediaEvent("pause", function () { + if (!_this.quiz_displayed) { + $(".Ldt-Pause-Add-Question").show(); + } + }); - this.onMediaEvent("pause", function() { - if (! _this.quiz_displayed) { - $(".Ldt-Pause-Add-Question").show(); - } - }); + this.onMediaEvent("play", function () { + $(".Ldt-Pause-Add-Question").hide(); + }); - 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); - // 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-Overlay").hide(); + $(".Ldt-Quiz-Submit input").click(function () { + _this.answer(); + }); - $(".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(); + } + ); - //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; - $(".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; - 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(); + $(".Ldt-Ctrl-Quiz-Create") + .addClass("button_highlight") + .delay(5000) + .queue(function () { + $(this).removeClass("button_highlight").dequeue(); }); - }else{ - vote_prop = "skipped_vote"; - vote_val = 0; - } + } else { + vote_prop = "skipped_vote"; + vote_val = 0; + } - _this.submit(_this.user, _this.userid, _this.annotation.id, vote_prop, vote_val); + _this.submit( + _this.user, + _this.userid, + _this.annotation.id, + vote_prop, + vote_val + ); - //Resume the current video - event.data.media.play(); + //Resume the current video + event.data.media.play(); + + _this.hide(); + $(".Ldt-Pause-Add-Question").hide(); - _this.hide(); - $(".Ldt-Pause-Add-Question").hide(); + _this.player.trigger("QuizCreator.skip"); + }); - _this.player.trigger("QuizCreator.skip"); - }); - - _this.refresh(); + _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); - }); -} +const UniqueChoiceQuestion = function (ns) { + return class extends ns.Widgets.Widget { + constructor(annotation) { + this.annotation = annotation; + } -//UniqueChoice Question -IriSP.Widgets.UniqueChoiceQuestion = function(annotation) { - this.annotation = annotation; -} - -IriSP.Widgets.UniqueChoiceQuestion.prototype = new IriSP.Widgets.Widget(); + renderQuizTemplate(answer, identifier) { + return ( + '' + ); + } -IriSP.Widgets.UniqueChoiceQuestion.prototype.renderQuizTemplate = function(answer, identifier) { - return ''; -} + renderTemplate(answer, identifier) { + var id = this.generateUid(); + return ( + '' + ); + } -IriSP.Widgets.UniqueChoiceQuestion.prototype.renderTemplate = function(answer, identifier) { - var id = this.generateUid(); - return ''; -} + renderFullTemplate(answer, identifier) { + var correct = answer && answer.correct ? "checked" : ""; + var id = this.generateUid(); + return ( + '' + ); + } + }; +}; -IriSP.Widgets.UniqueChoiceQuestion.prototype.renderFullTemplate = function(answer, identifier) { - var correct = (answer && answer.correct) ? "checked" : ""; - var id = this.generateUid(); - return ''; -} - +const MultipleChoiceQuestion = function (ns) { + return class extends ns.Widgets.Widget { + constructor(annotation) { + this.annotation = annotation; + } -//MultipleChoice Question -IriSP.Widgets.MultipleChoiceQuestion = function(annotation) { - this.annotation = annotation; -} - -IriSP.Widgets.MultipleChoiceQuestion.prototype = new IriSP.Widgets.Widget(); + renderQuizTemplate(answer, identifier) { + return ( + ' ' + ); + } -IriSP.Widgets.MultipleChoiceQuestion.prototype.renderQuizTemplate = function(answer, identifier) { - return ' '; -} - -IriSP.Widgets.MultipleChoiceQuestion.prototype.renderTemplate = function(answer, identifier) { - var id = this.generateUid(); - return ''; -} + renderTemplate(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 ' '; -} + renderFullTemplate(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 - }; + submit(user, user_id, question, prop, val) { + var _this = this; + var _url = Mustache.render(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({ + jQuery.ajax({ url: _url, type: this.api_method, - contentType: 'application/json', + contentType: "application/json", data: JSON.stringify(donnees), - success: function(_data) { + success: function (_data) {}, + error: function (_xhr, _error, _thrown) { + ns.log("Error when sending annotation", _thrown); }, - error: function(_xhr, _error, _thrown) { - IriSP.log("Error when sending annotation", _thrown); - } - }); -} + }); + } + }; +}; + +export { Quiz, UniqueChoiceQuestion, MultipleChoiceQuestion, quizStyles }; \ No newline at end of file