integration/js/editor.js
changeset 41 3ec2343f2b85
parent 39 d3d8a88878ed
child 42 40909e8d6855
--- a/integration/js/editor.js	Tue Nov 06 18:49:13 2012 +0100
+++ b/integration/js/editor.js	Thu Nov 08 18:24:47 2012 +0100
@@ -13,8 +13,7 @@
     mashup_title_placeholder: "Hashcut sans titre"
 }
 
-IriSP.Hashcut = function(options) {
-    
+IriSP.editor = function(options) {
     
     /* Load Media List */
     
@@ -24,48 +23,60 @@
             serializer: IriSP.serializers.medialist
         }),
         mashup = new IriSP.Model.Mashup(false, project),
-        mediatemplate = _.template('<li class="item-video" data-media-id="<%= id %>"><img src="<%= thumbnail %>" alt="<%= title %>" />'
+        mediatemplate = _.template('<li class="item-video media" data-media-id="<%= id %>"><img src="<%= thumbnail %>" alt="<%= title %>" />'
             + '<span class="video-info"><span class="title-video"><%= title %></span><span class="author"><%= description %></span>'
             + '<span class="time-length"><%= IriSP.hc_messages.Duration_ %> <span><%= duration.toString() %></span></span></span></li>'),
-        segmenttemplate = _.template('<li class="item-video" data-segment-id="<%= annotation.id %>" data-media-id="<%= annotation.getMedia().id %>">'
+        segmenttemplate = _.template('<li class="item-video annotation" data-segment-id="<%= annotation.id %>" data-media-id="<%= annotation.getMedia().id %>">'
             + '<img src="<%= annotation.getMedia().thumbnail %>" alt="<%= annotation.getMedia().title %>" />'
             + '<div class="validate <%= annotation.status %>"><div class="validate-tooltip"><ul><li><%= annotation.status_messages.join("</li><li>") %></li></ul></div></div><span class="video-info"><span class="title-video"><%= annotation.getMedia().title %></span>'
             + '<span class="subtitle"><%= annotation.title %></span><span class="duration"><%= annotation.begin.toString() %> - <%= annotation.end.toString() %> (<%= annotation.getDuration().toString() %>)</span>'
             + '<ul class="tools"><li><a class="edit" href="#" title="<%= IriSP.hc_messages.edit_segment %>"></a></li><li><a class="bottom" href="#" title="<%= IriSP.hc_messages.segment_down %>"></a></li>'
             + '<li><a class="top" href="#" title="<%= IriSP.hc_messages.segment_up %>"></a></li><li><a class="delete" href="#" title="<%= IriSP.hc_messages.delete_segment %>"></a></li></ul></span></li>'),
-        viztemplate = _.template('<div class="frise-segment" data-segment-id="<%= segmentid %>" style="background-color:<%= color %>; left:<%= left %>%; width:<%= width %>%;"></div>'),
-        intervaltemplate = _.template('<span class="frise-indication" style="left:<%= left %>%;"><%= time.toString() %></span>'),
         mediasegmenttemplate = _.template('<div class="media-segments-list"><div class="media-segment">'
-            + '<div class="media-section media-segment-section" style="left:<%= left %>px; width:<%= width %>px; background:<%= annotation.getMedia().color %>"></div>'
+            + '<div class="media-section media-segment-section" style="left:<%= left %>px; width:<%= width %>px; background:<%= annotation.color %>"></div>'
             + '<div class="media-section media-current-section" style="left:<%= currentleft %>px; width:<%= currentwidth %>px;"><div class="media-current-section-inner"></div></div>'
             + '<div class="popin media-segment-popin" style="left:<%= popleft %>px"><img style="left:<%= pointerpos %>px;" class="pointer" src="img/popin-triangle.png" alt="" /><div class="popin-content">'
             + '<h3><%= annotation.title %></h3><a href="#" class="button reprendre-segment" data-segment-id="<%= annotation.id %>"><%= IriSP.hc_messages.clone_segment %></a>'
             + '<p><%= IriSP.hc_messages.From_ %> <span><%= annotation.begin.toString() %></span> <%= IriSP.hc_messages.to_ %> <span><%= annotation.end.toString() %></span> (<%= IriSP.hc_messages.duration_ %> <span><%= annotation.getDuration().toString() %></span>)</p>'
-            + '</div></div></div></div>');
+            + '</div></div></div></div>'),
+        addMode, currentMedia, currentSegment;
+    
+    IriSP.mashupcore(project, mashup);
     
     /* Validation of segments and mashup */
     
     var segmentcritical = [
         {
             validate: function(_s) {
-                var _d = _s.getDuration();
-                return (_d > 1000 && _d < 180000);
+                return (_s.getDuration() >= 1000);
             },
-            message: "La durée du segment doit être comprise entre 1 seconde et trois minutes"
+            message: "Le segment doit durer au moins une seconde"
+        },
+        {
+            validate: function(_s) {
+                return (_s.getDuration() < 180000);
+            },
+            message: "Le segment doit durer moins de trois minutes"
         },
         {
             validate: function(_s) {
                 return (!!_s.title && _s.title !== IriSP.hc_messages.segment_title_placeholder);
             },
-            message: "Un titre doit être donné au segment"
+            message: "Le segment doit avoir un titre"
         }
     ];
     var segmentwarning = [
         {
             validate: function(_s) {
-                return (_s.description);
+                return (!!_s.description);
             },
             message: "Il est recommandé de donner une description au segment"
+        },
+        {
+            validate: function(_s) {
+                return (!!_s.keywords.length);
+            },
+            message: "Il est recommandé de tagguer le segment"
         }
     ];
     
@@ -129,30 +140,14 @@
     });
     
     /* Fill right column when mashup is updated */
