Updated LatestAnnotation, CurrentSegmentInfobox, AnnotationController and AnnotationList widgets to use timerange to find the current segment when the corresponding option is used + CurrentSegmentInfobox now has an option for editing the current segment + LatestAnnotation now has a "Copy and edit" button that allows to use the text from the currently displayed annotation into the CreateAnnotation widget textarea
authordurandn
Tue, 01 Sep 2015 15:31:46 +0200
changeset 1046 eb77616c245f
parent 1045 b06345320ffb
child 1047 c3bf174e0ef8
Updated LatestAnnotation, CurrentSegmentInfobox, AnnotationController and AnnotationList widgets to use timerange to find the current segment when the corresponding option is used + CurrentSegmentInfobox now has an option for editing the current segment + LatestAnnotation now has a "Copy and edit" button that allows to use the text from the currently displayed annotation into the CreateAnnotation widget textarea
src/widgets/AnnotationsController.js
src/widgets/AnnotationsList.css
src/widgets/AnnotationsList.js
src/widgets/CurrentSegmentInfobox.css
src/widgets/CurrentSegmentInfobox.js
src/widgets/LatestAnnotation.css
src/widgets/LatestAnnotation.js
src/widgets/img/loader.gif
--- a/src/widgets/AnnotationsController.js	Tue Sep 01 15:24:26 2015 +0200
+++ b/src/widgets/AnnotationsController.js	Tue Sep 01 15:31:46 2015 +0200
@@ -15,7 +15,7 @@
     display_or_write: false,
     starts_hidden: false,
     hide_without_segment: false,
-    segments_annotation_type: "chap"
+    segments_annotation_type: "chap",
 };
 
 IriSP.Widgets.AnnotationsController.prototype.template = 
@@ -57,7 +57,17 @@
             _this.player.trigger("CreateAnnotation.hide");
         }
     })
-    this.onMediaEvent("timeupdate", "onTimeUpdate")
+    
+    if(this.hide_without_segment){
+        this.onMediaEvent("timeupdate", function(){
+            _this.refresh();
+        })
+        this.onMediaEvent("settimerange", function(_timeRange){
+            _this.refresh(_timeRange);
+        })
+        this.segments = this.source.getAnnotationsByTypeTitle(this.segments_annotation_type)
+        this.currentSegment = false
+    }
     
     if (this.starts_hidden) {
         this.visible = true
@@ -70,25 +80,53 @@
     
 };
 
