|
1 |
|
2 IriSP.Widgets.Markers = function(player, config) { |
|
3 IriSP.Widgets.Widget.call(this, player, config); |
|
4 }; |
|
5 |
|
6 IriSP.Widgets.Markers.prototype = new IriSP.Widgets.Widget(); |
|
7 |
|
8 IriSP.Widgets.Markers.prototype.defaults = { |
|
9 annotation_type: "markers", |
|
10 line_height: 8, |
|
11 background: "#e0e0e0", |
|
12 marker_color: "#ff80fc", |
|
13 hover_color: "#e15581", |
|
14 selected_color: "#74d600", |
|
15 ball_radius: 4, |
|
16 pause_on_write: true, |
|
17 api_serializer: "ldt_annotate", |
|
18 api_endpoint_template: "", |
|
19 api_method_create: "POST", |
|
20 api_method_editing: "PUT", |
|
21 project_id: "", |
|
22 creator_name: "", |
|
23 after_send_timeout: 0, |
|
24 close_after_send: false, |
|
25 }; |
|
26 |
|
27 IriSP.Widgets.Markers.prototype.template = |
|
28 '<div class="Ldt-Markers-Display" style="height:{{line_height}}px;">' |
|
29 + '<div class="Ldt-Markers-List" style="height:{{line_height}}px; position: relative;"></div>' |
|
30 + '<div class="Ldt-Markers-Position"></div>' |
|
31 + '</div>' |
|
32 + '<div class="Ldt-Markers-Inputs">' |
|
33 + '<div class="Ldt-Markers-Screen Ldt-Markers-ScreenMain">' |
|
34 + '<div class="Ldt-Markers-Create">+</div>' |
|
35 + '<div class="Ldt-Markers-Info"></div>' |
|
36 + '</div>' |
|
37 + '<div class="Ldt-Markers-Screen Ldt-Markers-ScreenSending">' |
|
38 + '<div class="Ldt-Markers-Screen-InnerBox">{{l10n.wait_while_processing}}</div>' |
|
39 + '</div>' |
|
40 + '<div class="Ldt-Markers-Screen Ldt-Markers-ScreenSuccess">' |
|
41 + '<a title="{{l10n.close_widget}}" class="Ldt-Markers-Close" href="#"></a>' |
|
42 + '<div class="Ldt-Markers-Screen-InnerBox">{{l10n.annotation_saved}}</div>' |
|
43 + '</div>' |
|
44 + '<div class="Ldt-Markers-Screen Ldt-Markers-ScreenFailure">' |
|
45 + '<a title="{{l10n.close_widget}}" class="Ldt-Markers-Close" href="#"></a>' |
|
46 + '<div class="Ldt-Markers-Screen-InnerBox">{{l10n.error_while_contacting}}</div>' |
|
47 + '</div>' |
|
48 + '</div>'; |
|
49 |
|
50 |
|
51 IriSP.Widgets.Markers.prototype.markerTemplate = |
|
52 '<div class="Ldt-Markers-Marker" style="height:{{height}}px; left:{{left}}px; width: 2px; background-color: black;">' + |
|
53 '<div class="Ldt-Markers-MarkerBall" style="background-color: {{marker_color}}; position: relative; width: {{ball_diameter}}px; height: {{ball_diameter}}px; left: {{ball_left}}px; top: {{ball_top}}px; border: 1px solid; border-radius: {{ball_radius}}px"></div>' + |
|
54 '</div>'; |
|
55 |
|
56 IriSP.Widgets.Markers.prototype.infoTemplate = |
|
57 '{{^edit}}<div class="Ldt-Markers-MarkerDescription">{{marker_info}}</div>{{/edit}}' + |
|
58 '{{#edit}}<div class="Ldt-Markers-MarkerEdit">' + |
|
59 '<textarea class="Ldt-Markers-MarkerTextArea" cols="60" rows="4">{{marker_info}}</textarea>' + |
|
60 '<div class="Ldt-Markers-Buttons">' + |
|
61 '<div class="Ldt-Markers-MarkerSend">{{send}}</div>' + |
|
62 '<div class="Ldt-Markers-MarkerCancel">{{cancel}}</div>' + |
|
63 '</div>' + |
|
64 '</div>{{/edit}}' |
|
65 |
|
66 IriSP.Widgets.Markers.prototype.messages = { |
|
67 en : { |
|
68 send : "Send", |
|
69 cancel : "Cancel", |
|
70 wait_while_processing: "Please wait while your annotation is being processed...", |
|
71 error_while_contacting: "An error happened while contacting the server. Your annotation has not been saved.", |
|
72 annotation_saved: "Thank you, your annotation has been saved.", |
|
73 close_widget: "Close", |
|
74 }, |
|
75 fr : { |
|
76 send : "Envoyer", |
|
77 cancel : "Annuler", |
|
78 wait_while_processing: "Veuillez patienter pendant le traitement de votre annotation...", |
|
79 error_while_contacting: "Une erreur s'est produite en contactant le serveur. Votre annotation n'a pas été enregistrée.", |
|
80 annotation_saved: "Merci, votre annotation a été enregistrée.", |
|
81 close_widget: "Fermer", |
|
82 } |
|
83 } |
|
84 |
|
85 IriSP.Widgets.Markers.prototype.draw = function(){ |
|
86 var _this = this; |
|
87 |
|
88 this.renderTemplate(); |
|
89 |
|
90 this.markers = this.getWidgetAnnotations().filter(function(_ann) { |
|
91 return ((_ann.getDuration() == 0) || (_ann.begin == _ann.end)); |
|
92 }); |
|
93 this.drawMarkers(); |
|
94 |
|
95 this.$.find(".Ldt-Markers-Create").click(function(){ |
|
96 if (!_this.selectedMarker){ |
|
97 _this.toggleCreateMarker(); |
|
98 } |
|
99 else { |
|
100 _this.selectedMarker = false; |
|
101 _this.$.find(".Ldt-Markers-Info").html(""); |
|
102 _this.$.find(".Ldt-Markers-MarkerBall").css("background-color", _this.marker_color) |
|
103 _this.$.find(".Ldt-Markers-Create").html("+"); |
|
104 } |
|
105 }) |
|
106 this.$.find(".Ldt-Markers-Info").click(function(){ |
|
107 if (_this.selectedMarker&&!_this.editing){ |
|
108 _this.toggleCreateMarker(); |
|
109 } |
|
110 }) |
|
111 this.showScreen("Main"); |
|
112 this.$.css({ |
|
113 margin: "1px 0", |
|
114 height: this.line_height, |
|
115 background: this.background |
|
116 }); |
|
117 |
|
118 this.$.find(".Ldt-Markers-Close").click(function() { |
|
119 _this.showScreen("Main"); |
|
120 }); |
|
121 |
|
122 this.onMediaEvent("timeupdate", "updatePosition"); |
|
123 this.onMdpEvent("Markers.refresh", this.functionWrapper("drawMarkers")); |
|
124 |
|
125 this.editing = false; |
|
126 this.selectedMarker = false; |
|
127 } |
|
128 |
|
129 |
|
130 IriSP.Widgets.Markers.prototype.updatePosition = function(_time) { |
|
131 var _x = Math.floor( this.width * _time / this.media.duration); |
|
132 this.$.find('.Ldt-Markers-Position').css({ |
|
133 left: _x + "px" |
|
134 }); |
|
135 }; |
|
136 |
|
137 |
|
138 IriSP.Widgets.Markers.prototype.toggleCreateMarker = function(){ |
|
139 if(!this.editing){ |
|
140 this.editing = true |
|
141 } |
|
142 else { |
|
143 this.editing = false |
|
144 } |
|
145 var _divHtml = ""; |
|
146 if (this.selectedMarker){ |
|
147 _divHtml = Mustache.to_html(this.infoTemplate, { |
|
148 edit: this.editing, |
|
149 marker_info: this.selectedMarker.description, |
|
150 send: this.l10n.send, |
|
151 cancel: this.l10n.cancel |
|
152 }) |
|
153 |
|
154 this.$.find(".Ldt-Markers-Info").html(_divHtml); |
|
155 } |
|
156 else { |
|
157 if (this.editing) { |
|
158 _divHtml = Mustache.to_html(this.infoTemplate, { |
|
159 edit: this.editing, |
|
160 marker_info: "", |
|
161 send: this.l10n.send, |
|
162 cancel: this.l10n.cancel, |
|
163 }) |
|
164 } |
|
165 this.$.find(".Ldt-Markers-Info").html(_divHtml); |
|
166 } |
|
167 |
|
168 if(this.editing){ |
|
169 this.$.find(".Ldt-Markers-MarkerSend").click(this.functionWrapper("onSubmit")); |
|
170 this.$.find(".Ldt-Markers-MarkerCancel").click(this.functionWrapper("toggleCreateMarker")); |
|
171 this.$.find(".Ldt-Markers-MarkerTextArea").bind("change keyup input paste", this.functionWrapper("onDescriptionChange")); |
|
172 this.$.find(".Ldt-Markers-Create").html("-"); |
|
173 } |
|
174 else { |
|
175 this.$.find(".Ldt-Markers-Create").html("+"); |
|
176 } |
|
177 }; |
|
178 |
|
179 IriSP.Widgets.Markers.prototype.onDescriptionChange = function(){ |
|
180 var _field = this.$.find(".Ldt-Markers-MarkerTextArea"), |
|
181 _contents = _field.val(); |
|
182 _field.css("border-color", !!_contents ? "#e87d9f" : "#ff0000"); |
|
183 if (!!_contents) { |
|
184 _field.removeClass("empty"); |
|
185 } else { |
|
186 _field.addClass("empty"); |
|
187 } |
|
188 this.pauseOnWrite(); |
|
189 return !!_contents; |
|
190 }; |
|
191 |
|
192 IriSP.Widgets.Markers.prototype.pauseOnWrite = function(){ |
|
193 if (this.pause_on_write && !this.media.getPaused()) { |
|
194 this.media.pause(); |
|
195 } |
|
196 }; |
|
197 |
|
198 IriSP.Widgets.Markers.prototype.showScreen = function(_screenName) { |
|
199 this.$.find('.Ldt-Markers-Screen' + _screenName).show() |
|
200 .siblings().hide(); |
|
201 if ((_screenName=="Main")&&(this.editing)){ |
|
202 this.toggleCreateMarker(); |
|
203 }; |
|
204 } |
|
205 |
|
206 IriSP.Widgets.Markers.prototype.drawMarkers = function(){ |
|
207 this.$.remove("Ldt-Markers-Marker"); |
|
208 var _this = this, |
|
209 _scale = this.width / this.source.getDuration(), |
|
210 list_$ = this.$.find('.Ldt-Markers-List'); |
|
211 |
|
212 this.markers.forEach(function(_marker){ |
|
213 var _left = _marker.begin * _scale -1; |
|
214 _data = { |
|
215 left: _left, |
|
216 height: _this.line_height-1, |
|
217 ball_top: (_this.ball_radius*2 > _this.line_height) ? 0 : ((_this.line_height - _this.ball_radius*2)/2)-1, |
|
218 ball_radius: (_this.ball_radius*2 > _this.line_height) ? _this.line_height/2 : _this.ball_radius, |
|
219 ball_diameter: (_this.ball_radius*2 > _this.line_height) ? _this.line_height/2 : _this.ball_radius*2, |
|
220 ball_left: -_this.ball_radius, |
|
221 marker_color: ((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))? _this.selected_color : _this.marker_color |
|
222 } |
|
223 var _html = Mustache.to_html(_this.markerTemplate, _data), |
|
224 _el = IriSP.jQuery(_html); |
|
225 _el.mouseover(function(){ |
|
226 if (!((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))){ |
|
227 _el.children().css("background-color", _this.hover_color); |
|
228 }; |
|
229 }) |
|
230 .mouseout(function(){ |
|
231 if (!((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))){ |
|
232 _el.children().css("background-color", _this.marker_color); |
|
233 }; |
|
234 }) |
|
235 .click(function(){ |
|
236 _this.showScreen("Main"); |
|
237 if (!((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))){ |
|
238 list_$.find(".Ldt-Markers-MarkerBall").css("background-color", _this.marker_color) |
|
239 _el.children().css("background-color", _this.selected_color) |
|
240 _this.selectedMarker = _marker; |
|
241 _divHtml = Mustache.to_html(_this.infoTemplate, { |
|
242 edit: _this.editing, |
|
243 marker_info: _marker.description, |
|
244 send: _this.l10n.send, |
|
245 cancel: _this.l10n.cancel |
|
246 }) |
|
247 |
|
248 _this.$.find(".Ldt-Markers-Info").html(_divHtml); |
|
249 |
|
250 if(_this.editing){ |
|
251 _this.$.find(".Ldt-Markers-MarkerSend").click(_this.functionWrapper("onSubmit")); |
|
252 _this.$.find(".Ldt-Markers-MarkerCancel").click(_this.functionWrapper("toggleCreateMarker")); |
|
253 } |
|
254 } |
|
255 else { |
|
256 var _divHtml = "" |
|
257 if (_this.editing){ |
|
258 _divHtml = Mustache.to_html(_this.infoTemplate, { |
|
259 edit: _this.editing, |
|
260 marker_info: "", |
|
261 send: _this.l10n.send, |
|
262 cancel: _this.l10n.cancel |
|
263 }); |
|
264 } |
|
265 _el.children().css("background-color", _this.hover_color); |
|
266 _this.selectedMarker = false; |
|
267 _this.$.find(".Ldt-Markers-Info").html(_divHtml); |
|
268 |
|
269 if(_this.editing){ |
|
270 _this.$.find(".Ldt-Markers-MarkerSend").click(_this.functionWrapper("onSubmit")); |
|
271 _this.$.find(".Ldt-Markers-MarkerCancel").click(_this.functionWrapper("toggleCreateMarker")); |
|
272 } |
|
273 } |
|
274 |
|
275 if (_this.selectedMarker){ |
|
276 _this.$.find(".Ldt-Markers-Create").html("-") |
|
277 } |
|
278 else { |
|
279 _this.$.find(".Ldt-Markers-Create").html("+") |
|
280 } |
|
281 |
|
282 if (_this.selectedMarker) { |
|
283 // If we unselect a marker we shouldn't trigger pause or time jump |
|
284 _this.media.pause(); |
|
285 _marker.trigger("click"); |
|
286 } |
|
287 }) |
|
288 .appendTo(list_$); |
|
289 }) |
|
290 } |
|
291 |
|
292 IriSP.Widgets.Markers.prototype.onSubmit = function(){ |
|
293 |
|
294 /* Si les champs obligatoires sont vides, on annule l'envoi */ |
|
295 if (!this.onDescriptionChange()) { |
|
296 return false; |
|
297 } |
|
298 |
|
299 /* On pause la vidéo si elle est encore en train de tourner */ |
|
300 if (!this.media.getPaused()){ |
|
301 this.media.pause(); |
|
302 } |
|
303 |
|
304 var _this = this, |
|
305 _exportedAnnotations = new IriSP.Model.List(this.player.sourceManager), /* Création d'une liste d'annotations contenant une annotation afin de l'envoyer au serveur */ |
|
306 _url = Mustache.to_html(this.api_endpoint_template, {annotation_id: this.selectedMarker ? this.selectedMarker.id : ""}); |
|
307 if (this.selectedMarker){ |
|
308 var _export = this.player.sourceManager.newLocalSource({serializer: IriSP.serializers[this.api_serializer]}) |
|
309 _annotation = this.selectedMarker; |
|
310 _annotation.source = _export |
|
311 _annotation.description = this.$.find(".Ldt-Markers-MarkerTextArea").val(), /* Champ description */ |
|
312 _annotationTypes = this.source.getAnnotationTypes().searchByTitle(this.annotation_type, true), /* Récupération du type d'annotation dans lequel l'annotation doit être ajoutée */ |
|
313 _annotationType = (_annotationTypes.length ? _annotationTypes[0] : new IriSP.Model.AnnotationType(false, _export)); /* Si le Type d'Annotation n'existe pas, il est créé à la volée */ |
|
314 } |
|
315 else { |
|
316 var _export = this.player.sourceManager.newLocalSource({serializer: IriSP.serializers[this.api_serializer]}), /* Création d'un objet source utilisant un sérialiseur spécifique pour l'export */ |
|
317 _annotation = new IriSP.Model.Annotation(false, _export); /* Création d'une annotation dans cette source avec un ID généré à la volée (param. false) */ |
|
318 _annotationTypes = this.source.getAnnotationTypes().searchByTitle(this.annotation_type, true), /* Récupération du type d'annotation dans lequel l'annotation doit être ajoutée */ |
|
319 _annotationType = (_annotationTypes.length ? _annotationTypes[0] : new IriSP.Model.AnnotationType(false, _export)); /* Si le Type d'Annotation n'existe pas, il est créé à la volée */ |
|
320 /* Si nous avons dû générer un ID d'annotationType à la volée... */ |
|
321 if (!_annotationTypes.length) { |
|
322 /* Il ne faudra pas envoyer l'ID généré au serveur */ |
|
323 _annotationType.dont_send_id = true; |
|
324 /* Il faut inclure le titre dans le type d'annotation */ |
|
325 _annotationType.title = this.annotation_type; |
|
326 } |
|
327 |
|
328 _annotation.setMedia(this.source.currentMedia.id); /* Id du média annoté */ |
|
329 _currentTime = this.media.getCurrentTime(); |
|
330 _annotation.setBegin(_currentTime); /* Timecode de la lecture de la video */ |
|
331 _annotation.setEnd(_currentTime); /* Timecode de fin du widget */ |
|
332 _annotation.setAnnotationType(_annotationType.id); /* Id du type d'annotation */ |
|
333 if (this.project_id != ""){ |
|
334 /* Champ id projet, seulement si on l'a renseigné dans la config */ |
|
335 _annotation.project_id = this.project_id; |
|
336 } |
|
337 _annotation.created = new Date(); /* Date de création de l'annotation */ |
|
338 _annotation.description = this.$.find(".Ldt-Markers-MarkerTextArea").val(); /* Champ description */ |
|
339 _annotation.creator = this.creator_name; |
|
340 } |
|
341 _annotation.project_id = this.project_id; |
|
342 |
|
343 /* |
|
344 * Nous remplissons les données de l'annotation générée à la volée |
|
345 * ATTENTION: Si nous sommes sur un MASHUP, ces éléments doivent se référer AU MEDIA D'ORIGINE |
|
346 * */ |
|
347 |
|
348 _exportedAnnotations.push(_annotation); /* Ajout de l'annotation à la liste à exporter */ |
|
349 _export.addList("annotation",_exportedAnnotations); /* Ajout de la liste à exporter à l'objet Source */ |
|
350 |
|
351 /* Envoi de l'annotation via AJAX au serveur ! */ |
|
352 IriSP.jQuery.ajax({ |
|
353 url: _url, |
|
354 type: this.selectedMarker ? this.api_method_editing : this.api_method_create, |
|
355 contentType: 'application/json', |
|
356 data: _export.serialize(), /* L'objet Source est sérialisé */ |
|
357 success: function(_data) { |
|
358 _this.showScreen('Success'); /* Si l'appel a fonctionné, on affiche l'écran "Annotation enregistrée" */ |
|
359 window.setTimeout(function(){ |
|
360 _this.showScreen("Main") |
|
361 }, |
|
362 (_this.after_send_timeout || 5000)); |
|
363 _export.getAnnotations().removeElement(_annotation, true); /* Pour éviter les doublons, on supprime l'annotation qui a été envoyée */ |
|
364 _export.deSerialize(_data); /* On désérialise les données reçues pour les réinjecter */ |
|
365 _this.source.merge(_export); /* On récupère les données réimportées dans l'espace global des données */ |
|
366 if (_this.pause_on_write && _this.media.getPaused()) { |
|
367 _this.media.play(); |
|
368 } |
|
369 _this.markers.push(_annotation); |
|
370 _this.selectedMarker = _annotation; |
|
371 _this.player.trigger("AnnotationsList.refresh"); /* On force le rafraîchissement du widget AnnotationsList */ |
|
372 _this.player.trigger("Markers.refresh"); |
|
373 _this.$.find(".Ldt-Markers-MarkerTextArea").val("") |
|
374 }, |
|
375 error: function(_xhr, _error, _thrown) { |
|
376 IriSP.log("Error when sending annotation", _thrown); |
|
377 _export.getAnnotations().removeElement(_annotation, true); |
|
378 _this.showScreen('Failure'); |
|
379 window.setTimeout(function(){ |
|
380 _this.showScreen("Main"); |
|
381 }, |
|
382 (_this.after_send_timeout || 5000)); |
|
383 } |
|
384 }); |
|
385 this.showScreen('Sending'); |
|
386 |
|
387 return false; |
|
388 }; |