-   
-    function setPointerToCurrentAnnotation() {
-        if (mashupCurrentAnnotation) {
-            var p = (mashupCurrentAnnotation.begin + mashupCurrentAnnotation.end) / (2 * mashup.duration);
-            $(".mashup-description .pointer").css("left", (100 * p) + "%");
-        }
-    }
     
     function updateMashupUI() {
-        var listhtml = '', vizhtml = '', t = 0, k = mashup.duration ? (100 / mashup.duration) : 0;
-        var critical = false, warning = false, messages = [];
+        var listhtml = '', critical = false, warning = false, messages = [];
         mashup.segments.forEach(function(_s) {
             listhtml += segmenttemplate(_s);
-            var vizdata = {
-                left: k * t,
-                width: k * _s.duration,
-                color: _s.getMedia().color,
-                segmentid: _s.annotation.id
-            }
-            vizhtml += viztemplate(vizdata);
             if (_s.annotation.status === "critical") {
                 critical = true;
             }
-            t += _s.duration.milliseconds;
         });
         if (critical) {
             messages.push("Certains segments ne sont pas valides");
@@ -179,217 +174,22 @@
         $(".liste-segment .validate").removeClass("critical warning valid").addClass(mashup.status);
         $(".liste-segment .validate-tooltip").html("<ul><li>" + messages.join("</li><li>")+"</li></ul>");
         
-        var intervals = [ 1000, 2000, 5000, 10000, 30000, 60000, 120000, 300000, 600000, 900000, 1800000, 3600000, 7200000 ];
-        
-        function createIntervals(maxn) {
-            for (var i = 0; i < intervals.length; i++) {
-                if (mashup.duration / intervals[i] <= maxn) {
-                    var html = '';
-                    for (var j = intervals[i]; j < mashup.duration; j += intervals[i]) {
-                        html += intervaltemplate({ left: k * j, time: new IriSP.Model.Time(j) });
-                    }
-                    return html;
-                }
-            }
-            return "";
-        }
+        $(".col-right .list-video").html(listhtml).find(".item-video:last-child .bottom, .item-video:first-child .top").addClass("disable");
         
-        $(".col-right .list-video").html(listhtml).find(".item-video:last-child .bottom, .item-video:first-child .top").addClass("disable");
-        $(".mashup-total-duration").text(mashup.duration.toString());
-        $(".frise-segments").html(vizhtml);
-        $(".col-right .frise-indications").html(createIntervals(4));
-        $(".bloc-pvw .frise-indications").html(createIntervals(8));
-        highlightCurrentSegment();
-        if (currentMedia === mashup) {
-            $(".Ldt-Ctrl-Time-Total").text(currentMedia.duration.toString());
-            if (mashupTimecode > mashup.duration) {
-                mashup.setCurrentTime(mashup.duration);
-            }
-            changeCurrentAnnotation();
-            setPointerToCurrentAnnotation();
-        }
-    }
-    
-    mashup.on("change",updateMashupUI);
-    
-    /* Slider */
-   
-    var timeSlider = $(".Ldt-Slider"),
-        timeSliderContainer = $(".Ldt-Slider-Container"),
-        slidersRange = 920;
-    timeSlider.slider({
-        range: "min",
-        value: 0,
-        min: 0,
-        max: slidersRange,
-        slide: function(event, ui) {
-            if (currentMedia) {
-                var t = currentMedia.duration * ui.value / slidersRange;
-                currentMedia.setCurrentTime(t);
-            }
-        }
-    });
-    
-    var timeSliderHandle = timeSlider.find('.ui-slider-handle'),
-        timeSliderMaximized = false,
-        timeSliderTimeoutId = false,
-        timeSliderMinimizedHeight = 4,
-        timeSliderMaximizedHeight = 10,
-        timeSliderTimeoutDuration = 1500,
-        timeTooltip = $(".Ldt-Slider-Time");
-    
-    timeSliderContainer.css(calculateSliderCss(timeSliderMinimizedHeight));
-    timeSliderHandle.css(calculateHandleCss(timeSliderMinimizedHeight));
-    
-    function timeSliderMouseOver() {
-        if (timeSliderTimeoutId) {
-            window.clearTimeout(timeSliderTimeoutId);
-            timeSliderTimeoutId = false;
-        }
-        if (!timeSliderMaximized) {
-           timeSliderAnimateToHeight(timeSliderMaximizedHeight);
-           timeSliderMaximized = true;
-        }
-    }
-    
-    function timeSliderMouseOut() {
-        timeTooltip.hide();
-        if (timeSliderTimeoutId) {
-            clearTimeout(timeSliderTimeoutId);
-            timeSliderTimeoutId = false;
-        }
-        timeSliderTimeoutId = setTimeout(function() {
-            if (timeSliderMaximized) {
-                timeSliderAnimateToHeight(timeSliderMinimizedHeight);
-                timeSliderMaximized = false;
-            }
-            timeSliderTimeoutId = false;
-        }, timeSliderTimeoutDuration);
+        project.trigger("mouseout-annotation");
     }
     
-    timeSliderContainer
-        .mouseover(function() {
-            timeTooltip.show();
-            timeSliderMouseOver();
-        })
-        .mouseout(timeSliderMouseOut);
-    timeSlider.mousemove(function(_e) {
-            var _x = _e.pageX - timeSlider.offset().left,
-                _t = new IriSP.Model.Time(
-                );
-            timeTooltip.text(_t.toString()).css("left",_x);
-        });
-    
-    $(".Ldt-Ctrl").mouseover(timeSliderMouseOver).mouseout(timeSliderMouseOut);
-    
-    function timeSliderAnimateToHeight(_height) {
-        timeSliderContainer.stop().animate(
-            calculateSliderCss(_height),
-            500,
-            function() {
-                IriSP.jQuery(this).css("overflow","visible");
-            });
-        timeSliderHandle.stop().animate(
-            calculateHandleCss(_height),
-            500,
-            function() {
-                IriSP.jQuery(this).css("overflow","visible");
-            });
-    }
-
-    function calculateSliderCss(_size) {
-        return {
-            height: _size + "px",
-            "margin-top": (timeSliderMinimizedHeight - _size) + "px"
-        };
-    }
-
-    function calculateHandleCss(_size) {
-        return {
-            height: (2 + _size) + "px",
-            width: (2 + _size) + "px",
-            "margin-left": -Math.ceil(2 + _size / 2) + "px" 
-        }
-    }
-    
-    /* Controller Widget */
-   
-    var volBlock = $(".Ldt-Ctrl-Volume-Control");
-    
-    $('.Ldt-Ctrl-Sound')
-        .click(function() {
-            if (currentMedia) {
-                currentMedia.setMuted(!currentMedia.getMuted());
-            }
-        })
-        .mouseover(function() {
-            volBlock.show();
-        })
-        .mouseout(function() {
-            volBlock.hide();
-        });
-    volBlock.mouseover(function() {
-        volBlock.show();
-    }).mouseout(function() {
-        volBlock.hide();
+    mashup.on("setcurrent", function() {
+        currentMedia = mashup;
     });
     
-    var volBar = $(".Ldt-Ctrl-Volume-Bar");
-    
-    function ctrlVolumeUpdater() {
-        if (currentMedia) {
-            var _muted = currentMedia.getMuted(),
-                _vol = currentMedia.getVolume();
-            if (_vol === false) {
-                _vol = .5;
-            }
-            var _soundCtl = $(".Ldt-Ctrl-Sound");
-            _soundCtl.removeClass("Ldt-Ctrl-Sound-Mute Ldt-Ctrl-Sound-Half Ldt-Ctrl-Sound-Full");
-            if (_muted) {        
-                _soundCtl.attr("title", "Activer le son")
-                    .addClass("Ldt-Ctrl-Sound-Mute");    
-            } else {
-                _soundCtl.attr("title", "Couper le son")
-                    .addClass(_vol < .5 ? "Ldt-Ctrl-Sound-Half" : "Ldt-Ctrl-Sound-Full" )
-            }
-            volBar.slider("value", _muted ? 0 : 100 * _vol);
-            volBar.attr("title",'Volume : ' + Math.floor(100 * _vol) + '%');
-        }
-    }
-    
-    volBar.slider({
-        slide: function(event, ui) {
-            if (currentMedia) {
-                currentMedia.setVolume(ui.value / 100);
-            }
-        }
-    });
-    
-    $(".Ldt-Ctrl-Play").click(function() {
-        if (currentMedia) {
-            if (currentMedia.getPaused()) {        
-                currentMedia.play();
-            } else {
-                currentMedia.pause();
-            }
-        }
-    });
-    
-    $(".Ldt-Ctrl-SetIn").click(function() {
-        if (currentMedia && currentSegment) {
-            currentSegment.setBegin(currentMedia.getCurrentTime());
-        }
-    });
-    $(".Ldt-Ctrl-SetOut").click(function() {
-        if (currentMedia && currentSegment) {
-            currentSegment.setEnd(currentMedia.getCurrentTime());
-        }
-    });
+    mashup.on("change",updateMashupUI);
     
     /* Slice Widget */
    
     var sliceSlider = $(".Ldt-Slice"),
-        sliceStartTime;
+        sliceStartTime,
+        slidersRange = 920;
     
     sliceSlider.slider({
         range: true,
@@ -430,93 +230,8 @@
             }
         });
     
-    /* UI Events */
-
-    function onCurrentMediaPlay() {
-        $(".Ldt-Ctrl-Play")
-            .attr("title", "Pause")
-            .removeClass("Ldt-Ctrl-Play-PlayState")
-            .addClass("Ldt-Ctrl-Play-PauseState")
-    }
     
-    function onCurrentMediaPause() {
-        $(".Ldt-Ctrl-Play")
-            .attr("title", "Lecture")
-            .removeClass("Ldt-Ctrl-Play-PauseState")
-            .addClass("Ldt-Ctrl-Play-PlayState")
-    }
-    
-    function onCurrentMediaTimeupdate(_time) {
-        $(".Ldt-Ctrl-Time-Elapsed").text(_time.toString());
-        timeSlider.slider("value",slidersRange * _time / currentMedia.duration);
-    }
-    
-    /* Mashup Player */
-
-    var mashupCurrentMedia = null,
-        mashupCurrentAnnotation = null,
-        mashupSegmentBegin,
-        mashupSegmentEnd,
-        mashupTimecode = 0,
-        mashupSeeking = false,
-        seekdiv = $(".video-wait"),
-        mashupTimedelta;
-    
-    function showSeek() {
-        if (mashupSeeking) {
-            seekdiv.show();
-        }
-    }
-    
-    function changeCurrentAnnotation() {
-        if (mashupTimecode >= mashup.duration) {
-            if (!mashup.paused) {
-                mashup.paused = true;
-                mashup.trigger("pause");
-            }
-            mashupTimecode = 0;
-        }
-        var _annotation = mashup.getAnnotationAtTime( mashupTimecode );
-        if (typeof _annotation === "undefined") {
-            if (mashupCurrentMedia) {
-                mashupCurrentMedia.pause();
-                if (!mashup.paused) {
-                    mashup.paused = true;
-                    mashup.trigger("pause");
-                }
-            }
-            return;
-        }
-        mashupCurrentAnnotation = _annotation;
-        mashupSegmentBegin = mashupCurrentAnnotation.annotation.begin.milliseconds;
-        mashupSegmentEnd = mashupCurrentAnnotation.annotation.end.milliseconds;
-        mashupTimedelta = mashupSegmentBegin - mashupCurrentAnnotation.begin.milliseconds;
-        mashupCurrentMedia = mashupCurrentAnnotation.getMedia();
-        
-        project.getMedias().forEach(function(_media) {
-            if (_media !== mashupCurrentMedia) {
-                _media.hide();
-                _media.pause();
-            } else {
-                _media.show();
-            }
-        });
-        
-        mashupCurrentMedia.setCurrentTime( mashupTimecode + mashupTimedelta);
-        mashupCurrentMedia.seeking = true;
-        
-        if (!mashup.paused) {
-            mashupCurrentMedia.play();
-            mashupSeeking = true;
-            setTimeout(showSeek,200);
-        }
-        mashup.trigger("timeupdate", new IriSP.Model.Time(mashupTimecode));
-
-    }
-    
-    /* Set current Media */
-   
-    var currentMedia, currentSegment;
+    /* Update Segment UI */
     
     function updateSegmentUI() {
         if (currentMedia && currentSegment) {
@@ -564,23 +279,14 @@
         }
     }
     
-    var addMode;
-    
     function setMedia(media) {
         if (currentMedia) {
             currentMedia.pause();
         }
         currentMedia = media;
+        project.trigger("set-current", media);
         if (currentMedia.elementType == "media") {
-            $("video").hide();
             showSegmentation();
-            if (!currentMedia.loaded) {
-                seekdiv.show();
-            }
-            var currentvideo = $('#video_' + currentMedia.id);
-            if (!currentvideo.length) {
-                addMediaPlayer(currentMedia);
-            }
             $(".tab-media-title").text(currentMedia.title);
             
             addMode = !(currentSegment && mashup.hasAnnotation(currentSegment));
@@ -591,6 +297,8 @@
                 currentSegment.setBegin(0);
                 currentSegment.setEnd(currentMedia.duration);
                 currentSegment.title = IriSP.hc_messages.segment_title_placeholder;
+                currentSegment.color = currentMedia.color;
+                currentSegment.keywords = [];
                 currentSegment.description = "";
                 currentSegment.on("change-begin", function() {
                     if (currentMedia && currentSegment === this) {
@@ -604,28 +312,25 @@
                         updateSegmentUI();
                     }
                 });
-                currentSegment.on("enter", function() {
-                    if (currentMedia === mashup) {
-                        $(".annotation-title").text(this.title);
-                        $(".annotation-begin").text(this.begin.toString());
-                        $(".annotation-end").text(this.end.toString());
-                        $(".annotation-media-title").text(this.getMedia().title);
-                        $(".annotation-description").text(this.description);
-                        setPointerToCurrentAnnotation();
-                        highlightCurrentSegment();
-                    }
-                });
             }
             if (currentMedia.loaded) {
                 currentMedia.setCurrentTime(currentSegment.begin);
             }
             $(".add-segment").val(addMode ? "Ajouter au Hashcut" : "Sauvegarder");
             $(".create-or-edit").text(addMode ? "Créer un nouveau segment" : "Modifier le segment");
-            updateSegmentUI();
             media.show();
             $("#segment-title").val(currentSegment.title);
             $("#segment-description").val(currentSegment.description);
-            $("#segment-tags").val("");
+            var segment_tags = $("#segment-tags");
+            segment_tags.tagit("option","onTagRemoved",function(){});
+            segment_tags.tagit("option","onTagAdded",function(){});
+            segment_tags.tagit("removeAll");
+            _(currentSegment.keywords).each(function(tag) {
+                segment_tags.tagit("createTag",tag);
+            });
+            segment_tags.tagit("option","onTagRemoved",updateSegmentTags);
+            segment_tags.tagit("option","onTagAdded",updateSegmentTags);
+            updateSegmentUI();
             var relatedSegments = mashup.segments.filter(function(_s) {
                 return _s.getMedia() === currentMedia && _s.annotation !== currentSegment;
             });
@@ -652,254 +357,15 @@
             } else {
                 $(".self-media-segments").hide();
             }
+            
+            //TODO: Show Related Segments from http://capsicum/pf/ldtplatform/api/ldt/1.0/segments/bytimecode/f72aa2f4-29bb-11e2-a193-08002791f1b7/0/674000?format=json
+            
         }
         $(".self-media-segments .media-segments-list").html(html);
         if (currentMedia.elementType === "mashup") {
             showPreview();
-            mashup.checkLoaded();
         }
-        $(".Ldt-Ctrl-Time-Total").text(currentMedia.duration.toString());
-        // TODO: Do something with the tags !
-        onCurrentMediaTimeupdate(currentMedia.getCurrentTime());
-        onCurrentMediaPause();
-        highlightCurrentSegment();
     }