-IriSP.Widgets.AnnotationsController.prototype.onTimeUpdate = function(){
+IriSP.Widgets.AnnotationsController.prototype.refresh = function(_timeRange){
+    _timeRange = typeof _timeRange !== 'undefined' ? _timeRange : false ;
+    
+    if(!_timeRange){
+        if (this.media.getTimeRange()){
+            _timeRange = this.media.getTimeRange();
+        }
+    }
+    
     if (this.hide_without_segment){
-        _currentTime = this.media.getCurrentTime() 
-        _segmentsAnnotations = this.source.getAnnotationsByTypeTitle(this.segments_annotation_type)
-        _currentSegments = _segmentsAnnotations.filter(function(_segment){
-            return (_currentTime >= _segment.begin && _currentTime <= _segment.end)
-        });
-        if (_currentSegments.length == 0){
+        if (!_timeRange && !this.media.getTimeRange()){
+            _currentTime = this.media.getCurrentTime() 
+            _currentSegments = this.segments.filter(function(_segment){
+                return (_currentTime >= _segment.begin && _currentTime <= _segment.end)
+            });
+            if(_currentSegments.length > 0){
+                currentSegment = true;
+            }
+            else {
+                currentSegment = false;
+            }
+        }
+        else {
+            var _timeRangeBegin = _timeRange[0],
+                _timeRangeEnd = _timeRange[1];
+            _currentSegments = this.segments.filter(function(_segment){
+                return (_timeRangeBegin == _segment.begin && _timeRangeEnd == _segment.end)
+            });
+            if(_currentSegments.length > 0){
+                currentSegment = true;
+            }
+            else {
+                currentSegment = false;
+            }
+        }
+        if (!currentSegment && _currentSegments.length == 0){
             if (this.visible){
                 this.hide();
-                _this.player.trigger("CreateAnnotation.hide");
-                _this.player.trigger("AnnotationsList.hide");
+                this.player.trigger("CreateAnnotation.hide");
+                this.player.trigger("AnnotationsList.hide");
             }
         }
         else {
             if (!this.visible){
                 this.show();
-                _this.player.trigger("CreateAnnotation.hide");
-                _this.player.trigger("AnnotationsList.hide");
+                this.player.trigger("CreateAnnotation.hide");
+                this.player.trigger("AnnotationsList.hide");
             }
         }
     }
--- a/src/widgets/AnnotationsList.css	Tue Sep 01 15:24:26 2015 +0200
+++ b/src/widgets/AnnotationsList.css	Tue Sep 01 15:31:46 2015 +0200
@@ -1,9 +1,14 @@
 /* AnnotationsListWidget */
 
+#ui-datepicker-div
+{
+    display: none;
+}
+
 .Ldt-AnnotationsListWidget {
     border: none; margin: 0; padding: 0;
     overflow: auto;
-    max-height: 480px;
+    max-height: 380px;
 }
 .Ldt-AnnotationsListWidget a {
     text-decoration: none;
--- a/src/widgets/AnnotationsList.js	Tue Sep 01 15:24:26 2015 +0200
+++ b/src/widgets/AnnotationsList.js	Tue Sep 01 15:31:46 2015 +0200
@@ -37,8 +37,10 @@
     start_visible: true,
     show_audio : true,
     show_filters : false,
+    show_header : false,
+    custom_header : false,
     show_creation_date : false,
-    show_timecode : true, 
+    show_timecode : true,
     /*
      * Only annotation in the current segment will be displayed. Designed to work with the Segments Widget.
      */
@@ -71,21 +73,30 @@
 IriSP.Widgets.AnnotationsList.prototype.messages = {
     en: {
         voice_annotation: "Voice Annotation",
-        now_playing: "Now playing..."
+        now_playing: "Now playing...",
+        everyone: "Everyone",
+        header: "Annotations for this content"
     },
     fr: {
         voice_annotation: "Annotation Vocale",
-        now_playing: "Lecture en cours..."
+        now_playing: "Lecture en cours...",
+        everyone: "Tous",
+        header: "Annotations sur ce contenu"
     }
 };
 
 IriSP.Widgets.AnnotationsList.prototype.template =
-    '<div class="Ldt-AnnotationsListWidget">'
+    '{{#show_header}}<p class="Ldt-AnnotationsList-header">'
+    +     '{{#custom_header}}{{custom_header}}{{/custom_header}}'
+    +     '{{^custom_header}}{{l10n.header}}{{/custom_header}}'
+    + '</p>{{/show_header}}'
+    + '<div class="Ldt-AnnotationsListWidget">'
     + '{{#show_filters}}'
     + '<div class="Ldt-AnnotationsList-Filters">'
-    +    '<input class="Ldt-AnnotationsList-filter-text" type="text" value="Mot-clés"></input>'
-    +    '<select class="Ldt-AnnotationsList-filter-dropdown"></select>'
-    +    '<label class="Ldt-AnnotationsList-filter-checkbox"><input type="checkbox">Toutes annotations</label>'
+    +    '<input class="Ldt-AnnotationsList-filter-text" id="Ldt-AnnotationsList-keywordsFilter" type="text" value=""></input>'
+    +    '<select class="Ldt-AnnotationsList-filter-dropdown" id="Ldt-AnnotationsList-userFilter"><option selected value="">{{l10n.everyone}}</option></select>'
+    +    '<label class="Ldt-AnnotationsList-filter-date">Date: <input id="Ldt-AnnotationsList-dateFilter" type="text"></input></label>'
+    +    '<label class="Ldt-AnnotationsList-filter-checkbox"><input type="checkbox" id="Ldt-AnnotationsList-ignoreSegmentsFilter">Toutes annotations</label>'
     + '</div>'
     + '{{/show_filters}}'
     + '{{#show_audio}}<div class="Ldt-AnnotationsList-Audio"></div>{{/show_audio}}'
@@ -177,15 +188,23 @@
     _list = _list.filter(function(_annotation) {
         return _annotation.found !== false;
     });
-    if (this.filter_by_segments) {
+    
+    if ((this.filter_by_segments)&&(!(this.show_filters && this.ignoresegmentcheckbox_$[0].checked))) {
         /*
          *  A given annotation is considered "in" segment if the middle of it is between the segment beginning and the segment end. 
          *  Note this is meant to be used for "markings" annotations (not segments)
          */
         _segmentsAnnotation = this.currentSource.getAnnotationsByTypeTitle(this.segments_annotation_type)
-        _currentSegments = _segmentsAnnotation.filter(function(_segment){
-            return (_currentTime >= _segment.begin && _currentTime <= _segment.end)
-        });
+        if (this.media.getTimeRange()){
+            _currentSegments = _segmentsAnnotation.filter(function(_segment){
+                return (_this.media.getTimeRange()[0] == _segment.begin && _this.media.getTimeRange()[1] == _segment.end)
+            });
+        }
+        else {
+            _currentSegments = _segmentsAnnotation.filter(function(_segment){
+                return (_currentTime >= _segment.begin && _currentTime <= _segment.end)
+            });
+        }
         if (_currentSegments.length == 0) {
             _list = _list.filter(function(_annotation){
                 return false;
@@ -209,6 +228,7 @@
             return Math.abs((_annotation.begin + _annotation.end) / 2 - _currentTime);
         }).slice(0, this.limit_count);
     }
+    
     if (this.newest_first) {
         _list = _list.sortBy(function(_annotation) {
             return -_annotation.created.valueOf();
@@ -219,6 +239,31 @@
         });
     }
     
+    if (this.show_filters){
+        _username = this.userselect_$[0].options[this.userselect_$[0].selectedIndex].value;
+        if (_username != "false")
+        {
+            _list = _list.filter(function(_annotation){
+                return _annotation.creator == _username
+            })
+        }
+        _keyword = this.keywordinput_$[0].value;
+        if (_keyword != ""){
+            _list = _list.filter(function(_annotation){
+               return _annotation.description.toLowerCase().match(_keyword.toLowerCase());
+            });
+        }
+        
+        
+        if(this.datefilterinput_$[0].value != ""){
+            _date = this.datefilterinput_$.datepicker("getDate");
+            _list = _list.filter(function(_annotation){
+                return ((_annotation.created.getDate() == _date.getDate())&&(_annotation.created.getMonth() == _date.getMonth())&&(_annotation.created.getFullYear() == _date.getFullYear()))
+            });
+        }
+        
+    }
+    
     var _ids = _list.idIndex;
     
     if (_forceRedraw || !IriSP._.isEqual(_ids, this.lastIds) || this.searchString !== this.lastSearch) {
@@ -246,7 +291,8 @@
             );
             var _title = "",
                 _description = _annotation.description,
-                _thumbnail = (typeof _annotation.thumbnail !== "undefined" && _annotation.thumbnail ? _annotation.thumbnail : _this.default_thumbnail);
+                _thumbnail = (typeof _annotation.thumbnail !== "undefined" && _annotation.thumbnail ? _annotation.thumbnail : _this.default_thumbnail)
+            
             // Update : display creator
             if (_annotation.creator) {
                 _title = _annotation.creator;
@@ -334,6 +380,9 @@
                 .mouseout(function() {
                     _annotation.trigger("unselect");
                 })
+                .click(function() {
+                    _annotation.trigger("click");
+                })
                 .appendTo(_this.list_$);
             IriSP.attachDndData(_el.find("[draggable]"), {
                 title: _title,
@@ -393,16 +442,20 @@
 };
 
 IriSP.Widgets.AnnotationsList.prototype.hide = function() {
+    var _this = this;
     if (this.visible){
         this.visible = false;
-        this.widget_$.slideUp()
+        this.widget_$.slideUp(function(){
+            _this.$.find('.Ldt-AnnotationsList-header').hide();            
+        });
     }
 }
 
 IriSP.Widgets.AnnotationsList.prototype.show = function() {
     if(!this.visible){
         this.visible = true;
-        this.widget_$.slideDown()
+        this.$.find('.Ldt-AnnotationsList-header').show();
+        this.widget_$.slideDown();
     }
 }
 
@@ -428,7 +481,23 @@
         
     this.list_$ = this.$.find(".Ldt-AnnotationsList-ul");
     this.widget_$ = this.$.find(".Ldt-AnnotationsListWidget");
-    
+    this.userselect_$ = this.$.find("#Ldt-AnnotationsList-userFilter");
+    this.userselect_$.change(function(){
+        _this.player.trigger("AnnotationsList.refresh");
+    });
+    this.keywordinput_$ = this.$.find("#Ldt-AnnotationsList-keywordsFilter");
+    this.keywordinput_$.keyup(function(){
+        _this.player.trigger("AnnotationsList.refresh");
+    });
+    this.ignoresegmentcheckbox_$ = this.$.find("#Ldt-AnnotationsList-ignoreSegmentsFilter");
+    this.ignoresegmentcheckbox_$.click(function(){
+        _this.player.trigger("AnnotationsList.refresh");
+    });
+    this.datefilterinput_$ = this.$.find("#Ldt-AnnotationsList-dateFilter");
+    this.datefilterinput_$.datepicker({ dateFormat: 'dd/mm/yy' });
+    this.datefilterinput_$.change(function(){
+        _this.player.trigger("AnnotationsList.refresh")
+    })
     
     this.source.getAnnotations().on("search", function(_text) {
         _this.searchString = _text;
@@ -453,6 +522,20 @@
         _this.throttledRefresh();
     });
     
+    if (this.show_filters){
+        _usernames = Array();
+        _list = this.getWidgetAnnotations()
+        _list.forEach(function(_annotation){
+            if(_usernames.indexOf(_annotation.creator) == -1){
+                _usernames.push(_annotation.creator);
+            }
+        });
+        this.userselect_$.html("<option selected value='false'>"+this.l10n.everyone+"</option>");
+        _usernames.forEach(function(_user){
+            _this.userselect_$.append("<option value='"+_user+"'>"+_user+"</option>");
+        });
+    }
+    
     this.onMdpEvent("AnnotationsList.refresh", function() {
         if (_this.ajax_url) {
             if (_this.mashupMode) {
@@ -484,11 +567,12 @@
     this.onMdpEvent("AnnotationsList.hide", "hide");
     this.onMdpEvent("AnnotationsList.show", "show");
     
-    this.onMdpEvent("createAnnotationWidget.addedAnnotation", "refresh");
+    this.onMdpEvent("createAnnotationWidget.addedAnnotation", this.throttledRefresh);
     var _events = [
         "timeupdate",
         "seeked",
-        "loadedmetadata"
+        "loadedmetadata",
+        "settimerange"
     ];
     for (var _i = 0; _i < _events.length; _i++) {
         this.onMediaEvent(_events[_i], this.throttledRefresh);
--- a/src/widgets/CurrentSegmentInfobox.css	Tue Sep 01 15:24:26 2015 +0200
+++ b/src/widgets/CurrentSegmentInfobox.css	Tue Sep 01 15:31:46 2015 +0200
@@ -39,10 +39,90 @@
 	font-weight: bold;
 }
 
+textarea.Ldt-CurrentSegmentInfobox-DescriptionInput.Ldt-CurrentSegmentInfobox-Description{
+	display: inline-block;
+	width: 95%;
+}
+
 .Ldt-CurrentSegmentInfobox-Tags{
 }
 
 .Ldt-CurrentSegmentInfobox-NoSegment{
 	font-size: 15px;
 	font-weight: bold;
+}
+
+.Ldt-CurrentSegmentInfobox-SubmitButton{
+	display: inline-block;
+    background-color: #d93c71;
+    color: #ffffff;
+    float: right;
+    cursor: pointer;
+    height: 14px;
+    width: 100px;
+    margin: 2px;
+    margin-top: 5px;
+    padding: 2px;
+    font-size: 11px;
+    border: 1px solid;
+    border-color: #eca3bc #631e34 #36101c #e16e93;
+    cursor: pointer;
+    text-align: center;
+    vertical-align: middle;
+}
+
+.Ldt-CurrentSegmentInfobox-CancelButton{
+	display: inline-block;
+    background-color: #d93c71;
+    color: #ffffff;
+    float: right;
+    cursor: pointer;
+    height: 14px;
+    width: 100px;
+    margin: 2px;
+    margin-top: 5px;
+    margin-right: 5px;
+    padding: 2px;
+    font-size: 11px;
+    border: 1px solid;
+    border-color: #eca3bc #631e34 #36101c #e16e93;
+    cursor: pointer;
+    text-align: center;
+    vertical-align: middle;
+}
+
+.Ldt-CurrentSegmentInfobox-CreateTagButton{
+	display: block;
+    background-color: #d93c71;
+    color: #ffffff;
+    cursor: pointer;
+    height: 14px;
+    width: 75px;
+    margin: 2px;
+    padding: 2px;
+    font-size: 11px;
+    border: 1px solid;
+    border-color: #eca3bc #631e34 #36101c #e16e93;
+    cursor: pointer;
+    text-align: center;
+    vertical-align: middle;
+}
+
+.Ldt-CurrentSegmentInfobox-Tags-Li-Input{
+	width: 80px;
+}
+
+.Ldt-CurrentSegmentInfobox-CreateTagButton:hover, .Ldt-CurrentSegmentInfobox-CancelButton:hover,
+.Ldt-CurrentSegmentInfobox-SubmitButton:hover{
+	background-color: #e15581;
+	border-color: #222222 #e87d9f #f0adc3 #68273c;
+}
+
+.Ldt-CurrentSegmentInfobox-Tags-Li-DeleteTagButton{
+	font-weight: bold;
+	color: #d93c71
+}
+
+.Ldt-CurrentSegmentInfobox-Tags-Li-DeleteTagButton:hover{
+	color: #e16e93
 }
\ No newline at end of file
--- a/src/widgets/CurrentSegmentInfobox.js	Tue Sep 01 15:24:26 2015 +0200
+++ b/src/widgets/CurrentSegmentInfobox.js	Tue Sep 01 15:31:46 2015 +0200
@@ -8,69 +8,263 @@
 
 IriSP.Widgets.CurrentSegmentInfobox.prototype.defaults = {
     annotation_type: "chap",
-    readonly: true,
-    empty_message: false
+    editable_segments: false,
+    empty_message: false,
+    project_id: false,
+    api_serializer: "ldt_annotate",
+    api_method: "PUT",
+    api_endpoint_template: ""
 };
 
 IriSP.Widgets.CurrentSegmentInfobox.prototype.template = 
-    "<div class='Ldt-CurrentSegmentInfobox'>" 
-    + "    <div class='Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-Title'>{{title}}</div>" 
-    + "    <div class='Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-Description'>{{description}}</div>" 
-    + "    <div class='Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-Tags'>"
-    + '        {{#tags.length}}'
-    + '        <ul class="Ldt-CurrentSegmentInfobox-Tags-Ul">'
-    + '        {{#tags}}'
-    + '            {{#.}}'
-    + '            <li class="Ldt-CurrentSegmentInfobox-Tags-Li">'
-    + '                <span>{{.}}</span>'
-    + '            </li>'
-    + '            {{/.}}'
-    + '        {{/tags}}'
-    + '        </ul>'
-    + '        {{/tags.length}}'
-    + "    </div>" 
-    + "</div>"
+      '<div class="Ldt-CurrentSegmentInfobox">'
+    +     '<div class="Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-Title">{{title}}</div>'
+    +     '<div class="Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-Description">{{description}}</div>' 
+    +     '<div class="Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-Tags">'
+    +         '{{#tags.length}}'
+    +         '<ul class="Ldt-CurrentSegmentInfobox-Tags-Ul">'
+    +         '{{#tags}}'
+    +             '{{#.}}'
+    +             '<li class="Ldt-CurrentSegmentInfobox-Tags-Li">'
+    +                 '<span>{{.}}</span>'
+    +             '</li>'
+    +             '{{/.}}'
+    +         '{{/tags}}'
+    +         '</ul>'
+    +         '{{/tags.length}}'
+    +     '</div>'
+    + '</div>'
 
+IriSP.Widgets.CurrentSegmentInfobox.prototype.editTemplate = 
+      '<div class="Ldt-CurrentSegmentInfobox">'
+    +     '<input type="text" class="Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-TitleInput Ldt-CurrentSegmentInfobox-Title" value="{{title}}"></input>'   
+    +     '<div class="Ldt-CurrentSegmentInfobox-CancelButton">{{cancel}}</div>'
+    +     '<div class="Ldt-CurrentSegmentInfobox-SubmitButton">{{submit}}</div>'
+    +     '<textarea class="Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-DescriptionInput Ldt-CurrentSegmentInfobox-Description">{{description}}</textarea>'
+    +     '<div class="Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-Tags">'       
+    +         '<div class="Ldt-CurrentSegmentInfobox-CreateTagButton">{{new_tag}}</div>'
+    +         '{{#tags.length}}'
+    +         '<ul class="Ldt-CurrentSegmentInfobox-Tags-Ul">'
+    +         '{{#tags}}'
+    +             '{{#.}}'
+    +             '<li class="Ldt-CurrentSegmentInfobox-Tags-Li">'
+    +                 '<input type="text" class="Ldt-CurrentSegmentInfobox-Tags-Li-Input" value="{{.}}"></input>'
+    +                 '<div class="Ldt-CurrentSegmentInfobox-Tags-Li-DeleteTagButton">{{delete_tag}}</div>'
+    +             '</li>'
+    +             '{{/.}}'
+    +         '{{/tags}}'
+    +         '</ul>'
+    +         '{{/tags.length}}'
+    +     '</div>'
+    + '</div>'
+    
 IriSP.Widgets.CurrentSegmentInfobox.prototype.messages = {
     fr : {
+        submit : "Soumettre",
+        cancel : "Annuler",
+        new_tag : "Nouveau tag",
+        delete_tag : "Supprimer",
         empty : "Le player vidéo ne lit actuellement aucun segment"
     },
     en: {
-        empty: "The player currently doesn't read any segment"
+        submit : "Submit",
+        cancel : "Cancel",
+        new_tag : "New tag",
+        delete_tag : "Delete tag",
+        empty : "The player currently doesn't read any segment"
     }
 }    
     
 IriSP.Widgets.CurrentSegmentInfobox.prototype.draw = function() {
     var _this = this;
     this.segments = this.getWidgetAnnotations();
-    
     this.renderTemplate();
+    this.currentSegment = false;
+    this.clearBox();
     this.refresh();
+    this.onMediaEvent("timeupdate", "refresh");
+    this.onMediaEvent("settimerange", function(_timeRange){
+        var _segmentBegin = _timeRange[0],
+            _segmentEnd = _timeRange[1],
+            _list = _this.segments.filter(function(_segment){
+                return _segment.begin.milliseconds == _segmentBegin.milliseconds && _segment.end.milliseconds == _segmentEnd.milliseconds
+            });
+        if (_list.length >0){
+            if (_this.currentSegment.id != _list[0].id){
+                _this.currentSegment = _list[0];
+                _data = {
+                    title: _this.currentSegment.title,
+                    description : _this.currentSegment.description,
+                    tags : _this.currentSegment.getTagTexts()
+                }
+                _this.$.html(Mustache.to_html(_this.template, _data))
+                if(_this.editable_segments&&_this.currentSegment){
+                    _this.$.find(".Ldt-CurrentSegmentInfobox").click(_this.functionWrapper("enableEditMode"));            
+                }
+            }
+        }
+    });
     
-    this.onMediaEvent("timeupdate", "refresh");
+    if(this.editable_segments&&this.currentSegment){
+        this.$.find(".Ldt-CurrentSegmentInfobox").click(_this.functionWrapper("enableEditMode"));        
+    }
+}
+
+IriSP.Widgets.CurrentSegmentInfobox.prototype.enableEditMode = function() {
+    if(this.currentSegment){
+        _data = {
+            title: this.currentSegment.title,
+            description : this.currentSegment.description,
+            tags : this.currentSegment.getTagTexts(),
+            submit : this.l10n.submit,
+            cancel : this.l10n.cancel,
+            new_tag : this.l10n.new_tag,
+            delete_tag : this.l10n.delete_tag
+        }
+        this.$.html(Mustache.to_html(this.editTemplate, _data));
+        this.$.find(".Ldt-CurrentSegmentInfobox-CancelButton").click(this.functionWrapper("disableEditMode"));
+        this.$.find(".Ldt-CurrentSegmentInfobox-CreateTagButton").click(this.functionWrapper("insertTagInput"));
+        this.$.find(".Ldt-CurrentSegmentInfobox-Tags-Li-DeleteTagButton").click(this.functionWrapper("deleteTagInput"));
+        this.$.find(".Ldt-CurrentSegmentInfobox-SubmitButton").click(this.functionWrapper("onSubmit"))
+    }
+}
+
+IriSP.Widgets.CurrentSegmentInfobox.prototype.disableEditMode = function() {
+    if(this.currentSegment){
+        data = {
+            title: this.currentSegment.title,
+            description : this.currentSegment.description,
+            tags : this.currentSegment.getTagTexts()
+        }
+        this.$.html(Mustache.to_html(this.template, _data));
+        this.$.find(".Ldt-CurrentSegmentInfobox").click(this.functionWrapper("enableEditMode")); 
+    }
+}
+
+IriSP.Widgets.CurrentSegmentInfobox.prototype.insertTagInput = function() {
+    if((!this.currentSegment.getTagTexts().length)&&(!this.$.find(".Ldt-CurrentSegmentInfobox-Tags-Ul").length)){
+        this.$.find(".Ldt-CurrentSegmentInfobox-Tags").prepend('<ul class="Ldt-CurrentSegmentInfobox-Tags-Ul"></ul>')
+    }
+    this.$.find(".Ldt-CurrentSegmentInfobox-Tags-Ul").append(
+        '<li class="Ldt-CurrentSegmentInfobox-Tags-Li">'
+        +'<input type="text" class="Ldt-CurrentSegmentInfobox-Tags-Li-Input" value=""></input>'
+        +'<div class="Ldt-CurrentSegmentInfobox-Tags-Li-DeleteTagButton">'+this.l10n.delete_tag+'</div>'
+        +'</li>');
+    this.$.find(".Ldt-CurrentSegmentInfobox-Tags-Li-DeleteTagButton").click(this.functionWrapper("deleteTagInput"));
+}
+
+IriSP.Widgets.CurrentSegmentInfobox.prototype.deleteTagInput = function(clickEvent) {
+    $(clickEvent.currentTarget).parent().remove();
+}
+
+IriSP.Widgets.CurrentSegmentInfobox.prototype.onSubmit = function() {
+    new_tags_titles = this.$.find(".Ldt-CurrentSegmentInfobox-Tags-Li-Input").map(function(){
+        if($(this).val()){
+            return $(this).val()
+        }
+    });
+    new_title = this.$.find(".Ldt-CurrentSegmentInfobox-TitleInput").val()
+    new_description = this.$.find(".Ldt-CurrentSegmentInfobox-DescriptionInput").val()
+    
+    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]}),
+        _annotation = new IriSP.Model.Annotation(this.currentSegment.id, _export); /* Création d'une annotation dans cette source avec un ID généré à la volée (param. false) */
+    
+    _annotation.setAnnotationType(this.currentSegment.getAnnotationType().id);
+    _annotation.setMedia(this.currentSegment.getMedia().id);
+    _annotation.setBegin(this.currentSegment.begin);
+    _annotation.setEnd(this.currentSegment.end);
+    _annotation.created = this.currentSegment.created;
+    _annotation.creator = this.currentSegment.creator;
+    _annotation.title = new_title /* Champ titre */
+    _annotation.description = new_description /* Champ description */
+    var _tagIds = IriSP._(new_tags_titles).map(function(_title) {
+        var _tags = _this.source.getTags(true).searchByTitle(_title, true);
+        if (_tags.length) {
+            var _tag = _tags[0];
+        }
+        else {
+            _tag = new IriSP.Model.Tag(_title.replace(/\W/g,'_'), _this.source);
+            _tag.title = _title;
+            _this.source.getTags().push(_tag);
+        }
+        return _tag.id;
+    });
+    _annotation.setTags(_tagIds);
+    _annotation.project_id = this.project_id;
+    
+    _exportedAnnotations.push(_annotation); /* Ajout de l'annotation à la liste à exporter */
+    _export.addList("annotation",_exportedAnnotations); /* Ajout de la liste à exporter à l'objet Source */    
+    
+    _url = Mustache.to_html(this.api_endpoint_template, {annotation_id: this.currentSegment.id});
+    
+    IriSP.jQuery.ajax({
+        url: _url,
+        type: this.api_method,
+        contentType: 'application/json',
+        data: _export.serialize(), /* L'objet Source est sérialisé */
+        success: function(_data) {
+            _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 */
+            _this.segments.forEach(function(_segment){
+                if (_segment.id == _annotation.id){
+                    _this.segments.removeElement(_segment)
+                }
+            })
+            _this.segments.push(_annotation)
+            _this.currentSegment = _annotation
+            _data = {
+                title: _this.currentSegment.title,
+                description : _this.currentSegment.description,
+                tags : _this.currentSegment.getTagTexts()
+            }
+            _this.$.html(Mustache.to_html(_this.template, _data))
+            if(_this.editable_segments&&_this.currentSegment){
+                _this.$.find(".Ldt-CurrentSegmentInfobox").click(_this.functionWrapper("enableEditMode"));             
+            }
+            _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);
+        }
+    });
 }
 
 IriSP.Widgets.CurrentSegmentInfobox.prototype.refresh = function() {
-    var _list = this.segments;
-    
-    _currentTime = this.media.getCurrentTime();
-    _list = _list.filter(function(_segment){
-        return (_segment.begin <= _currentTime && _segment.end >= _currentTime);
-    })
-    if (_list.length > 0){
-        _currentSegment = _list[0];
-        _data = {
-            title: _currentSegment.title,
-            description : _currentSegment.description,
-            tags : _currentSegment.getTagTexts()
+    if(!this.media.getTimeRange()){
+        var _currentTime = this.media.getCurrentTime();
+        var _list = this.segments.filter(function(_segment){
+            return (_segment.begin <= _currentTime && _segment.end >= _currentTime);
+        })
+        
+        if (_list.length > 0){
+            if (this.currentSegment.id != _list[0].id){
+                this.currentSegment = _list[0];
+                _data = {
+                    title: this.currentSegment.title,
+                    description : this.currentSegment.description,
+                    tags : this.currentSegment.getTagTexts()
+                }
+                this.$.html(Mustache.to_html(this.template, _data))
+                if(this.editable_segments&&this.currentSegment){
+                    this.$.find(".Ldt-CurrentSegmentInfobox").click(this.functionWrapper("enableEditMode"));             
+                }
+            }
         }
-        this.$.html(Mustache.to_html(this.template, _data))
+        else {
+            this.currentSegment = false;
+            this.clearBox();
+        }
     }
-    else {
-        var _empty_message = this.l10n.empty
-        if (this.empty_message) {
-            _empty_message = this.empty_message
-        }
-        this.$.find(".Ldt-CurrentSegmentInfobox").html("<div class='Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-NoSegment'>"+_empty_message+"</div>");
+}
+
+IriSP.Widgets.CurrentSegmentInfobox.prototype.clearBox = function(){
+    var _empty_message = this.l10n.empty
+    if (this.empty_message) {
+        _empty_message = this.empty_message
     }
+    this.$.find(".Ldt-CurrentSegmentInfobox").html("<div class='Ldt-CurrentSegmentInfobox-Element Ldt-CurrentSegmentInfobox-NoSegment'>"+_empty_message+"</div>");
 }
\ No newline at end of file
--- a/src/widgets/LatestAnnotation.css	Tue Sep 01 15:24:26 2015 +0200
+++ b/src/widgets/LatestAnnotation.css	Tue Sep 01 15:31:46 2015 +0200
@@ -25,6 +25,8 @@
 }
 
 .Ldt-LatestAnnotation-Content{
+	max-width: 230px;
+	text-align: justify;
 }
 
 .Ldt-LatestAnnotation-Title{
@@ -37,3 +39,26 @@
 	font-size: 14px;
     font-weight: bold;
 }
+
+.Ldt-LatestAnnotation-CopyEditButton{
+	display: inline-block;
+    background-color: #d93c71;
+    color: #ffffff;
+    float: right;
+    cursor: pointer;
+    height: 14px;
+    width: 100px;
+    margin: 2px;
+    padding: 2px;
+    font-size: 11px;
+    border: 1px solid;
+    border-color: #eca3bc #631e34 #36101c #e16e93;
+    cursor: pointer;
+    text-align: center;
+    vertical-align: middle;
+}
+
+.Ldt-LatestAnnotation-CopyEditButton:hover{
+	background-color: #e15581;
+	border-color: #222222 #e87d9f #f0adc3 #68273c;
+}
\ No newline at end of file
--- a/src/widgets/LatestAnnotation.js	Tue Sep 01 15:24:26 2015 +0200
+++ b/src/widgets/LatestAnnotation.js	Tue Sep 01 15:31:46 2015 +0200
@@ -16,31 +16,94 @@
      * Set to a username if you only want to display annotations from a given user
      */
     show_only_annotation_from_user: false,
+    /*
+     * Displays a button that copy currently displayed annotation into CreateAnnotation input field
+     */
+    copy_and_edit_button: false,
+    /*
+     * Allows clicks on an annotation from Annotations to display the annotation content into this widget
+     */
+    selectable_annotations: false,
     empty_message: false,
     starts_hidden: false,
+    show_header: false,
+    custom_header: false,
 };
 
+IriSP.Widgets.LatestAnnotation.prototype.messages = {
+    fr : {
+        copy_and_edit: "Copier et Editer",
+        empty : "Aucune annotation à afficher",
+        header: "Dernière annotation"
+    },
+    en: {
+        copy_and_edit: "Copy and Edit",
+        empty: "No annotation to display",
+        header: "Last annotation"
+    }
+}
+
 IriSP.Widgets.LatestAnnotation.prototype.template = 
-    "<div class='Ldt-LatestAnnotation'>"
+    "{{#show_header}}"
+    + "<p class='Ldt-LatestAnnotation-header'>"
+    +     "{{#custom_header}}{{custom_header}}{{/custom_header}}"
+    +     "{{^custom_header}}{{l10n.header}}{{/custom_header}}"
+    + "</p>"
+    + "{{/show_header}}"
+    + "<div class='Ldt-LatestAnnotation'>"
     + "</div>";
 
 IriSP.Widgets.LatestAnnotation.prototype.annotationTemplate =
     "<div class='Ldt-LatestAnnotation-Box'>"
-    + "    <div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-CreationDate'>{{{annotation_created}}}</div>" 
-    + "    <div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-Title'>{{{annotation_creator}}}{{#annotation_title}}: {{{annotation_title}}}{{/annotation_title}}</div>" 
-    + "    <div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-Content'>"
+    +     "<div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-CreationDate'>{{{annotation_created}}}</div>" 
+    +     "<div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-Title'>{{{annotation_creator}}}{{#annotation_title}}: {{{annotation_title}}}{{/annotation_title}}</div>" 
+    +     "<div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-Content'>"
     +         "{{{annotation_content}}}"
-    + "    </div>"
+    +     "</div>"
+    + "{{#copy_and_edit_button}}<div class='Ldt-LatestAnnotation-CopyEditButton'>{{button_text}}</div>{{/copy_and_edit_button}}"
     + "</div>"
 
+
 IriSP.Widgets.LatestAnnotation.prototype.draw = function(){
     var _this = this;
-    
     this.renderTemplate();
     
     this.annotationContainer_$ = this.$.find('.Ldt-LatestAnnotation');
     
-    this.onMediaEvent("timeupdate", "refresh");
+    if (this.selectable_annotations){
+        this.onMdpEvent("AnnotationsList.refresh", function(){
+            _this.getWidgetAnnotations().forEach(function(_annotation){
+                _annotation.off("click");
+                _annotation.on("click", function(){
+                    _html = Mustache.to_html(_this.annotationTemplate, {
+                        annotation_created: _annotation.created.toLocaleDateString()+", "+_annotation.created.toLocaleTimeString(),
+                        annotation_creator: _annotation.creator,
+                        annotation_title: _annotation.title,
+                        annotation_content: _annotation.description,
+                        copy_and_edit_button: _this.copy_and_edit_button,
+                        button_text: _this.l10n.copy_and_edit,
+                    });
+                    _this.annotationContainer_$.html(_html);
+                    _this.selectedAnnotation = true;
+                });
+            }); 
+        });
+        
+        this.segments = _this.source.getAnnotationsByTypeTitle(this.segments_annotation_type)
+        this.segments.forEach(function(_segment){
+            _segment.on("click", function(){
+                _this.selectedAnnotation = false;
+            })
+        })
+        this.currentSegment = false;
+    }
+    
+    this.onMediaEvent("timeupdate", function(){
+        _this.refresh();
+    });
+    this.onMediaEvent("settimerange", function(_timeRange){
+        _this.refresh(_timeRange);
+    })
     
     if (this.starts_hidden){
         this.visible = true;
@@ -51,40 +114,59 @@
         this.show();
     }
     
+    this.selectedAnnotation = false; // This flag tells the widget if it must display last annotation (false) or clicked annotation (true)
+    this.player.trigger("AnnotationsList.refresh");
     this.refresh();
 }
 
-IriSP.Widgets.LatestAnnotation.prototype.messages = {
-    fr : {
-        empty : "Aucune annotation à afficher"
-    },
-    en: {
-        empty: "No annotation to display"
-    }
-}
 
-IriSP.Widgets.LatestAnnotation.prototype.refresh = function(){ 
-    var _currentTime = this.media.getCurrentTime() 
-    var _segmentsAnnotations = this.source.getAnnotationsByTypeTitle(this.segments_annotation_type)
-    var _currentSegments = _segmentsAnnotations.filter(function(_segment){
-        return (_currentTime >= _segment.begin && _currentTime <= _segment.end)
-    });
+IriSP.Widgets.LatestAnnotation.prototype.refresh = function(_timeRange){
+    _timeRange = typeof _timeRange !== 'undefined' ? _timeRange : false ;
+    var _this = this;
     if (this.hide_without_segment){
-        if (_currentSegments.length == 0){
+        if (!_timeRange && !this.media.getTimeRange()){
+            var _currentTime = this.media.getCurrentTime();
+            var _currentSegments = this.segments.filter(function(_segment){
+                return (_currentTime >= _segment.begin && _currentTime <= _segment.end)
+            });
+            if (_currentSegments.length == 0){
+                this.currentSegment = false;
+                this.selectedAnnotation = false;
+            }
+            else {
+                this.currentSegment = _currentSegments[0]
+            }
+        }
+        else {
+            var _segmentBegin = _timeRange? _timeRange[0] : this.media.getTimeRange()[0],
+                _segmentEnd = _timeRange? _timeRange[1] : this.media.getTimeRange()[1];
+            if ((!this.currentSegment)||(this.currentSegment.begin != _segmentBegin || this.currentSegment.end != _segmentEnd)) {
+                var _currentSegments = this.segments.filter(function(_segment){
+                    return _segment.begin == _segmentBegin && _segment.end == _segmentEnd
+                });
+                if (_currentSegments.length > 0){
+                    this.selectedAnnotation = false;
+                    this.currentSegment = _currentSegments[0];
+                }
+            }
+        }
+        if (!this.currentSegment){
             if (this.visible){
-                this.hide()
+                this.hide();
             }
         }
         else {
             if (!this.visible){
-                this.show()
+                this.show();
             }
         }
     }
-    if (this.visible){
+    
+    if (this.visible && !this.selectedAnnotation){
         var _list = this.getWidgetAnnotations();
+        
         if(this.filter_by_segment){
-            if (_currentSegments.length == 0) {
+            if (!this.currentSegment) {
                 _list = _list.filter(function(_annotation){
                     return false;
                 });
@@ -92,40 +174,56 @@
             else {
                 _list = _list.filter(function(_annotation){
                     _annotationTime = (_annotation.begin+_annotation.end)/2;
-                    return (_currentSegments[0].begin <= _annotationTime && _currentSegments[0].end >= _annotationTime);
+                    return (_this.currentSegment.begin <= _annotationTime && _this.currentSegment.end >= _annotationTime);
                 });
             }
-            _list.sortBy(function(_annotation){
-                return _annotation.created;
+        }
+        _list = _list.sortBy(function(_annotation){
+            return _annotation.created;
+        });
+        
+        var _latestAnnotation = false;
+        var _html="";
+        if (_list.length != 0){
+            _latestAnnotation = _list.pop();
+            _html = Mustache.to_html(this.annotationTemplate, {
+                annotation_created: _latestAnnotation.created.toLocaleDateString()+", "+_latestAnnotation.created.toLocaleTimeString(),
+                annotation_creator: _latestAnnotation.creator,
+                annotation_title: _latestAnnotation.title,
+                annotation_content: _latestAnnotation.description,
+                copy_and_edit_button: this.copy_and_edit_button,
+                button_text: this.l10n.copy_and_edit,
             });
-            
-            var _latestAnnotation = false;
-            var _html="";
-            if (_list.length != 0){
-                _latestAnnotation = _list.pop();
-                _html = Mustache.to_html(this.annotationTemplate, {
-                    annotation_created: _latestAnnotation.created.toLocaleDateString()+", "+_latestAnnotation.created.toLocaleTimeString(),
-                    annotation_creator: _latestAnnotation.creator,
-                    annotation_title: _latestAnnotation.title,
-                    annotation_content: _latestAnnotation.description,
-                });
+        }
+        else {
+            var _empty_message = this.l10n.empty
+            if (this.empty_message) {
+                _empty_message = this.empty_message
             }
-            else {
-                var _empty_message = this.l10n.empty
-                if (this.empty_message) {
-                    _empty_message = this.empty_message
-                }
-                _html = "<div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-NoAnnotation'>"+_empty_message+"</div>";
-            }
-            this.annotationContainer_$.html(_html);
-            
+            _html = "<div class='Ldt-LatestAnnotation-Element Ldt-LatestAnnotation-NoAnnotation'>"+_empty_message+"</div>";
         }
+        this.annotationContainer_$.html(_html);    
     }
+
+    if(this.copy_and_edit_button){
+        this.copyAndEditButton_$ = this.$.find('.Ldt-LatestAnnotation-CopyEditButton');
+        this.copyAndEditButton_$.click(this.functionWrapper("copy_and_edit"));
+    }
+}
+
+IriSP.Widgets.LatestAnnotation.prototype.copy_and_edit = function(){
+    this.player.trigger("CreateAnnotation.show");
+    this.player.trigger("AnnotationsList.hide");
+    annotationText = $('.Ldt-LatestAnnotation-Content').get(0).innerHTML;
+    
+    $('.Ldt-CreateAnnotation-Description').removeClass('empty');
+    $('.Ldt-CreateAnnotation-Description').val(annotationText);
 }
 
 IriSP.Widgets.LatestAnnotation.prototype.hide = function() {
     if (this.visible){
         this.visible = false;
+        this.$.find('.Ldt-LatestAnnotation-header').hide();
         this.annotationContainer_$.hide()
     }
 }
@@ -133,6 +231,7 @@
 IriSP.Widgets.LatestAnnotation.prototype.show = function() {
     if(!this.visible){
         this.visible = true;
+        this.$.find('.Ldt-LatestAnnotation-header').show();
         this.annotationContainer_$.show()
     }
 }
Binary file src/widgets/img/loader.gif has changed