src/widgets/CreateAnnotation.js
changeset 1033 c20df1c080e6
parent 1021 7253d4d06f0d
child 1038 e78b889a75e1
--- a/src/widgets/CreateAnnotation.js	Fri Feb 13 16:48:05 2015 +0100
+++ b/src/widgets/CreateAnnotation.js	Fri Feb 13 16:57:53 2015 +0100
@@ -1,7 +1,16 @@
 /* TODO: Add Social Network Sharing */
 
 IriSP.Widgets.CreateAnnotation = function(player, config) {
+    var _this = this;
     IriSP.Widgets.Widget.call(this, player, config);
+    if (_this.api_method == 'local' && window.localStorage[_this.api_endpoint_template]) {
+        this.source.onLoad(function () {
+            var _export = _this.player.sourceManager.newLocalSource({serializer: IriSP.serializers[_this.api_serializer]});
+            _export.deSerialize(window.localStorage[_this.api_endpoint_template]);
+            console.log("Loaded personal annotations", _export);
+            _this.source.merge(_export);
+        });
+    };
 };
 
 IriSP.Widgets.CreateAnnotation.prototype = new IriSP.Widgets.Widget();
@@ -12,6 +21,7 @@
     start_visible : true,
     always_visible : false,
     show_slice : true,
+    show_controls: false,
     show_arrow : true,
     show_mic_record: false,
     show_mic_play: false,
@@ -46,7 +56,8 @@
     api_method: "POST",
     after_send_timeout: 0,
     close_after_send: false,