-    
-    function addMediaPlayer(media) {
-        var videoid = "video_" + media.id,
-            videoEl = $('<video>'),
-            width = $(".video").width(),
-            height = $(".video").height(),
-            mp4_file = media.video.replace(/\.webm$/i,'.mp4'),
-            webm_file = media.video.replace(/\.mp4$/i,'.webm'),
-            mp4_src = $('<source>'),
-            webm_src = $('<source>');
-        mp4_src.attr({
-            src: mp4_file,
-            type: "video/mp4"
-        });
-        webm_src.attr({
-            src: webm_file,
-            type: "video/webm"
-        });
-        videoEl.attr({
-            id : videoid,
-            width : width,
-            height : height
-        }).css({
-            position : "absolute",
-            left: 0,
-            top: 0,
-            width : width,
-            height : height
-        });
-        videoEl.append(mp4_src).append(webm_src);
-        $(".video").append(videoEl);
-        
-        media.show = function() {
-            videoEl.show();
-        }
-        media.hide = function() {
-            videoEl.hide();
-        }
-        
-        var popcorn = Popcorn("#" + videoid);
-        
-        // Binding functions to Popcorn
-        
-        media.on("setcurrenttime", function(_milliseconds) {
-            if (media.loaded) {
-                popcorn.currentTime(_milliseconds / 1000);
-            }
-        });
-        
-        media.on("setvolume", function(_vol) {
-            media.volume = _vol;
-            if (media.loaded) {
-                popcorn.volume(_vol);
-            }
-        });
-        
-        media.on("setmuted", function(_muted) {
-            media.muted = _muted;
-            if (media.loaded) {
-                popcorn.muted(_muted);
-            }
-        });
-        
-        media.on("setplay", function() {
-            if (media.loaded) {
-                popcorn.play();
-            }
-        });
-        
-        media.on("setpause", function() {
-            if (media.loaded) {
-                popcorn.pause();
-            }
-        });
-        
-        // Binding Popcorn events to media
-        
-        function getVolume() {
-            media.muted = popcorn.muted();
-            media.volume = popcorn.volume();
-        }
-        
-        popcorn.on("loadedmetadata", function() {
-            getVolume();
-            media.loaded = true;
-            media.trigger("loadedmetadata");
-            media.trigger("volumechange");
-        })
-        
-        popcorn.on("timeupdate", function() {
-            media.trigger("timeupdate", new IriSP.Model.Time(1000*popcorn.currentTime()));
-        });
-        
-        popcorn.on("volumechange", function() {
-            getVolume();
-            media.trigger("volumechange");
-        })
-        
-        popcorn.on("play", function() {
-            media.trigger("play");
-        });
-        
-        popcorn.on("pause", function() {
-            media.trigger("pause");
-        });
-        
-        popcorn.on("seeked", function() {
-            media.trigger("seeked");
-        });
-        
-        // Binding UI Events and Mashup Playing to Media
-        
-        media.on("loadedmetadata", function() {
-            if (media === currentMedia) {
-                seekdiv.hide();
-            }
-            mashup.checkLoaded();
-        });
-        
-        media.on("play", function() {
-            if (media === currentMedia) {
-                onCurrentMediaPlay();
-            }
-            if (mashup === currentMedia && media === mashupCurrentMedia) {
-                mashup.trigger("play");
-            }
-        });
-        
-        media.on("pause", function() {
-            if (media === currentMedia) {
-                onCurrentMediaPause();
-            }
-            if (mashup === currentMedia && media === mashupCurrentMedia) {
-                mashup.trigger("pause");
-            }
-        });
-        
-        media.on("timeupdate", function(_time) {
-            if (media === currentMedia) {
-                onCurrentMediaTimeupdate(_time);
-            }
-            if (mashup === currentMedia && !mashup.paused && media === mashupCurrentMedia && !media.seeking) {
-                if ( _time < mashupSegmentEnd ) {
-                    if ( _time >= mashupSegmentBegin ) {
-                        mashupTimecode = _time - mashupTimedelta;
-                    } else {
-                        mashupTimecode = mashupSegmentBegin - mashupTimedelta;
-                        media.setCurrentTime(mashupSegmentBegin);
-                    }
-                } else {
-                    mashupTimecode = mashupSegmentEnd - mashupTimedelta;
-                    media.pause();
-                    changeCurrentAnnotation();
-                }
-                mashup.trigger("timeupdate", new IriSP.Model.Time(mashupTimecode));
-            }
-        });
-        
-        media.on("seeked", function() {
-            media.seeking = false;
-            if (mashup === currentMedia && media === mashupCurrentMedia && mashupSeeking) {
-                mashupSeeking = false;
-                seekdiv.hide();
-            }
-        });
-        
-        media.on("volumechange", function() {
-            if (media === currentMedia) {
-                ctrlVolumeUpdater();
-            }
-            mashup.muted = media.muted;
-            mashup.volume = media.volume;
-            mashup.trigger("volumechange");
-        })
-        
-    }
-
-    // Mashup Events
-    
-    mashup.on("setcurrenttime", function(_milliseconds) {
-        mashupTimecode = _milliseconds;
-        changeCurrentAnnotation();
-    });
-    
-    mashup.on("setvolume", function(_vol) {
-        mashup.getMedias().forEach(function(_media) {
-            _media.setVolume(_vol);
-        });
-        mashup.volume = _vol;
-    });
-    
-    mashup.on("setmuted", function(_muted) {
-        mashup.getMedias().forEach(function(_media) {
-            _media.setMuted(_muted);
-        });
-        mashup.muted = _muted;
-    });
-    
-    mashup.on("setplay", function() {
-        mashup.paused = false;
-        changeCurrentAnnotation();
-    });
-    
-    mashup.on("setpause", function() {
-        mashup.paused = true;
-        if (mashupCurrentMedia) {
-            mashupCurrentMedia.pause();
-        }
-    });
-    
-    mashup.on("loadedmetadata", function() {
-        if (mashup === currentMedia) {
-            changeCurrentAnnotation();
-        }
-    });
-    
-    /* Mashup Events to UI */
-   
-    mashup.on("play", function() {
-        if (mashup === currentMedia) {
-            onCurrentMediaPlay();
-        }
-    });
-    
-    mashup.on("pause", function() {
-        if (mashup === currentMedia) {
-            onCurrentMediaPause();
-        }
-    });
-    
-    mashup.on("timeupdate", function(_time) {
-        if (mashup === currentMedia) {
-            $(".frise-position").css("left",(100*_time/mashup.duration)+"%");
-            onCurrentMediaTimeupdate(_time);
-        }
-    });
         
     /* Segment Form interaction */
    
