|
1068
|
1 |
/* TODO: Add Social Network Sharing */ |
|
|
2 |
|
|
|
3 |
IriSP.Widgets.QuizCreator = function(player, config) { |
|
|
4 |
var _this = this; |
|
|
5 |
IriSP.Widgets.Widget.call(this, player, config); |
|
|
6 |
}; |
|
|
7 |
|
|
|
8 |
IriSP.Widgets.QuizCreator.prototype = new IriSP.Widgets.Widget(); |
|
|
9 |
|
|
|
10 |
IriSP.Widgets.QuizCreator.prototype.defaults = { |
|
|
11 |
creator_name : "", |
|
|
12 |
tags : false, |
|
|
13 |
tag_titles : false, |
|
|
14 |
pause_on_write : true, |
|
|
15 |
annotation_type: "Quiz", |
|
|
16 |
api_serializer: "ldt_annotate", |
|
|
17 |
api_endpoint_template: "", |
|
|
18 |
api_method: "POST" |
|
|
19 |
}; |
|
|
20 |
|
|
|
21 |
IriSP.Widgets.QuizCreator.prototype.messages = { |
|
|
22 |
en: { |
|
|
23 |
}, |
|
|
24 |
fr: { |
|
|
25 |
} |
|
|
26 |
}; |
|
|
27 |
|
|
|
28 |
IriSP.Widgets.QuizCreator.prototype.template = |
|
|
29 |
'<div class="Ldt-QuizCreator-Ui Ldt-TraceMe">' |
|
|
30 |
+ '<div class="Ldt-QuizCreator-Question-Form">' |
|
|
31 |
+ '<textarea class="Ldt-QuizCreator-Question-Area" placeholder="Votre question"></textarea><br />' |
|
|
32 |
+ '<textarea class="Ldt-QuizCreator-Resource-Area" placeholder="Ressources (lien vers une image, etc.)"></textarea><br />' |
|
|
33 |
+ '</div>' |
|
|
34 |
+ '<p>Type de question ' |
|
|
35 |
+ '<select name="type" class="Ldt-QuizCreator-Question-Type">' |
|
|
36 |
+ '<option value="unique_choice">Choix unique</option>' |
|
|
37 |
+ '<option value="multiple_choice">Choix multiple</option>' |
|
|
38 |
+ '</select>' |
|
|
39 |
+ ' à <input type="text" placeholder="hh:mm:ss" size="6" class="Ldt-QuizCreator-Time" />' |
|
|
40 |
+ '<div class="Ldt-QuizCreator-Questions-Block">' |
|
|
41 |
+ '</div>' |
|
|
42 |
+ '<div>' |
|
|
43 |
+ ' <button class="Ldt-QuizCreator-Question-Add">Ajouter une réponse</button><hr>' |
|
|
44 |
+ ' <button class="Ldt-QuizCreator-Question-Save">Sauvegarder</button>' |
|
|
45 |
+ '</div>' |
|
|
46 |
+ '</div>'; |
|
|
47 |
|
|
|
48 |
/* Hide and clear the interface is case of someone skipped or answer the current question in the Quiz panel*/ |
|
|
49 |
IriSP.Widgets.QuizCreator.prototype.skip = function() { |
|
|
50 |
this.$.find(".Ldt-QuizCreator-Time").val(""); |
|
|
51 |
this.$.find(".Ldt-QuizCreator-Question-Area").val(""); |
|
|
52 |
this.$.find(".Ldt-QuizCreator-Resource-Area").val(""); |
|
|
53 |
this.$.find(".Ldt-QuizCreator-Questions-Block").html(""); |
|
|
54 |
this.current_annotation = undefined; |
|
|
55 |
}; |
|
|
56 |
|
|
|
57 |
IriSP.Widgets.QuizCreator.prototype.nbAnswers = function(){ |
|
|
58 |
var numItems = this.$.find('.Ldt-QuizCreator-Questions-Answer').length; |
|
|
59 |
return numItems; |
|
|
60 |
}; |
|
|
61 |
|
|
|
62 |
IriSP.Widgets.QuizCreator.prototype.draw = function() { |
|
|
63 |
var _this = this; |
|
|
64 |
|
|
|
65 |
this.onMediaEvent("timeupdate", function(_time) { |
|
|
66 |
_this.setBegin(_time); |
|
|
67 |
}); |
|
|
68 |
|
|
|
69 |
this.onMdpEvent("QuizCreator.show", function() { |
|
|
70 |
_this.setBegin(_this.media.currentTime); |
|
|
71 |
}); |
|
|
72 |
|
|
|
73 |
this.onMdpEvent("QuizCreator.create", function() { |
|
|
74 |
_this.skip(); |
|
|
75 |
_this.setBegin(_this.media.currentTime); |
|
|
76 |
}); |
|
|
77 |
|
|
|
78 |
this.onMdpEvent("QuizCreator.skip", function() { |
|
|
79 |
_this.skip(); |
|
|
80 |
}); |
|
|
81 |
|
|
|
82 |
this.onMdpEvent("QuizCreator.edit", function (_annotation) { |
|
|
83 |
_this.skip(); |
|
|
84 |
_this.addQuestion(_annotation); |
|
|
85 |
}); |
|
|
86 |
|
|
|
87 |
this.$.on("click", ".Ldt-QuizCreator-Remove", function() { |
|
|
88 |
$(this).parents(".Ldt-QuizCreator-Questions-Answer").remove(); |
|
|
89 |
}); |
|
|
90 |
|
|
|
91 |
this.begin = new IriSP.Model.Time(); |
|
|
92 |
this.end = this.source.getDuration(); |
|
|
93 |
this.answers = []; |
|
|
94 |
|
|
|
95 |
this.renderTemplate(); |
|
|
96 |
|
|
|
97 |
/* Quiz creator */ |
|
|
98 |
|
|
|
99 |
this.question = new IriSP.Widgets.UniqueChoiceQuestion(); |
|
|
100 |
|
|
|
101 |
this.$.find(".Ldt-QuizCreator-Question-Type").bind("change", this.functionWrapper("onQuestionTypeChange")); |
|
|
102 |
this.$.find(".Ldt-QuizCreator-Question-Add").bind("click", this.functionWrapper("onQuestionAdd")); |
|
|
103 |
this.$.find(".Ldt-QuizCreator-Question-Save").bind("click", this.functionWrapper("onSave")); |
|
|
104 |
|
|
|
105 |
this.$.find(".Ldt-QuizCreator-Time").keyup(function() { |
|
|
106 |
var str = _this.$.find(".Ldt-QuizCreator-Time").val(); |
|
|
107 |
_this.begin = IriSP.timestamp2ms(str); |
|
|
108 |
_this.end = _this.begin + 1000; |
|
|
109 |
}); |
|
|
110 |
|
|
|
111 |
this.onMediaEvent("timeupdate", function(_time) { |
|
|
112 |
// Do not update timecode if description is not empty |
|
|
113 |
if (_this.getDescription()) { |
|
|
114 |
_this.setBegin(_time); |
|
|
115 |
}; |
|
|
116 |
}); |
|
|
117 |
}; |
|
|
118 |
|
|
|
119 |
IriSP.Widgets.QuizCreator.prototype.getDescription = function() { |
|
|
120 |
return this.$.find(".Ldt-QuizCreator-Question-Area").val().trim(); |
|
|
121 |
}; |
|
|
122 |
|
|
|
123 |
IriSP.Widgets.QuizCreator.prototype.addQuestion = function(annotation, number) { |
|
|
124 |
var _this = this; |
|
|
125 |
|
|
|
126 |
if (annotation.content.data.type == "multiple_choice") { |
|
|
127 |
this.question = new IriSP.Widgets.MultipleChoiceQuestion(annotation); |
|
|
128 |
} |
|
|
129 |
else if (annotation.content.data.type == "unique_choice") { |
|
|
130 |
this.question = new IriSP.Widgets.UniqueChoiceQuestion(annotation); |
|
|
131 |
} |
|
|
132 |
|
|
|
133 |
var answers = annotation.content.data.answers; |
|
|
134 |
|
|
|
135 |
this.answers = []; |
|
|
136 |
|
|
|
137 |
|
|
|
138 |
this.$.find(".Ldt-QuizCreator-Time").val(annotation.begin); |
|
|
139 |
this.$.find(".Ldt-QuizCreator-Question-Area").val(annotation.content.data.question); |
|
|
140 |
this.$.find(".Ldt-QuizCreator-Resource-Area").val(annotation.content.data.resource); |
|
|
141 |
this.$.find(".Ldt-QuizCreator-Questions-Block").html(''); |
|
|
142 |
answers.forEach( function (ans) { |
|
|
143 |
_this.onQuestionAdd(null, ans); |
|
|
144 |
}); |
|
|
145 |
_this.current_annotation = annotation; |
|
|
146 |
}; |
|
|
147 |
|
|
|
148 |
IriSP.Widgets.QuizCreator.prototype.onQuestionTypeChange = function(e) { |
|
|
149 |
|
|
|
150 |
var _field = this.$.find(".Ldt-QuizCreator-Question-Type"); |
|
|
151 |
var _contents = _field.val(); |
|
|
152 |
|
|
|
153 |
var _this = this; |
|
|
154 |
switch(_contents) { |
|
|
155 |
case "unique_choice": |
|
|
156 |
this.question = new IriSP.Widgets.UniqueChoiceQuestion(); |
|
|
157 |
break; |
|
|
158 |
|
|
|
159 |
case "multiple_choice": |
|
|
160 |
this.question = new IriSP.Widgets.MultipleChoiceQuestion(); |
|
|
161 |
break; |
|
|
162 |
} |
|
|
163 |
|
|
|
164 |
var output = ""; |
|
|
165 |
|
|
|
166 |
_this.$.find(".Ldt-QuizCreator-Questions-Block").html(output); |
|
|
167 |
|
|
|
168 |
this.pauseOnWrite(); |
|
|
169 |
}; |
|
|
170 |
|
|
|
171 |
// Either e !== undefined, then it has been called by the interface and answer === undefined, generate an empty form. |
|
|
172 |
// Or e === null && answer !== undefined, an existing answer is provided. |
|
|
173 |
IriSP.Widgets.QuizCreator.prototype.onQuestionAdd = function(e, answer) { |
|
|
174 |
var output = '<div class="Ldt-QuizCreator-Questions-Answer">' |
|
|
175 |
+ 'Réponse <div class="Ldt-QuizCreator-Questions-Answer-Correct">'+ this.question.renderFullTemplate(answer, this.nbAnswers()) +'</div><br />' |
|
|
176 |
+ '<div class="Ldt-QuizCreator-Questions-Answer-Content">' |
|
|
177 |
+ '<input type="text" class="Ldt-QuizCreator-Answer-Content" data-question="'+ this.nbAnswers() +'" id="question'+ this.nbAnswers() + '"' + (answer ? ' value="'+ answer.content + '"' : "") + '/><br />' |
|
|
178 |
+ 'Commentaire <br/><textarea class="Ldt-QuizCreator-Answer-Feedback" data-question="'+ this.nbAnswers() +'" id="feedback'+ this.nbAnswers() +'">' + (answer ? answer.feedback : "") + '</textarea>' |
|
|
179 |
+ '</div>' |
|
|
180 |
+ '<div class="Ldt-QuizCreator-Questions-Answer-Delete"><div class="Ldt-QuizCreator-Remove"> </div></div>' |
|
|
181 |
+ '</div>'; |
|
|
182 |
this.$.find(".Ldt-QuizCreator-Questions-Block").append(output); |
|
|
183 |
this.$.find(".Ldt-QuizCreator-Answer-Content").last().focus(); |
|
|
184 |
|
|
|
185 |
this.pauseOnWrite(); |
|
|
186 |
}; |
|
|
187 |
|
|
|
188 |
IriSP.Widgets.QuizCreator.prototype.pauseOnWrite = function() { |
|
|
189 |
if (this.pause_on_write && !this.media.getPaused()) { |
|
|
190 |
this.media.pause(); |
|
|
191 |
} |
|
|
192 |
}; |
|
|
193 |
|
|
|
194 |
IriSP.Widgets.QuizCreator.prototype.setBegin = function (t) { |
|
|
195 |
this.begin = new IriSP.Model.Time(t || 0); |
|
|
196 |
this.end = this.begin + 500; |
|
|
197 |
this.$.find(".Ldt-QuizCreator-Time").val(this.begin.toString()); |
|
|
198 |
}; |
|
|
199 |
|
|
|
200 |
IriSP.Widgets.QuizCreator.prototype.get_local_annotation = function (ident) { |
|
|
201 |
return this.player.getLocalAnnotation(ident); |
|
|
202 |
}; |
|
|
203 |
|
|
|
204 |
IriSP.Widgets.QuizCreator.prototype.save_local_annotations = function() { |
|
|
205 |
this.player.saveLocalAnnotations(); |
|
|
206 |
// Merge modifications into widget source |
|
|
207 |
this.source.merge(this.player.localSource); |
|
|
208 |
}; |
|
|
209 |
|
|
|
210 |
IriSP.Widgets.QuizCreator.prototype.delete_local_annotation = function(ident) { |
|
|
211 |
this.source.getAnnotations().removeId(ident); |
|
|
212 |
this.player.deleteLocalAnnotation(ident); |
|
|
213 |
this.current_annotation = undefined; |
|
|
214 |
this.refresh(true); |
|
|
215 |
}; |
|
|
216 |
|
|
|
217 |
IriSP.Widgets.QuizCreator.prototype.show = function() { |
|
|
218 |
this.$.find(".Ldt-QuizCreator-Question-Area").focus(); |
|
|
219 |
}; |
|
|
220 |
|
|
|
221 |
IriSP.Widgets.QuizCreator.prototype.hide = function() { |
|
|
222 |
this.$.find(".Ldt-QuizCreator-Questions-Block").html(""); |
|
|
223 |
this.$.find(".Ldt-QuizCreator-Question-Area").val(""); |
|
|
224 |
this.$.find(".Ldt-QuizCreator-Resource-Area").val(""); |
|
|
225 |
this.$.find(".Ldt-QuizCreator-Time").val(""); |
|
|
226 |
}; |
|
|
227 |
|
|
|
228 |
/* Save a local annotation */ |
|
|
229 |
IriSP.Widgets.QuizCreator.prototype.onSave = function(event, should_publish) { |
|
|
230 |
// Either the annotation already exists (then we overwrite its |
|
|
231 |
// content) or it must be created. |
|
|
232 |
var is_created = false; |
|
|
233 |
|
|
|
234 |
if (this.nbAnswers() <= 0) { |
|
|
235 |
alert("Vous devez spécifier au moins une réponse à votre question !"); |
|
|
236 |
return false; |
|
|
237 |
}; |
|
|
238 |
// Check that there is at least 1 valid answer |
|
|
239 |
if (! this.$.find(".quiz-question-edition:checked").length) { |
|
|
240 |
alert("Vous n'avez pas indiqué de bonne réponse."); |
|
|
241 |
return false; |
|
|
242 |
}; |
|
|
243 |
var _annotation; |
|
|
244 |
if (this.current_annotation) { |
|
|
245 |
is_created = false; |
|
|
246 |
_annotation = this.current_annotation; |
|
|
247 |
} else { |
|
|
248 |
is_created = true; |
|
|
249 |
var _annotationTypes = this.source.getAnnotationTypes().searchByTitle(this.annotation_type, true), /* Récupération du type d'annotation dans lequel l'annotation doit être ajoutée */ |
|
|
250 |
_annotationType = (_annotationTypes.length ? _annotationTypes[0] : new IriSP.Model.AnnotationType(false, this.player.localSource)); /* Si le Type d'Annotation n'existe pas, il est créé à la volée */ |
|
|
251 |
|
|
|
252 |
/* Si nous avons dû générer un ID d'annotationType à la volée... */ |
|
|
253 |
if (!_annotationTypes.length) { |
|
|
254 |
/* Il ne faudra pas envoyer l'ID généré au serveur */ |
|
|
255 |
_annotationType.dont_send_id = true; |
|
|
256 |
/* Il faut inclure le titre dans le type d'annotation */ |
|
|
257 |
_annotationType.title = this.annotation_type; |
|
|
258 |
} |
|
|
259 |
|
|
|
260 |
_annotation = new IriSP.Model.Annotation(false, this.player.localSource); /* Création d'une annotation dans cette source avec un ID généré à la volée (param. false) */ |
|
|
261 |
|
|
|
262 |
// Initialize some fields in case of creation |
|
|
263 |
_annotation.created = new Date(); /* Date de création de l'annotation */ |
|
|
264 |
_annotation.creator = this.creator_name; |
|
|
265 |
_annotation.setAnnotationType(_annotationType.id); /* Id du type d'annotation */ |
|
|
266 |
this.player.localSource.getMedias().push(this.source.currentMedia); |
|
|
267 |
_annotation.setMedia(this.source.currentMedia.id); /* Id du média annoté */ |
|
|
268 |
} |
|
|
269 |
|
|
|
270 |
/* |
|
|
271 |
* Nous remplissons les données de l'annotation |
|
|
272 |
* */ |
|
|
273 |
_annotation.setBeginEnd(this.begin, this.end); |
|
|
274 |
_annotation.modified = new Date(); /* Date de modification de l'annotation */ |
|
|
275 |
_annotation.contributor = this.creator_name; |
|
|
276 |
_annotation.description = this.getDescription(); |
|
|
277 |
_annotation.title = _annotation.description; |
|
|
278 |
_annotation.content = {}; |
|
|
279 |
_annotation.content.data = {}; |
|
|
280 |
_annotation.content.data.type = this.$.find(".Ldt-QuizCreator-Question-Type").val(); |
|
|
281 |
_annotation.content.data.question = _annotation.description; |
|
|
282 |
_annotation.content.data.resource = this.$.find(".Ldt-QuizCreator-Resource-Area").val(); |
|
|
283 |
_annotation.content.data.answers = $.makeArray($(".Ldt-QuizCreator-Questions-Answer") |
|
|
284 |
.map(function (ans) |
|
|
285 |
{ |
|
|
286 |
return { |
|
|
287 |
content: $(this).find(".Ldt-QuizCreator-Answer-Content").val(), |
|
|
288 |
feedback: $(this).find(".Ldt-QuizCreator-Answer-Feedback").val(), |
|
|
289 |
correct: $(this).find(".Ldt-Quiz-Question-Check").is(':checked') |
|
|
290 |
}; |
|
|
291 |
})); |
|
|
292 |
this.current_annotation = _annotation; |
|
|
293 |
if (is_created) { |
|
|
294 |
// Add the annotation to the localSource |
|
|
295 |
this.player.addLocalAnnotation(_annotation); |
|
|
296 |
// Update also the remote source |
|
|
297 |
this.source.merge([ _annotation ]); |
|
|
298 |
this.player.trigger("Annotation.create", _annotation); |
|
|
299 |
} else { |
|
|
300 |
// Update the annotation |
|
|
301 |
this.player.saveLocalAnnotations(); |
|
|
302 |
this.player.trigger("Annotation.update", _annotation); |
|
|
303 |
}; |
|
|
304 |
this.player.trigger("AnnotationsList.update"); /* On force le rafraîchissement des widgets AnnotationsList */ |
|
|
305 |
this.player.trigger("Quiz.refresh"); /* On force le rafraîchissement des widgets Quiz */ |
|
|
306 |
}; |