src/widgets/Quiz.js
changeset 1072 ac1eacb3aa33
parent 1068 7623f9af9272
child 1076 510fd2a482f4
equal deleted inserted replaced
1071:02c04d2c8fd8 1072:ac1eacb3aa33
     1 IriSP.Widgets.Quiz = function(player, config) {
     1 import Mustache from "mustache";
     2     IriSP.Widgets.Widget.call(this, player, config);
     2 import quizStyles from "./Quiz.module.css";
     3 }
     3 import jQuery from "jquery";
     4 
     4 
     5 IriSP.Widgets.Quiz.prototype = new IriSP.Widgets.Widget();
     5 const Quiz = function (ns) {
     6 
     6   return class extends ns.Widgets.Widget {
     7 IriSP.Widgets.Quiz.prototype.defaults = {
     7     constructor(player, config) {
     8     // annotation_type: "at_quiz",
     8       super(player, config);
     9 	quiz_activated: true,
     9     }
    10 	api_serializer: "ldt_annotate",
    10 
    11     analytics_api: "",
    11     static defaults = {
    12     api_method: "POST",
    12       // annotation_type: "at_quiz",
    13     user: "",
    13       quiz_activated: true,
    14     userid:""
    14       api_serializer: "ldt_annotate",
    15 }
    15       analytics_api: "",
    16 
    16       api_method: "POST",
    17 IriSP.Widgets.Quiz.prototype.template = '<div class="Ldt-Quiz-Container">'
    17       user: "",
    18 	                                    + '<div class="Ldt-Quiz-Header">'
    18       userid: "",
    19                                         + '  <div class="Ldt-Quiz-Index"></div><div class="Ldt-Quiz-Score"></div>'
    19     };
    20                                         + '</div>'
    20 
    21                                         + '<div class="Ldt-Quiz-Content">'
    21     static template =
    22                                         + '  <h1 class="Ldt-Quiz-Title">{{question}}</h1>'
    22       '<div class="Ldt-Quiz-Container">' +
    23                                         + '  <div class="Ldt-Quiz-Questions">'
    23       '<div class="Ldt-Quiz-Header">' +
    24                                         + '  </div>'
    24       '  <div class="Ldt-Quiz-Index"></div><div class="Ldt-Quiz-Score"></div>' +
    25                                         + '</div>'
    25       "</div>" +
    26                                         + '<div class="Ldt-Quiz-Footer">'
    26       '<div class="Ldt-Quiz-Content">' +
    27                                         + '  <div class="Ldt-Quiz-Votes">'
    27       '  <h1 class="Ldt-Quiz-Title">{{question}}</h1>' +
    28                                         + '      <span class="Ldt-Quiz-Votes-Question">Avez-vous trouvé cette question utile ?</span>'
    28       '  <div class="Ldt-Quiz-Questions">' +
    29                                         + '      <div class="Ldt-Quiz-Votes-Buttons">'
    29       "  </div>" +
    30                                         + '          <div class="Ldt-Quiz-Vote-Skip-Block"><a href="#" class="Ldt-Quiz-Vote-Skip">Passer</a></div>'
    30       "</div>" +
    31                                         + '          <div><input type="button" value="Non" class="Ldt-Quiz-Vote-Useless" /></div>'
    31       '<div class="Ldt-Quiz-Footer">' +
    32                                         + '          <div><input type="button" value="Oui" class="Ldt-Quiz-Vote-Useful" /></div>'
    32       '  <div class="Ldt-Quiz-Votes">' +
    33                                         + '      </div>'
    33       '      <span class="Ldt-Quiz-Votes-Question">Avez-vous trouvé cette question utile ?</span>' +
    34                                         + '  </div>'
    34       '      <div class="Ldt-Quiz-Votes-Buttons">' +
    35                                         + '  <div class="Ldt-Quiz-Submit">'
    35       '          <div class="Ldt-Quiz-Vote-Skip-Block"><a href="#" class="Ldt-Quiz-Vote-Skip">Passer</a></div>' +
    36                                         + '      <div class="Ldt-Quiz-Submit-Button"><input type="button" value="Valider" /></div>'
    36       '          <div><input type="button" value="Non" class="Ldt-Quiz-Vote-Useless" /></div>' +
    37                                         + '      <div class="Ldt-Quiz-Submit-Skip-Link"><a href="#">Passer</a></div><div style="clear:both;"></div>'
    37       '          <div><input type="button" value="Oui" class="Ldt-Quiz-Vote-Useful" /></div>' +
    38                                         + '  </div>'
    38       "      </div>" +
    39                                         + '  <div class="Ldt-Quiz-Result">Bonne réponse</div>'
    39       "  </div>" +
    40                                         + '</div>'
    40       '  <div class="Ldt-Quiz-Submit">' +
    41 										+ '</div>';
    41       '      <div class="Ldt-Quiz-Submit-Button"><input type="button" value="Valider" /></div>' +
    42 
    42       '      <div class="Ldt-Quiz-Submit-Skip-Link"><a href="#">Passer</a></div><div style="clear:both;"></div>' +
    43 IriSP.Widgets.Quiz.prototype.annotationTemplate = '';
    43       "  </div>" +
    44 
    44       '  <div class="Ldt-Quiz-Result">Bonne réponse</div>' +
    45 IriSP.Widgets.Quiz.prototype.update = function(annotation) {
    45       "</div>" +
    46 	var _this = this;
    46       "</div>";
    47 
    47 
    48 	if (this.quiz_activated &&
    48     static annotationTemplate = "";
    49 		this.correct[annotation.id] != 1 &&
    49 
    50 		this.correct[annotation.id] != 0) {
    50     update(annotation) {
    51 
    51       var _this = this;
    52 		_this.quiz_displayed = true;
    52 
    53 
    53       if (
    54 		//Pause the current video
    54         this.quiz_activated &&
    55 		this.media.pause();
    55         this.correct[annotation.id] != 1 &&
    56 
    56         this.correct[annotation.id] != 0
    57 		this.annotation = annotation;
    57       ) {
    58 
    58         _this.quiz_displayed = true;
    59 		var question = annotation.content.data.question;
    59 
    60 		var answers = annotation.content.data.answers;
    60         //Pause the current video
    61 		var resource = annotation.content.data.resource;
    61         this.media.pause();
    62 
    62 
    63 		$(".Ldt-Quiz-Votes").hide();
    63         this.annotation = annotation;
       
    64 
       
    65         var question = annotation.content.data.question;
       
    66         var answers = annotation.content.data.answers;
       
    67         var resource = annotation.content.data.resource;
       
    68 
       
    69         $(".Ldt-Quiz-Votes").hide();
    64         $(".Ldt-Pause-Add-Question").hide();
    70         $(".Ldt-Pause-Add-Question").hide();
    65 		$(".Ldt-Quiz-Container .Ldt-Quiz-Title").html(question);
    71         $(".Ldt-Quiz-Container .Ldt-Quiz-Title").html(question);
    66 
    72 
    67 		var i = 0;
    73         var i = 0;
    68 
    74 
    69 		var score = Mustache.to_html('<span class="Ldt-Quiz-Correct-Answer">{{ correctness.0 }}</span> / <span class="Ldt-Quiz-Incorrect-Answer">{{ correctness.1 }}</span>', { correctness: this.globalScore() });
    75         var score = Mustache.render(
    70 		$(".Ldt-Quiz-Index").html(Mustache.to_html("Q{{index}}/{{total}}", { index: annotation.number + 1,
    76           '<span class="Ldt-Quiz-Correct-Answer">{{ correctness.0 }}</span> / <span class="Ldt-Quiz-Incorrect-Answer">{{ correctness.1 }}</span>',
    71                                                                               total: this.totalAmount }));
    77           { correctness: this.globalScore() }
    72 		$(".Ldt-Quiz-Score").html(score);
    78         );
    73 		this.question = new IriSP.Widgets.UniqueChoiceQuestion(annotation);
    79         $(".Ldt-Quiz-Index").html(
    74 		this.resource = new IriSP.Widgets.UniqueChoiceQuestion(resource);
    80           Mustache.render("Q{{index}}/{{total}}", {
    75 
    81             index: annotation.number + 1,
    76 		if (annotation.content.data.type == "multiple_choice") {
    82             total: this.totalAmount,
    77 			this.question = new IriSP.Widgets.MultipleChoiceQuestion(annotation);
    83           })
    78 		this.resource = new IriSP.Widgets.MultipleChoiceQuestion(resource);
    84         );
    79 		}
    85         $(".Ldt-Quiz-Score").html(score);
    80 		else if (annotation.content.data.type == "unique_choice") {
    86         this.question = new ns.Widgets.UniqueChoiceQuestion(annotation);
    81 			this.question = new IriSP.Widgets.UniqueChoiceQuestion(annotation);
    87         this.resource = new ns.Widgets.UniqueChoiceQuestion(resource);
    82 		this.resource = new IriSP.Widgets.UniqueChoiceQuestion(resource);
    88 
    83 		}
    89         if (annotation.content.data.type == "multiple_choice") {
    84 
    90           this.question = new ns.Widgets.MultipleChoiceQuestion(annotation);
    85 		var output = "";
    91           this.resource = new ns.Widgets.MultipleChoiceQuestion(resource);
    86 		for (i = 0; i < answers.length; i++) {
    92         } else if (annotation.content.data.type == "unique_choice") {
    87 			output += '<div class="quiz-question-block"><p>' + this.question.renderQuizTemplate(answers[i], i) + '<span class="quiz-question-label">'+ answers[i].content + '</span></p></div>';
    93           this.question = new ns.Widgets.UniqueChoiceQuestion(annotation);
    88 		}
    94           this.resource = new ns.Widgets.UniqueChoiceQuestion(resource);
    89 
    95         }
    90 
    96 
    91 		var QR = '';
    97         var output = "";
    92 		//If there is an attached resource, display it on the resources overlay
    98         for (i = 0; i < answers.length; i++) {
    93 		if (resource != null) {
    99           output +=
    94             QR = '<div class="quiz-resource-block" id="resource" >' + resource + '</div>';
   100             '<div class="quiz-question-block"><p>' +
    95         };
   101             this.question.renderQuizTemplate(answers[i], i) +
    96 		$(".Ldt-Quiz-Questions").html(QR + output);
   102             '<span class="quiz-question-label">' +
    97 		$(".Ldt-Quiz-Overlay").fadeIn();
   103             answers[i].content +
    98 
   104             "</span></p></div>";
    99 		$(".Ldt-Quiz-Submit").fadeIn();
   105         }
   100 
   106 
   101 		//Let's automatically check the checkbox/radio if we click on the label
   107         var QR = "";
   102 		$(".quiz-question-label").click(function() {
   108         //If there is an attached resource, display it on the resources overlay
   103             var input = $(this).siblings("input");
   109         if (resource != null) {
   104             if (input.prop('checked') && input.prop('type') == 'radio') {
   110           QR =
   105                 // Already checked. Consider a double click on unique question as a validation.
   111             '<div class="quiz-resource-block" id="resource" >' +
   106 		        _this.answer();
   112             resource +
   107             } else {
   113             "</div>";
   108                 input.prop('checked', !input.prop('checked'));
   114         }
   109             }
   115         $(".Ldt-Quiz-Questions").html(QR + output);
   110 		});
   116         $(".Ldt-Quiz-Overlay").fadeIn();
   111 
   117 
   112 		//In case we click on the first "Skip" link
   118         $(".Ldt-Quiz-Submit").fadeIn();
   113 		$(".Ldt-Quiz-Submit-Skip-Link").click({media: this.media}, function(event) {
   119 
   114 			_this.hide();
   120         //Let's automatically check the checkbox/radio if we click on the label
   115 			_this.player.trigger("QuizCreator.skip");
   121         $(".quiz-question-label").click(function () {
   116 			event.data.media.play();
   122           var input = $(this).siblings("input");
   117 		});
   123           if (input.prop("checked") && input.prop("type") == "radio") {
   118 	}
   124             // Already checked. Consider a double click on unique question as a validation.
   119 };
   125             _this.answer();
   120 
   126           } else {
   121 IriSP.Widgets.Quiz.prototype.hide = function() {
   127             input.prop("checked", !input.prop("checked"));
   122 	var _this = this;
   128           }
   123 
   129         });
   124 	$(".Ldt-Quiz-Votes").hide();
   130 
   125 	$(".Ldt-Quiz-Overlay").hide();
   131         //In case we click on the first "Skip" link
   126 	$(".Ldt-Pause-Add-Question").hide();
   132         $(".Ldt-Quiz-Submit-Skip-Link").click(
   127 	_this.quiz_displayed = false;
   133           { media: this.media },
   128 }
   134           function (event) {
   129 
   135             _this.hide();
   130 IriSP.Widgets.Quiz.prototype.answer = function() {
   136             _this.player.trigger("QuizCreator.skip");
   131 	var _this = this;
   137             event.data.media.play();
   132 
   138           }
   133     function insert_timecode_links (s) {
   139         );
       
   140       }
       
   141     }
       
   142 
       
   143     hide() {
       
   144       var _this = this;
       
   145 
       
   146       $(".Ldt-Quiz-Votes").hide();
       
   147       $(".Ldt-Quiz-Overlay").hide();
       
   148       $(".Ldt-Pause-Add-Question").hide();
       
   149       _this.quiz_displayed = false;
       
   150     }
       
   151 
       
   152     answer() {
       
   153       var _this = this;
       
   154 
       
   155       function insert_timecode_links(s) {
   134         return (s || "").replace(/\s(\d+:\d+)/, function (match, timecode) {
   156         return (s || "").replace(/\s(\d+:\d+)/, function (match, timecode) {
   135             return ' <a href="#t=' + (IriSP.timestamp2ms(timecode) / 1000) + '">' + timecode + '</a>';
   157           return (
       
   158             ' <a href="#t=' +
       
   159             ns.timestamp2ms(timecode) / 1000 +
       
   160             '">' +
       
   161             timecode +
       
   162             "</a>"
       
   163           );
   136         });
   164         });
   137     };
   165       }
   138 
   166 
   139 	var answers = _this.annotation.content.data.answers;
   167       var answers = _this.annotation.content.data.answers;
   140 
   168 
   141     // Augment answers with the correct feedback
   169       // Augment answers with the correct feedback
   142     var i = 0;
   170       var i = 0;
   143     var wrong = 0;
   171       var wrong = 0;
   144     // Signature is an array giving the answers signature: 1 for checked, 0 for unchecked
   172       // Signature is an array giving the answers signature: 1 for checked, 0 for unchecked
   145     // We cannot simply store the right answer index, since there may be multiple-choice questions
   173       // We cannot simply store the right answer index, since there may be multiple-choice questions
   146     var signature = [];
   174       var signature = [];
   147     _this.$.find(".Ldt-Quiz-Question-Check").each( function (code) {
   175       _this.$.find(".Ldt-Quiz-Question-Check").each(function (code) {
   148         var checked = $(this).is(":checked");
   176         var checked = $(this).is(":checked");
   149         signature.push(checked ? 1 : 0);
   177         signature.push(checked ? 1 : 0);
   150         var ans = answers[i];
   178         var ans = answers[i];
   151         if ((ans.correct && !checked)
   179         if ((ans.correct && !checked) || (!ans.correct && checked)) {
   152             || (!ans.correct && checked)) {
   180           wrong += 1;
   153             wrong += 1;
   181           jQuery(this)
   154             IriSP.jQuery(this).parents(".quiz-question-block").append('<div class="quiz-question-feedback quiz-question-incorrect-feedback">'+ insert_timecode_links(ans.feedback) +'</div>');
   182             .parents(".quiz-question-block")
       
   183             .append(
       
   184               '<div class="quiz-question-feedback quiz-question-incorrect-feedback">' +
       
   185                 insert_timecode_links(ans.feedback) +
       
   186                 "</div>"
       
   187             );
   155         } else {
   188         } else {
   156             IriSP.jQuery(this).parents(".quiz-question-block").append('<div class="quiz-question-feedback quiz-question-correct-feedback">'+ insert_timecode_links(ans.feedback) +'</div>');
   189           jQuery(this)
       
   190             .parents(".quiz-question-block")
       
   191             .append(
       
   192               '<div class="quiz-question-feedback quiz-question-correct-feedback">' +
       
   193                 insert_timecode_links(ans.feedback) +
       
   194                 "</div>"
       
   195             );
   157         }
   196         }
   158         i++;
   197         i++;
   159     });
   198       });
   160 
   199 
   161 	if (wrong) {
   200       if (wrong) {
   162 		$(".Ldt-Quiz-Result").html("Mauvaise réponse");
   201         $(".Ldt-Quiz-Result").html("Mauvaise réponse");
   163 		$(".Ldt-Quiz-Result").css({"background-color" : "red"});
   202         $(".Ldt-Quiz-Result").css({ "background-color": "red" });
   164 		this.correct[this.annotation.id] = 0;
   203         this.correct[this.annotation.id] = 0;
   165 	} else {
   204       } else {
   166 		$(".Ldt-Quiz-Result").html("Bonne réponse !");
   205         $(".Ldt-Quiz-Result").html("Bonne réponse !");
   167 		$(".Ldt-Quiz-Result").css({"background-color" : "green"});
   206         $(".Ldt-Quiz-Result").css({ "background-color": "green" });
   168 		this.correct[this.annotation.id] = 1;
   207         this.correct[this.annotation.id] = 1;
   169 	}
   208       }
   170 
   209 
   171 	$(".Ldt-Quiz-Result").animate({height:"100%"},500, "linear", function() {
   210       $(".Ldt-Quiz-Result").animate(
   172 		$(".Ldt-Quiz-Result").delay(2000).animate({ height:"0%" }, 500);
   211         { height: "100%" },
   173 	});
   212         500,
   174 
   213         "linear",
   175 	var question_number = this.annotation.number + 1;
   214         function () {
   176 	var correctness = this.globalScore();
   215           $(".Ldt-Quiz-Result").delay(2000).animate({ height: "0%" }, 500);
   177 	var score = "";
   216         }
   178 	score += '<span class="Ldt-Quiz-Correct-Answer">' + correctness[0] +'</span> / <span class="Ldt-Quiz-Incorrect-Answer">' + correctness[1] + '</span>';
   217       );
   179 	$(".Ldt-Quiz-Index").html("Q"+ question_number + "/" + this.totalAmount);
   218 
   180 	$(".Ldt-Quiz-Score").html(score);
   219       var question_number = this.annotation.number + 1;
   181 
   220       var correctness = this.globalScore();
   182 	this.submit(this.user, this.userid, this.annotation.id, wrong ? 'wrong_answer' : 'right_answer', signature.join(""));
   221       var score = "";
   183 
   222       score +=
   184 	//Hide the "Validate" button and display the UI dedicated to votes
   223         '<span class="Ldt-Quiz-Correct-Answer">' +
   185 	$(".Ldt-Quiz-Submit").fadeOut(400, function () {
   224         correctness[0] +
   186 	    $(".Ldt-Quiz-Votes").show();
   225         '</span> / <span class="Ldt-Quiz-Incorrect-Answer">' +
   187     });
   226         correctness[1] +
       
   227         "</span>";
       
   228       $(".Ldt-Quiz-Index").html("Q" + question_number + "/" + this.totalAmount);
       
   229       $(".Ldt-Quiz-Score").html(score);
       
   230 
       
   231       this.submit(
       
   232         this.user,
       
   233         this.userid,
       
   234         this.annotation.id,
       
   235         wrong ? "wrong_answer" : "right_answer",
       
   236         signature.join("")
       
   237       );
       
   238 
       
   239       //Hide the "Validate" button and display the UI dedicated to votes
       
   240       $(".Ldt-Quiz-Submit").fadeOut(400, function () {
       
   241         $(".Ldt-Quiz-Votes").show();
       
   242       });
       
   243     }
       
   244 
       
   245     globalScore() {
       
   246       // Return 2 variables to know how many right and wrong answers there are
       
   247       var values = _.values(this.correct);
       
   248       var ok = values.filter(function (s) {
       
   249         return s == 1;
       
   250       }).length;
       
   251       var not_ok = values.filter(function (s) {
       
   252         return s == 0;
       
   253       }).length;
       
   254       return [ok, not_ok];
       
   255     }
       
   256 
       
   257     refresh() {
       
   258       var _annotations = this.getWidgetAnnotations().sortBy(function (
       
   259         _annotation
       
   260       ) {
       
   261         return _annotation.begin;
       
   262       });
       
   263 
       
   264       var _this = this;
       
   265 
       
   266       _this.totalAmount = _annotations.length;
       
   267       _this.number = 0;
       
   268       _this.correct = {};
       
   269       _this.keys = {};
       
   270 
       
   271       _annotations.forEach(function (_a) {
       
   272         //Fix each annotation as "non-answered yet"
       
   273         _this.correct[_a.id] = -1;
       
   274         _this.keys[_this.number] = _a.id;
       
   275         _a.number = _this.number++;
       
   276       });
       
   277     }
       
   278 
       
   279     draw() {
       
   280       var _this = this;
       
   281       _this.quiz_displayed = false;
       
   282       this.onMediaEvent("enter-annotation", function (annotation) {
       
   283         var an = _this.getWidgetAnnotations().filter(function (a) {
       
   284           return a === annotation;
       
   285         });
       
   286         if (an.number === undefined) {
       
   287           _this.refresh();
       
   288         }
       
   289         if (an.length) {
       
   290           _this.update(an[0]);
       
   291         }
       
   292       });
       
   293       this.onMdpEvent("Quiz.activate", function () {
       
   294         _this.quiz_activated = true;
       
   295       });
       
   296 
       
   297       this.onMdpEvent("Quiz.deactivate", function () {
       
   298         _this.quiz_activated = false;
       
   299         _this.hide();
       
   300       });
       
   301 
       
   302       this.onMdpEvent("Quiz.hide", function () {
       
   303         _this.hide();
       
   304       });
       
   305 
       
   306       this.onMdpEvent("Quiz.refresh", function () {
       
   307         _this.refresh();
       
   308       });
       
   309 
       
   310       this.onMediaEvent("pause", function () {
       
   311         if (!_this.quiz_displayed) {
       
   312           $(".Ldt-Pause-Add-Question").show();
       
   313         }
       
   314       });
       
   315 
       
   316       this.onMediaEvent("play", function () {
       
   317         $(".Ldt-Pause-Add-Question").hide();
       
   318       });
       
   319 
       
   320       // Add Ldt-Quiz-Overlay widget on top of video player
       
   321       _this.overlay = $("<div class='Ldt-Quiz-Overlay'></div>").appendTo(
       
   322         $("#" + _this.container)
       
   323       );
       
   324       _this.PauseAddQuestion = $(
       
   325         "<div class='Ldt-Pause-Add-Question' title='Ajoutez une question !'>"
       
   326       )
       
   327         .on("click", function () {
       
   328           _this.player.trigger("QuizCreator.create");
       
   329         })
       
   330         .appendTo($("#" + _this.container));
       
   331       _this.overlay.html(this.template);
       
   332 
       
   333       $(".Ldt-Quiz-Overlay").hide();
       
   334 
       
   335       $(".Ldt-Quiz-Submit input").click(function () {
       
   336         _this.answer();
       
   337       });
       
   338 
       
   339       //In case we click on the first "Skip" link
       
   340       $(".Ldt-Quiz-Submit-Skip-Link").click(
       
   341         { media: this.media },
       
   342         function (event) {
       
   343           _this.submit(
       
   344             _this.user,
       
   345             _this.userid,
       
   346             _this.annotation.id,
       
   347             "skipped_answer",
       
   348             0
       
   349           );
       
   350           _this.hide();
       
   351           _this.player.trigger("QuizCreator.skip");
       
   352           event.data.media.play();
       
   353         }
       
   354       );
       
   355 
       
   356       $(
       
   357         '.Ldt-Quiz-Votes-Buttons input[type="button"], .Ldt-Quiz-Votes-Buttons a'
       
   358       ).click({ media: this.media }, function (event) {
       
   359         var vote_prop, vote_val;
       
   360 
       
   361         if ($(this).hasClass("Ldt-Quiz-Vote-Useful")) {
       
   362           vote_prop = "useful";
       
   363           vote_val = 1;
       
   364         } else if ($(this).hasClass("Ldt-Quiz-Vote-Useless")) {
       
   365           vote_prop = "useless";
       
   366           vote_val = -1;
       
   367 
       
   368           $(".Ldt-Ctrl-Quiz-Create")
       
   369             .addClass("button_highlight")
       
   370             .delay(5000)
       
   371             .queue(function () {
       
   372               $(this).removeClass("button_highlight").dequeue();
       
   373             });
       
   374         } else {
       
   375           vote_prop = "skipped_vote";
       
   376           vote_val = 0;
       
   377         }
       
   378 
       
   379         _this.submit(
       
   380           _this.user,
       
   381           _this.userid,
       
   382           _this.annotation.id,
       
   383           vote_prop,
       
   384           vote_val
       
   385         );
       
   386 
       
   387         //Resume the current video
       
   388         event.data.media.play();
       
   389 
       
   390         _this.hide();
       
   391         $(".Ldt-Pause-Add-Question").hide();
       
   392 
       
   393         _this.player.trigger("QuizCreator.skip");
       
   394       });
       
   395 
       
   396       _this.refresh();
       
   397     }
       
   398   };
   188 };
   399 };
   189 
   400 
   190 IriSP.Widgets.Quiz.prototype.globalScore = function() {
   401 const UniqueChoiceQuestion = function (ns) {
   191     // Return 2 variables to know how many right and wrong answers there are
   402   return class extends ns.Widgets.Widget {
   192     var values = _.values(this.correct);
   403     constructor(annotation) {
   193     var ok = values.filter( function (s) { return s == 1; }).length;
   404       this.annotation = annotation;
   194     var not_ok = values.filter( function (s) { return s == 0; }).length;
   405     }
   195 	return [ok, not_ok];
   406 
       
   407     renderQuizTemplate(answer, identifier) {
       
   408       return (
       
   409         '<input type="radio" class="quiz-question Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-' +
       
   410         identifier +
       
   411         '" name="question" data-question="' +
       
   412         identifier +
       
   413         '" value="' +
       
   414         identifier +
       
   415         '" />'
       
   416       );
       
   417     }
       
   418 
       
   419     renderTemplate(answer, identifier) {
       
   420       var id = this.generateUid();
       
   421       return (
       
   422         '<input type="radio" id="' +
       
   423         id +
       
   424         '" class="quiz-question-edition Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-' +
       
   425         identifier +
       
   426         '" name="question" data-question="' +
       
   427         identifier +
       
   428         '" value="' +
       
   429         identifier +
       
   430         '" /><label for="' +
       
   431         id +
       
   432         '" title="Veuillez sélectionner la réponse correcte"></label>'
       
   433       );
       
   434     }
       
   435 
       
   436     renderFullTemplate(answer, identifier) {
       
   437       var correct = answer && answer.correct ? "checked" : "";
       
   438       var id = this.generateUid();
       
   439       return (
       
   440         '<input type="radio" id="' +
       
   441         id +
       
   442         '" ' +
       
   443         correct +
       
   444         ' class="quiz-question-edition Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-' +
       
   445         identifier +
       
   446         '" name="question" data-question="' +
       
   447         identifier +
       
   448         '" value="' +
       
   449         identifier +
       
   450         '" /><label for="' +
       
   451         id +
       
   452         '"></label>'
       
   453       );
       
   454     }
       
   455   };
   196 };
   456 };
   197 
   457 
   198 IriSP.Widgets.Quiz.prototype.refresh = function() {
   458 const MultipleChoiceQuestion = function (ns) {
   199     var _annotations = this.getWidgetAnnotations().sortBy(function(_annotation) {
   459   return class extends ns.Widgets.Widget {
   200         return _annotation.begin;
   460     constructor(annotation) {
   201     });
   461       this.annotation = annotation;
   202 
   462     }
   203     var _this = this;
   463 
   204 
   464     renderQuizTemplate(answer, identifier) {
   205 	_this.totalAmount = _annotations.length;
   465       return (
   206 	_this.number = 0;
   466         '<input type="checkbox" class="quiz-question Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-' +
   207 	_this.correct = {};
   467         identifier +
   208 	_this.keys = {};
   468         '" name="question[' +
   209 
   469         identifier +
   210     _annotations.forEach(function(_a) {
   470         ']" data-question="' +
   211 		//Fix each annotation as "non-answered yet"
   471         identifier +
   212 		_this.correct[_a.id] = -1;
   472         '" value="' +
   213 		_this.keys[_this.number] = _a.id;
   473         identifier +
   214 		_a.number = _this.number++;
   474         '" /> '
   215     });
   475       );
   216 
   476     }
   217 }
   477 
   218 
   478     renderTemplate(answer, identifier) {
   219 IriSP.Widgets.Quiz.prototype.draw = function() {
   479       var id = this.generateUid();
   220 	var _this = this;
   480       return (
   221 	_this.quiz_displayed = false;
   481         '<input type="checkbox" id="' +
   222     this.onMediaEvent("enter-annotation", function (annotation) {
   482         id +
   223         var an = _this.getWidgetAnnotations().filter( function (a) { return a === annotation; });
   483         '" class="quiz-question-edition Ldt-Quiz-Question-Check" name="question[' +
   224         if (an.number === undefined) {
   484         identifier +
   225             _this.refresh();
   485         ']" data-question="' +
   226         }
   486         identifier +
   227         if (an.length) {
   487         '" value="' +
   228             _this.update(an[0]);
   488         identifier +
       
   489         '" /><label for="' +
       
   490         id +
       
   491         '" title="Veuillez sélectionner la ou les réponses correctes"></label>'
       
   492       );
       
   493     }
       
   494 
       
   495     renderFullTemplate(answer, identifier) {
       
   496       var correct = answer && answer.correct ? "checked" : "";
       
   497       var id = this.generateUid();
       
   498       return (
       
   499         '<input type="checkbox" id="' +
       
   500         id +
       
   501         '" ' +
       
   502         correct +
       
   503         ' class="quiz-question-edition Ldt-Quiz-Question-Check" name="question[' +
       
   504         identifier +
       
   505         ']" data-question="' +
       
   506         identifier +
       
   507         '" value="' +
       
   508         identifier +
       
   509         '" /><label for="' +
       
   510         id +
       
   511         '"></label> '
       
   512       );
       
   513     }
       
   514 
       
   515     submit(user, user_id, question, prop, val) {
       
   516       var _this = this;
       
   517       var _url = Mustache.render(this.analytics_api, {
       
   518           id: this.source.projectId,
       
   519         }),
       
   520         donnees = {
       
   521           username: user,
       
   522           useruuid: user_id,
       
   523           subject: question,
       
   524           property: prop,
       
   525           value: val,
       
   526           session: _this.session_id,
   229         };
   527         };
   230     });
   528 
   231     this.onMdpEvent("Quiz.activate", function() {
   529       jQuery.ajax({
   232 		_this.quiz_activated = true;
       
   233     });
       
   234 
       
   235     this.onMdpEvent("Quiz.deactivate", function() {
       
   236 		_this.quiz_activated = false;
       
   237 		_this.hide();
       
   238     });
       
   239 
       
   240     this.onMdpEvent("Quiz.hide", function() {
       
   241 		_this.hide();
       
   242     });
       
   243 
       
   244     this.onMdpEvent("Quiz.refresh", function() {
       
   245 		_this.refresh();
       
   246     });
       
   247 
       
   248     this.onMediaEvent("pause", function() {
       
   249 		if (! _this.quiz_displayed) {
       
   250 		    $(".Ldt-Pause-Add-Question").show();
       
   251         }
       
   252     });
       
   253 
       
   254     this.onMediaEvent("play", function() {
       
   255 	   $(".Ldt-Pause-Add-Question").hide();
       
   256     });
       
   257 
       
   258     // Add Ldt-Quiz-Overlay widget on top of video player
       
   259 	_this.overlay = $("<div class='Ldt-Quiz-Overlay'></div>").appendTo($('#' + _this.container));
       
   260 	_this.PauseAddQuestion = $("<div class='Ldt-Pause-Add-Question' title='Ajoutez une question !'>")
       
   261         .on("click", function() { _this.player.trigger("QuizCreator.create"); })
       
   262         .appendTo($('#' + _this.container));
       
   263 	_this.overlay.html(this.template);
       
   264 
       
   265 	$(".Ldt-Quiz-Overlay").hide();
       
   266 
       
   267     $(".Ldt-Quiz-Submit input").click(function() {
       
   268 		_this.answer();
       
   269     });
       
   270 
       
   271 	//In case we click on the first "Skip" link
       
   272 	$(".Ldt-Quiz-Submit-Skip-Link").click({ media: this.media }, function(event) {
       
   273 		_this.submit(_this.user, _this.userid, _this.annotation.id, "skipped_answer", 0);
       
   274 		_this.hide();
       
   275 		_this.player.trigger("QuizCreator.skip");
       
   276 		event.data.media.play();
       
   277 	});
       
   278 
       
   279     $(".Ldt-Quiz-Votes-Buttons input[type=\"button\"], .Ldt-Quiz-Votes-Buttons a").click({media: this.media}, function(event) {
       
   280 		var vote_prop, vote_val;
       
   281 
       
   282 		if ($(this).hasClass("Ldt-Quiz-Vote-Useful")) {
       
   283 			vote_prop = "useful";
       
   284 			vote_val = 1;
       
   285 		} else if ($(this).hasClass("Ldt-Quiz-Vote-Useless")) {
       
   286 			vote_prop = "useless";
       
   287 			vote_val = -1;
       
   288 
       
   289 			$(".Ldt-Ctrl-Quiz-Create").addClass("button_highlight").delay(5000).queue(function() {
       
   290                 $(this).removeClass("button_highlight").dequeue();
       
   291             });
       
   292 		}else{
       
   293 			vote_prop = "skipped_vote";
       
   294 			vote_val = 0;
       
   295 		}
       
   296 
       
   297 		_this.submit(_this.user, _this.userid, _this.annotation.id, vote_prop, vote_val);
       
   298 
       
   299 		//Resume the current video
       
   300 		event.data.media.play();
       
   301 
       
   302 		_this.hide();
       
   303 		$(".Ldt-Pause-Add-Question").hide();
       
   304 
       
   305 		_this.player.trigger("QuizCreator.skip");
       
   306 	});
       
   307 
       
   308     _this.refresh();
       
   309 };
       
   310 
       
   311 //Generates uid
       
   312 //source : http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
       
   313 IriSP.Widgets.Widget.prototype.generateUid = function () {
       
   314     return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
       
   315         var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
       
   316         return v.toString(16);
       
   317     });
       
   318 }
       
   319 
       
   320 //UniqueChoice Question
       
   321 IriSP.Widgets.UniqueChoiceQuestion = function(annotation) {
       
   322     this.annotation = annotation;
       
   323 }
       
   324 
       
   325 IriSP.Widgets.UniqueChoiceQuestion.prototype = new IriSP.Widgets.Widget();
       
   326 
       
   327 IriSP.Widgets.UniqueChoiceQuestion.prototype.renderQuizTemplate = function(answer, identifier) {
       
   328 	return '<input type="radio" class="quiz-question Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-' + identifier + '" name="question" data-question="' + identifier + '" value="' + identifier + '" />';
       
   329 }
       
   330 
       
   331 IriSP.Widgets.UniqueChoiceQuestion.prototype.renderTemplate = function(answer, identifier) {
       
   332 	var id = this.generateUid();
       
   333 	return '<input type="radio" id="' + id + '" class="quiz-question-edition Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-'+ identifier +'" name="question" data-question="'+ identifier +'" value="' + identifier + '" /><label for="'+ id +'" title="Veuillez sélectionner la réponse correcte"></label>';
       
   334 }
       
   335 
       
   336 IriSP.Widgets.UniqueChoiceQuestion.prototype.renderFullTemplate = function(answer, identifier) {
       
   337 	var correct = (answer && answer.correct) ? "checked" : "";
       
   338 	var id = this.generateUid();
       
   339 	return '<input type="radio" id="'+ id +'" '+ correct +' class="quiz-question-edition Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-'+ identifier +'" name="question" data-question="'+ identifier +'" value="' + identifier + '" /><label for="'+ id +'"></label>';
       
   340 }
       
   341 
       
   342 
       
   343 //MultipleChoice Question
       
   344 IriSP.Widgets.MultipleChoiceQuestion = function(annotation) {
       
   345     this.annotation = annotation;
       
   346 }
       
   347 
       
   348 IriSP.Widgets.MultipleChoiceQuestion.prototype = new IriSP.Widgets.Widget();
       
   349 
       
   350 IriSP.Widgets.MultipleChoiceQuestion.prototype.renderQuizTemplate = function(answer, identifier) {
       
   351 	return '<input type="checkbox" class="quiz-question Ldt-Quiz-Question-Check Ldt-Quiz-Question-Check-'+ identifier + '" name="question['+ identifier +']" data-question="'+ identifier +'" value="' + identifier + '" /> ';
       
   352 }
       
   353 
       
   354 IriSP.Widgets.MultipleChoiceQuestion.prototype.renderTemplate = function(answer, identifier) {
       
   355 	var id = this.generateUid();
       
   356 	return '<input type="checkbox" id="'+ id +'" class="quiz-question-edition Ldt-Quiz-Question-Check" name="question['+ identifier +']" data-question="'+ identifier +'" value="' + identifier + '" /><label for="'+ id +'" title="Veuillez sélectionner la ou les réponses correctes"></label>';
       
   357 }
       
   358 
       
   359 IriSP.Widgets.MultipleChoiceQuestion.prototype.renderFullTemplate = function(answer, identifier) {
       
   360 	var correct = (answer && answer.correct) ? "checked" : "";
       
   361 	var id = this.generateUid();
       
   362 	return '<input type="checkbox" id="'+ id +'" '+ correct +' class="quiz-question-edition Ldt-Quiz-Question-Check" name="question['+ identifier +']" data-question="'+ identifier +'" value="' + identifier + '" /><label for="'+ id +'"></label> ';
       
   363 }
       
   364 
       
   365 IriSP.Widgets.Quiz.prototype.submit = function(user,user_id,question,prop,val) {
       
   366     var _this = this;
       
   367 	var _url = Mustache.to_html(this.analytics_api, {id: this.source.projectId}),
       
   368 	donnees = {
       
   369 			"username": user,
       
   370 			"useruuid": user_id,
       
   371 			"subject": question,
       
   372 			"property": prop,
       
   373 		    "value": val,
       
   374             "session": _this.session_id
       
   375 		};
       
   376 
       
   377 	IriSP.jQuery.ajax({
       
   378         url: _url,
   530         url: _url,
   379         type: this.api_method,
   531         type: this.api_method,
   380         contentType: 'application/json',
   532         contentType: "application/json",
   381         data: JSON.stringify(donnees),
   533         data: JSON.stringify(donnees),
   382         success: function(_data) {
   534         success: function (_data) {},
       
   535         error: function (_xhr, _error, _thrown) {
       
   536           ns.log("Error when sending annotation", _thrown);
   383         },
   537         },
   384         error: function(_xhr, _error, _thrown) {
   538       });
   385             IriSP.log("Error when sending annotation", _thrown);
   539     }
   386         }
   540   };
   387     });
   541 };
   388 }
   542 
       
   543 export { Quiz, UniqueChoiceQuestion, MultipleChoiceQuestion, quizStyles };