@@ -907,29 +373,43 @@
         if (currentMedia && currentSegment) {
             currentSegment.title = $(this).val();
             updateSegmentUI();
-            updateMashupUI();
+            mashup.trigger("change");
         }
     });
     $("#segment-description").on("keyup change input paste", function() {
         if (currentMedia && currentSegment) {
             currentSegment.description = $(this).val();
-            updateSegmentUI();
+            mashup.trigger("change");
         }
     });
     $("#segment-form").submit(function() {
         if (addMode) {
             mashup.addAnnotation(currentSegment);
         } else {
-            updateMashupUI();
+            mashup.trigger("change");
         }
         var segment = mashup.getAnnotation(currentSegment);
         currentSegment = undefined;
         setMedia(mashup);
         if (segment) {
             mashup.setCurrentTime(segment.begin);
+            mashup.trigger("enter-annotation",segment);
         }
         return false;
-    })
+    });
+    
+    $("#segment-tags").tagit();
+    
+    
+    /* We have to defer this function because the tagit events
+     * are triggered before the data are updated */
+    function updateSegmentTags() {
+        window.setTimeout(function() {
+            if (currentMedia && currentSegment) {
+                currentSegment.keywords = $("#segment-tags").tagit("assignedTags");
+            }
+        }, 0);
+    }
     
     /* Click on media items */
    