-    tag_prefix: "#"
+    tag_prefix: "#",
+    slice_widget: null
 };
 
 IriSP.Widgets.CreateAnnotation.prototype.messages = {
@@ -104,8 +115,13 @@
     + '<span class="Ldt-CreateAnnotation-Times"> {{#show_slice}}{{l10n.from_time}} {{/show_slice}}{{^show_slice}}{{l10n.at_time}} {{/show_slice}} <span class="Ldt-CreateAnnotation-Begin">00:00</span>'
     + '{{#show_slice}} {{l10n.to_time}} <span class="Ldt-CreateAnnotation-End">{{end}}</span>{{/show_slice}}</span></span>'
     + '{{#show_creator_field}}{{l10n.your_name_}} <input class="Ldt-CreateAnnotation-Creator empty" value="{{creator_name}}" />{{/show_creator_field}}</h3>'
+    + '{{#show_controls}}<div class="Ldt-CreateAnnotation-Controls">'
+    +   '<span class="Ldt-CreateAnnotation-Control-In">IN</span>'
+    +   '<span class="Ldt-CreateAnnotation-Control-Out">OUT</span>'
+    +   '<span class="Ldt-CreateAnnotation-Control-Play">Play</span>'
+    + '</div>{{/show_controls}}'
     + '<textarea class="Ldt-CreateAnnotation-Description empty" placeholder="{{l10n.type_description}}"></textarea>'
-    + '<div class="Ldt-CreateAnnotation-Avatar"><img src="{{creator_avatar}}" title="{{creator_name}}"></img></div>'
+    + '{{#show_creator_field}}<div class="Ldt-CreateAnnotation-Avatar"><img src="{{creator_avatar}}" title="{{creator_name}}"></img></div>{{/show_creator_field}}'
     + '<input type="submit" class="Ldt-CreateAnnotation-Submit" value="{{l10n.submit}}" />'
     + '{{#show_mic_record}}<div class="Ldt-CreateAnnotation-RecBlock"><div class="Ldt-CreateAnnotation-RecLabel">Add voice annotation</div>'
     + '    <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="220" height="160">'
@@ -130,7 +146,7 @@
     + '             pluginspage="http://www.macromedia.com/go/getflashplayer">'
     + '        </embed>'
     + '    </object>'
-    + '</div>{{/show_mic_record}}' 
+    + '</div>{{/show_mic_record}}'
     + '{{#tags.length}}<div class="Ldt-CreateAnnotation-Tags"><div class="Ldt-CreateAnnotation-TagTitle">{{l10n.add_keywords_}}</div><ul class="Ldt-CreateAnnotation-TagList">'
     + '{{#tags}}<li class="Ldt-CreateAnnotation-TagLi" tag-id="{{id}}" data-text="{{tag_prefix}}{{title}}"><span class="Ldt-CreateAnnotation-TagButton">{{title}}</span></li>{{/tags}}</ul></div>{{/tags.length}}'
     + '{{#polemics.length}}<div class="Ldt-CreateAnnotation-Polemics"><div class="Ldt-CreateAnnotation-PolemicTitle">{{l10n.add_polemic_keywords_}}</div><ul class="Ldt-CreateAnnotation-PolemicList">'
@@ -140,15 +156,15 @@
     + '<div class="Ldt-CreateAnnotation-Screen Ldt-CreateAnnotation-Error">{{^always_visible}}<a title="{{l10n.close_widget}}" class="Ldt-CreateAnnotation-Close" href="#"></a>{{/always_visible}}<div class="Ldt-CreateAnnotation-InnerBox">{{l10n.error_while_contacting}}</div></div>'
     + '<div class="Ldt-CreateAnnotation-Screen Ldt-CreateAnnotation-Saved">{{^always_visible}}<a title="{{l10n.close_widget}}" class="Ldt-CreateAnnotation-Close" href="#"></a>{{/always_visible}}<div class="Ldt-CreateAnnotation-InnerBox">{{l10n.annotation_saved}}</div></div>'
     + '</div></div>';
-    
+
 IriSP.Widgets.CreateAnnotation.prototype.draw = function() {
     var _this = this;
-    
+
     this.begin = new IriSP.Model.Time();
     this.end = this.source.getDuration();
-    
+
     this.tag_prefix = this.tag_prefix || "";
-    
+
     if (this.tag_titles && !this.tags) {
 		if(!(this.tag_titles.length==1 && this.tag_titles[0]=="")){
 			this.tags = IriSP._(this.tag_titles).map(function(_tag_title) {
@@ -184,13 +200,13 @@
     this.renderTemplate();
     if (this.show_mic_record) {
         this.recorder = this.$.find("embed")[0];
-        
+
         window.setAudioUrl = function(_url) {
             _this.audio_url = _url;
-        }
+        };
     }
     if (this.show_slice) {
-        this.insertSubwidget(
+        this.slice_widget = this.insertSubwidget(
             this.$.find(".Ldt-CreateAnnotation-Slice"),
             {
                 type: "Slice",
@@ -243,14 +259,34 @@
     if (this.show_creator_field) {
         this.$.find(".Ldt-CreateAnnotation-Creator").bind("change keyup input paste", this.functionWrapper("onCreatorChange"));
     }
-    
+    this.$.find("[class^='Ldt-CreateAnnotation-Control-']").click(function() {
+        var action = this.className.replace('Ldt-CreateAnnotation-Control-', '');
+        switch (action) {
+            case "In":
+               // Set In bound to current player time
+               _this.begin = new IriSP.Model.Time(_this.media.getCurrentTime() || 0);
+               _this.$.find(".Ldt-CreateAnnotation-Begin").html(_this.begin.toString());
+               break;
+            case "Out":
+               // Set In bound to current player time
+               _this.end = new IriSP.Model.Time(_this.media.getCurrentTime() || _this.media.duration);
+               _this.$.find(".Ldt-CreateAnnotation-End").html(_this.end.toString());
+               break;
+            case "Play":
+               _this.media.setCurrentTime(_this.begin);
+               _this.media.play()
+               break;
+        }
+        return false;
+    });
+
     if (this.start_visible) {
         this.show();
     } else {
         this.$.hide();
         this.hide();
     }
-    
+
     this.onMdpEvent("CreateAnnotation.toggle","toggle");
     this.$.find("form").submit(this.functionWrapper("onSubmit"));
 };
@@ -294,10 +330,18 @@
 };
 
 IriSP.Widgets.CreateAnnotation.prototype.toggle = function() {
+    var _this = this;
     if (!this.always_visible) {
         if (this.visible) {
             this.hide();
         } else {
+            _this.begin = new IriSP.Model.Time(_this.media.getCurrentTime() || 0);
+            _this.end = new IriSP.Model.Time(_this.media.getCurrentTime() || 0);
+            _this.$.find(".Ldt-CreateAnnotation-Begin").html(_this.begin.toString());
+            _this.$.find(".Ldt-CreateAnnotation-End").html(_this.end.toString());
+            if (_this.slice_widget) {
+                _this.slice_widget.setBounds(_this.begin, _this.end);
+            }
             this.show();
         }
     }
@@ -375,11 +419,11 @@
     if (!this.onDescriptionChange() || (this.show_title_field && !this.onTitleChange()) || (this.show_creator_field && !this.onCreatorChange())) {
         return false;
     }
-    
+
     if (this.recorder) {
         this.recorder.stopRecord();
     }
-    
+
     var _this = this,
         _exportedAnnotations = new IriSP.Model.List(this.player.sourceManager), /* Création d'une liste d'annotations contenant une annotation afin de l'envoyer au serveur */
         _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 */
@@ -387,7 +431,7 @@
         _annotationTypes = this.source.getAnnotationTypes().searchByTitle(this.annotation_type, true), /* Récupération du type d'annotation dans lequel l'annotation doit être ajoutée */
         _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 */
         _url = Mustache.to_html(this.api_endpoint_template, {id: this.source.projectId}); /* Génération de l'URL à laquelle l'annotation doit être envoyée, qui doit inclure l'ID du projet */
-    
+
     /* Si nous avons dû générer un ID d'annotationType à la volée... */
     if (!_annotationTypes.length) {
         /* Il ne faudra pas envoyer l'ID généré au serveur */
@@ -395,7 +439,7 @@
         /* Il faut inclure le titre dans le type d'annotation */
         _annotationType.title = this.annotation_type;
     }
-    
+
     /*
      * Nous remplissons les données de l'annotation générée à la volée
      * ATTENTION: Si nous sommes sur un MASHUP, ces éléments doivent se référer AU MEDIA D'ORIGINE
@@ -403,20 +447,22 @@
     _annotation.setMedia(this.source.currentMedia.id); /* Id du média annoté */
     _annotation.setBegin(this.begin); /*Timecode de début */
     _annotation.setEnd(this.end); /* Timecode de fin */
-   
+    _annotation.created = new Date(); /* Date de création de l'annotation */
+
     _annotation.setAnnotationType(_annotationType.id); /* Id du type d'annotation */
+    _annotation.description = this.$.find(".Ldt-CreateAnnotation-Description").val(); /* Champ description */
     if (this.show_title_field) {
         /* Champ titre, seulement s'il est visible */
         _annotation.title = this.$.find(".Ldt-CreateAnnotation-Title").val();
+    } else {
+        _annotation.title = _annotation.description;
     }
-    _annotation.created = new Date(); /* Date de création de l'annotation */
-    _annotation.description = this.$.find(".Ldt-CreateAnnotation-Description").val(); /* Champ description */
-   
+
     var tagIds = Array.prototype.map.call(
         this.$.find(".Ldt-CreateAnnotation-TagLi.selected"),
         function(el) { return IriSP.jQuery(el).attr("tag-id")}
     );
-        
+
     IriSP._(_annotation.description.match(/#[^\s#.,;]+/g)).each(function(_tt) {
         var _tag,
             _tag_title = _tt.replace(/^#/,''),
@@ -431,9 +477,9 @@
         if (tagIds.indexOf(_tag.id) === -1) {
             tagIds.push(_tag.id);
         }
-        
+
     })
-   
+
     _annotation.setTags(IriSP._(tagIds).uniq()); /*Liste des ids de tags */
     if (this.audio_url) {
         _annotation.audio = {
@@ -448,47 +494,65 @@
         _annotation.creator = this.creator_name;
     }
     _exportedAnnotations.push(_annotation); /* Ajout de l'annotation à la liste à exporter */
-    _export.addList("annotation",_exportedAnnotations); /* Ajout de la liste à exporter à l'objet Source */
-    
-    var _this = this;
-    /* Envoi de l'annotation via AJAX au serveur ! */
-    IriSP.jQuery.ajax({
-        url: _url,
-        type: this.api_method,
-        contentType: 'application/json',
-        data: _export.serialize(), /* L'objet Source est sérialisé */
-        success: function(_data) {
-            _this.showScreen('Saved'); /* Si l'appel a fonctionné, on affiche l'écran "Annotation enregistrée" */
-            if (_this.after_send_timeout) { /* Selon les options de configuration, on revient à l'écran principal ou on ferme le widget, ou rien */
-                window.setTimeout(
-                    function() {
-                        _this.close_after_send
-                        ? _this.hide()
-                        : _this.show();
-                    },
-                    _this.after_send_timeout
-                );
+
+    if (this.api_method == 'local') {
+        // Append to existing localStorage annotations
+        // FIXME: handle movie ids
+        /* Use localStorage */
+        /* Data will be serialized in the localStore property designated by api_endpoint_template */
+        _export.addList("annotation", _exportedAnnotations); /* Ajout de la liste à exporter à l'objet Source */
+        _this.source.merge(_export); /* On ajoute la nouvelle annotation au recueil original */
+        // Import previously saved local annotations
+        if (window.localStorage[_this.api_endpoint_template]) {
+            _export.deSerialize(window.localStorage[_this.api_endpoint_template]);
+        }
+        // Save everything back
+        window.localStorage[_this.api_endpoint_template] = _export.serialize();
+        if (_this.pause_on_write && _this.media.getPaused()) {
+            _this.media.play();
+        }
+        _this.player.trigger("AnnotationsList.refresh"); /* On force le rafraîchissement du widget AnnotationsList */
+        _this.$.find(".Ldt-CreateAnnotation-Description").val("");
+    } else {
+        _export.addList("annotation",_exportedAnnotations); /* Ajout de la liste à exporter à l'objet Source */
+       /* Envoi de l'annotation via AJAX au serveur ! */
+        IriSP.jQuery.ajax({
+            url: _url,
+            type: this.api_method,
+            contentType: 'application/json',
+            data: _export.serialize(), /* L'objet Source est sérialisé */
+            success: function(_data) {
+                _this.showScreen('Saved'); /* Si l'appel a fonctionné, on affiche l'écran "Annotation enregistrée" */
+                if (_this.after_send_timeout) { /* Selon les options de configuration, on revient à l'écran principal ou on ferme le widget, ou rien */
+                    window.setTimeout(
+                        function() {
+                            _this.close_after_send
+                                ? _this.hide()
+                                : _this.show();
+                        },
+                        _this.after_send_timeout
+                    );
+                }
+                _export.getAnnotations().removeElement(_annotation, true); /* Pour éviter les doublons, on supprime l'annotation qui a été envoyée */
+                _export.deSerialize(_data); /* On désérialise les données reçues pour les réinjecter */
+                _this.source.merge(_export); /* On récupère les données réimportées dans l'espace global des données */
+                if (_this.pause_on_write && _this.media.getPaused()) {
+                    _this.media.play();
+                }
+                _this.player.trigger("AnnotationsList.refresh"); /* On force le rafraîchissement du widget AnnotationsList */
+            },
+            error: function(_xhr, _error, _thrown) {
+                IriSP.log("Error when sending annotation", _thrown);
+                _export.getAnnotations().removeElement(_annotation, true);
+                _this.showScreen('Error');
+                window.setTimeout(function(){
+                    _this.showScreen("Main")
+                },
+                                  (_this.after_send_timeout || 5000));
             }
-            _export.getAnnotations().removeElement(_annotation, true); /* Pour éviter les doublons, on supprime l'annotation qui a été envoyée */
-            _export.deSerialize(_data); /* On désérialise les données reçues pour les réinjecter */
-            _this.source.merge(_export); /* On récupère les données réimportées dans l'espace global des données */
-            if (_this.pause_on_write && _this.media.getPaused()) {
-                _this.media.play();
-            }
-            _this.player.trigger("AnnotationsList.refresh"); /* On force le rafraîchissement du widget AnnotationsList */
-        },
-        error: function(_xhr, _error, _thrown) {
-            IriSP.log("Error when sending annotation", _thrown);
-            _export.getAnnotations().removeElement(_annotation, true);
-            _this.showScreen('Error');
-            window.setTimeout(function(){
-                _this.showScreen("Main")
-            },
-            (_this.after_send_timeout || 5000));
-        }
-    });
-    this.showScreen('Wait');
-    
+        });
+        this.showScreen('Wait');
+    }
+
     return false;
 };
-