@@ -967,50 +447,40 @@
         mashup.setAnnotationsById(ids);
     }
     
-    function highlightCurrentSegment() {
-        $(".organize-segments .item-video, .col-left .item-video, .frise-segment").removeClass("active");
-        var segmentid = undefined;
-        if (currentMedia && currentSegment) {
-            segmentid = currentSegment.id;
-        }
-        if (currentMedia === mashup && mashupCurrentAnnotation) {
-            segmentid = mashupCurrentAnnotation.annotation.id;
-        }
-        $(".item-video[data-segment-id='" + segmentid + "']").addClass("active");
+    project.on("mouseover-annotation", function(annotation) {
+        var mediaid = annotation.getMedia().id;
+        $(".media").removeClass("active");
+        $(".media[data-media-id='" + mediaid + "']").addClass("active");
+    });
+    
+    project.on("mouseout-annotation", function(annotation) {
+        $(".media").removeClass("active");
         var mediaid = undefined;
-        if (currentMedia) {
+        if (currentMedia && currentMedia.elementType === "media") {
             mediaid = currentMedia.id;
+            if (currentSegment) {
+                $(".annotation").removeClass("active");
+                $(".annotation[data-segment-id='" + currentSegment.id + "']").addClass("active");
+            }
         }
-        if (currentMedia === mashup && mashupCurrentMedia) {
-            mediaid = mashupCurrentMedia.id
+        if (currentMedia === mashup && mashup.currentMedia) {
+            mediaid = mashup.currentMedia.id
         }
-        $(".col-left .item-video[data-media-id='" + mediaid + "']").addClass("active");
-    }
-    
-    function hoverSegment() {
-        var segmentid = $(this).attr("data-segment-id");
-        $(".organize-segments .item-video, .frise-segment").removeClass("active");
-        $(".item-video[data-segment-id='" + segmentid + "'], .frise-segment[data-segment-id='" + segmentid + "']").addClass("active");
-    }
-    
-    $(".frise")
-    .on("mouseover", ".frise-segment", hoverSegment)
-    .on("mouseout", ".frise-segment", highlightCurrentSegment)
+        $(".media[data-media-id='" + mediaid + "']").addClass("active");
+    });
     
     $(".organize-segments")
     .sortable({
         stop : reorganizeMashup
     })
-    .on("mouseover", ".item-video", hoverSegment)
-    .on("mouseout", ".item-video", highlightCurrentSegment)
-    .on("click", ".item-video", function(e) {
-        var el = $(this),
-            segment = mashup.getAnnotationById(el.attr("data-segment-id"));
-        setMedia(mashup);
-        if (segment) {
-            mashup.setCurrentTime(segment.begin);
-        }
-        return false;
+    .on("mouseover", ".item-video", function() {
+        project.trigger("mouseover-annotation", project.getElement($(this).attr("data-segment-id")));
+    })
+    .on("mouseout", ".item-video", function() {
+        project.trigger("mouseout-annotation");
+    })
+    .on("click", ".item-video", function() {
+        project.trigger("click-annotation", project.getElement($(this).attr("data-segment-id")));
     })
     .on("click", ".edit", function(e) {
         var currentItem = $(this).parents(".item-video"),
@@ -1130,6 +600,11 @@
     
     /* Changing Hashcut Title and description */
     
+    $("#hashcut-tags").tagit({
+        onTagRemoved: updateSegmentTags,
+        onTagAdded: updateSegmentTags
+    });
+    
     mashup.title = IriSP.hc_messages.mashup_title_placeholder;
     $(".title-video-wrap a").text(mashup.title);
     $("#hashcut-title").val(mashup.title);
@@ -1137,13 +612,19 @@
     $("#hashcut-title").on("keyup change input paste", function() {
         mashup.title = $(this).val();
         $(".title-video-wrap a").text(mashup.title);
-        updateMashupUI();
+        mashup.trigger("change");
     });
     
     $("#hashcut-description").on("keyup change input paste", function() {
         mashup.description = $(this).val();
-        updateMashupUI();
+        mashup.trigger("change");
     });
     
-    updateMashupUI();
+    function updateMashupTags() {
+        window.setTimeout(function() {
+            mashup.keywords = $("#segment-tags").tagit("assignedTags");
+        }, 0);
+    }
+    
+    mashup.trigger("change");
 }