Finished Mediafragment new-model
authorveltr
Fri, 27 Apr 2012 19:18:21 +0200
branchnew-model
changeset 881 f11b234497f7
parent 880 4c7b33bf2795
child 882 61c384dda19e
Finished Mediafragment
src/js/init.js
src/js/model.js
src/js/modules/mediafragment.js
src/js/widgets/sliceWidget.js
src/js/widgets/tagCloudWidget.js
src/js/widgets/tweetsWidget.js
src/widgets/CreateAnnotation.js
src/widgets/Mediafragment.js
src/widgets/Polemic.js
src/widgets/Segments.js
src/widgets/Slider.js
--- a/src/js/init.js	Thu Apr 26 19:18:57 2012 +0200
+++ b/src/js/init.js	Fri Apr 27 19:18:21 2012 +0200
@@ -44,7 +44,7 @@
 
     /* widget specific requirements */
     for(var _i = 0; _i < this.config.gui.widgets.length; _i++) {
-        if(this.config.gui.widgets[_i].type === "Sparkline") {
+        if(this.config.gui.widgets[_i].type === "Sparkline" || this.config.gui.widgets[_i].type === "Arrow") {
             $L.script(IriSP.getLib("raphael"));
         }
         if(this.config.gui.widgets[_i].type === "TraceWidget") {
--- a/src/js/model.js	Thu Apr 26 19:18:57 2012 +0200
+++ b/src/js/model.js	Fri Apr 27 19:18:21 2012 +0200
@@ -73,9 +73,14 @@
 IriSP.Model.List.prototype = new Array();
 
 IriSP.Model.List.prototype.getElement = function(_id) {
-    var _index = (IriSP._(this.idIndex).indexOf(this.source.getNamespaced(_id).fullName));
+    var _index = IriSP._(this.idIndex).indexOf(_id);
     if (_index !== -1) {
         return this[_index];
+    } else {
+        var _un = _id.replace(/.*:/);
+        return IriSP._(this.idIndex).find(function(_i) {
+            return _i.replace(/.*:/) === _un;
+        });
     }
 }
 
@@ -538,7 +543,7 @@
 }
 
 IriSP.Model.Source.prototype.getElement = function(_elId) {
-    return this.directory.getElement(_this.getNamespaced(_elId).fullname);
+    return this.directory.getElement(this.getNamespaced(_elId).fullname);
 }
 
 IriSP.Model.Source.prototype.setCurrentMediaId = function(_idRef) {
@@ -680,7 +685,18 @@
 }
 
 IriSP.Model.Directory.prototype.getElement = function(_id) {
-    return this.elements[_id];
+    var _res = this.elements[_id];
+    if (typeof _res === "undefined") {
+        var _un = _id.replace(/.*:/),
+            _keys = IriSP._(this.elements).keys();
+            _key = IriSP._(_keys).find(function(_i) {
+                return _i.replace(/.*:/) === _un;
+            });
+        if (typeof _key !== "undefined") {
+            _res = this.elements[_key];
+        }
+    }
+    return _res;
 }
 
 IriSP.Model.Directory.prototype.addElement = function(_element) {
--- a/src/js/modules/mediafragment.js	Thu Apr 26 19:18:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/* mediafragment module */
-
-IriSP.MediaFragment = function(Popcorn, config, Serializer) {
-  IriSP.Module.call(this, Popcorn, config, Serializer);
-
-  this.mutex = false; /* a mutex because we access the url from two different functions */
-
-  this._Popcorn.listen( "loadedmetadata", IriSP.wrap(this,this.advanceTime));
-  this._Popcorn.listen( "pause", IriSP.wrap(this,this.updateTime));
-  this._Popcorn.listen( "seeked", IriSP.wrap(this,this.updateTime));
-  this._Popcorn.listen( "IriSP.PolemicTweet.click", IriSP.wrap(this,this.updateAnnotation));
-  this._Popcorn.listen( "IriSP.SegmentsWidget.click", IriSP.wrap(this,this.updateAnnotation));
-  
-  window.onhashchange = IriSP.wrap(this, this.advanceTime);
-};
-
-IriSP.MediaFragment.prototype = new IriSP.Module();
-
-IriSP.MediaFragment.prototype.advanceTime = function() {
-             var url = window.location.href;
-
-              if ( url.split( "#" )[ 1 ] != null ) {
-                  pageoffset = url.split( "#" )[1];
-
-                  if ( pageoffset.substring(0, 2) === "t=") {
-                    // timecode 
-                    if ( pageoffset.substring( 2 ) != null ) {
-                    var offsettime = pageoffset.substring( 2 );
-                    this._Popcorn.currentTime( parseFloat(offsettime) );
-                    
-                    /* we have to trigger this signal manually because of a
-                     bug in the jwplayer */
-                    this._Popcorn.trigger("seeked", parseFloat(offsettime));
-                    }
-                  } else if ( pageoffset.substring(0, 3) === "id=") {
-                    // annotation
-                    var annotationId = pageoffset.substring( 3 );
-                    // there's no better way than that because
-                    // of possible race conditions
-                    this._serializer.sync(IriSP.wrap(this, function() {
-                          this.lookupAnnotation.call(this, annotationId); 
-                          }));
-                  }
-              }
-};
-
-/** handler for the seeked signal. It may have or may have not an argument.
-    @param time if not undefined, the time we're seeking to 
-*/
-IriSP.MediaFragment.prototype.updateTime = function(time) {
-  if (this.mutex === true) {
-    return;
-  }
-
-  var history = window.history;
-  if ( !history.pushState ) {
-    return false;
-  }
-    
-  if (IriSP.null_or_undefined(time) || typeof(time) != "number") {
-    var ntime = this._Popcorn.currentTime().toFixed(2)
-  } else {
-    var ntime = time.toFixed(2);
-  }
-
-  // used to relay the new hash to the embedder
-  this._Popcorn.trigger("IriSP.Mediafragment.hashchange", "#t=" + ntime);
-  
-  splitArr = window.location.href.split( "#" )
-  history.replaceState( {}, "", splitArr[0] + "#t=" + ntime );
-};
-
-
-IriSP.MediaFragment.prototype.updateAnnotation = function(annotationId) {
-  var _this = this;
-  this.mutex = true;
-
-  var history = window.history;
-  if ( !history.pushState ) {
-    return false;
-  }
- 
-  
-  // used to relay the new hash to the embedder
-  this._Popcorn.trigger("IriSP.Mediafragment.hashchange", "#id=" + annotationId);
-  
-  splitArr = window.location.href.split( "#" )
-  history.replaceState( {}, "", splitArr[0] + "#id=" + annotationId);
-
-  
-  // reset the mutex afterwards to prevent the module from reacting to his own changes.
-  window.setTimeout(function() { _this.mutex = false }, 50);
-};
-
-// lookup and seek to the beginning of an annotation
-IriSP.MediaFragment.prototype.lookupAnnotation = function(annotationId) {
-  var _this = this;
-  this.mutex = true;
-
-  var annotation = undefined;
-  var annotations = this._serializer._data.annotations;
-
-  var i;
-  for (i = 0; i < annotations.length; i++) {
-      if (annotations[i].id === annotationId) {
-        annotation = annotations[i];
-        break;
-      }
-  }
-
-  if (typeof(annotation) !== "undefined") {
-    this._Popcorn.currentTime(annotation.begin / 1000);
-
-    /* we have to trigger this signal manually because of a
-     bug in the jwplayer */
-    this._Popcorn.trigger("seeked", annotation.begin / 1000);
-    this._Popcorn.trigger("IriSP.Mediafragment.showAnnotation", annotationId);
-  }
-  
-  window.setTimeout(function() { _this.mutex = false }, 50);
-};
--- a/src/js/widgets/sliceWidget.js	Thu Apr 26 19:18:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/** A widget to create a new segment */
-IriSP.SliceWidget = function(Popcorn, config, Serializer) {
-  IriSP.Widget.call(this, Popcorn, config, Serializer);
-  
-};
-
-IriSP.SliceWidget.prototype = new IriSP.Widget();
-
-IriSP.SliceWidget.prototype.draw = function() {
-  var templ = Mustache.to_html(IriSP.sliceWidget_template);
-  this.selector.append(templ);
-  
-  this.sliceZone = this.selector.find(".Ldt-sliceZone");
-  
-  /* global variables used to keep the position and width
-     of the zone.
-  */  
-  this.zoneLeft = 0;
-  this.zoneWidth = 0;
-  
-  this.leftHandle = this.selector.find(".Ldt-sliceLeftHandle");
-  this.rightHandle = this.selector.find(".Ldt-sliceRightHandle");
-
-  var left = this.selector.offset().left;
-  var top = this.selector.offset().top;
-
-  // a bug in firefox makes it use the wrong format
-  if (!IriSP.jQuery.browser.mozilla) {
-    // contain the handles correctly - we cannot set
-    // containment: parent because it wouldn't allow to select the 
-    // whole slice, so we have to compute a box in which the slice is
-    // allowed to move.
-    var containment = [left - 8, top, this.selector.width() + left, top];
-
-    // var containment = [left - 16, top, this.selector.width() + left - 8, top];
-    this.leftHandle.draggable({axis: "x",
-    drag: IriSP.wrap(this, this.leftHandleDragged),  
-    containment: containment
-    });
-
-    containment = [left, top, this.selector.width() + left, top];
-    // containment = [left, top, this.selector.width() + left - 8, top];
-    this.rightHandle.draggable({axis: "x",
-    drag: IriSP.wrap(this, this.rightHandleDragged),    
-    containment: containment
-    });
-  
-  } else { // firefox
-    // we need to define a containment specific to firefox.
-    
-    var containment = [left - 16, top, this.selector.width() + left - 8, top];
-    this.leftHandle.draggable({axis: "x",
-    drag: IriSP.wrap(this, this.leftHandleDragged),  
-    containment: containment
-    });
-
-    containment = [left, top, this.selector.width() + left - 8, top];
-    this.rightHandle.draggable({axis: "x",
-    drag: IriSP.wrap(this, this.rightHandleDragged),    
-    containment: containment
-    });
-  }
-  
-  this.leftHandle.css("position", "absolute");
-  this.rightHandle.css("position", "absolute");
-  
-  this._Popcorn.listen("IriSP.SliceWidget.position", 
-                        IriSP.wrap(this, this.positionSliceHandler));
-  
-  this._Popcorn.listen("IriSP.SliceWidget.show", IriSP.wrap(this, this.show));
-  this._Popcorn.listen("IriSP.SliceWidget.hide", IriSP.wrap(this, this.hide));
-  this.selector.hide();
-};
-
-/** responds to an "IriSP.SliceWidget.position" message
-    @param params an array with the first element being the left distance in
-           percents and the second element the width of the slice in pixels
-*/        
-IriSP.SliceWidget.prototype.positionSliceHandler = function(params) {
-  left = params[0];
-  width = params[1];
-  
-  this.zoneLeft = left;
-  this.zoneWidth = width;
-  this.sliceZone.css("left", left + "px");
-  this.sliceZone.css("width", width + "px");
-  this.leftHandle.css("left", (left - 7) + "px");
-  this.rightHandle.css("left", left + width + "px");
-  
-  this._leftHandleOldLeft = left - 7;
-  this._rightHandleOldLeft = left + width;
-};
-
-/** handle a dragging of the left handle */
-IriSP.SliceWidget.prototype.leftHandleDragged = function(event, ui) {
-  /* we have a special variable, this._leftHandleOldLeft, to keep the
-     previous position of the handle. We do that to know in what direction
-     is the handle being dragged
-  */
-  
-  var currentX = this.leftHandle.offset().left;
-  var rightHandleX = Math.floor(this.rightHandle.position()["left"]);
-  
-  var container_offset = this.selector.offset().left;
-
-  if (Math.floor(ui.position.left) >= rightHandleX - 7) {
-    /* prevent the handle from moving past the right handle */
-    ui.position.left = rightHandleX - 7;
-  }
-
-  this.zoneWidth = rightHandleX - Math.floor(ui.position.left) - 7;  
-  this.zoneLeft = Math.floor(ui.position.left) + 8;
-  
-  this.sliceZone.css("width", this.zoneWidth);
-  this.sliceZone.css("left", this.zoneLeft + "px");
-  
-  this._leftHandleOldLeft = ui.position.left;  
-  this.broadcastChanges();
-    
-};
-
-/** handle a dragging of the right handle */
-IriSP.SliceWidget.prototype.rightHandleDragged = function(event, ui) { 
-  /* we have a special variable, this._leftHandleOldLeft, to keep the
-     previous position of the handle. We do that to know in what direction
-     is the handle being dragged
-  */
-  
-  var currentX = this.leftHandle.position()["left"];
-  var leftHandleX = Math.floor(this.leftHandle.position()["left"]);
-
-  var container_offset = this.selector.offset().left + this.selector.width();
-  
-  if (Math.floor(ui.position.left) < leftHandleX + 7) {
-    /* prevent the handle from moving past the left handle */
-    ui.position.left = leftHandleX + 7;
-  }
-
-  this.zoneWidth = Math.floor(ui.position.left) - (leftHandleX + 7);    
-  
-  this.sliceZone.css("width", this.zoneWidth);
-  //this.sliceZone.css("left", this.zoneLeft + "px");
-  this._rightHandleOldLeft = Math.floor(this._rightHandleOldLeft);  
-  this.broadcastChanges();
-};
-
-/** tell to the world that the coordinates of the slice have
-    changed 
-*/
-IriSP.SliceWidget.prototype.broadcastChanges = function() {
-  var leftPercent = (this.zoneLeft / this.selector.width()) * 100;
-  var zonePercent = (this.zoneWidth / this.selector.width()) * 100;
-
-  this._Popcorn.trigger("IriSP.SliceWidget.zoneChange", [leftPercent, zonePercent]);  
-};
-
-IriSP.SliceWidget.prototype.show = function() {
-  this.selector.show();
-};
-
-IriSP.SliceWidget.prototype.hide = function() {
-  this.selector.hide();
-};
\ No newline at end of file
--- a/src/js/widgets/tagCloudWidget.js	Thu Apr 26 19:18:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-IriSP.TagCloudWidget = function(Popcorn, config, Serializer) {
-  IriSP.Widget.call(this, Popcorn, config, Serializer);
-}
-
-IriSP.TagCloudWidget.prototype = new IriSP.Widget();
-
-IriSP.TagCloudWidget.prototype.draw = function() {
-    
-    var _urlRegExp = /https?:\/\/[0-9a-zA-Z\.%\/-_]+/g,
-        _stopWords = [
-            'aussi', 'and', 'avec', 'aux', 'bien', 'car', 'cette', 'comme', 'dans', 'donc', 'des', 'elle', 'encore', 'entre', 'est',
-            'être', 'eux', 'faire', 'fait', 'http', 'ici', 'ils', 'les', 'leur', 'leurs', 'mais', 'mes', 'même', 'mon', 'notre',
-            'non', 'nos', 'nous', 'ont', 'par', 'pas', 'peu', 'peut', 'plus', 'pour', 'que', 'qui', 'sans', 'ses' ,'son', 'sont', 'sur',
-            'tes', 'très', 'the', 'ton', 'tous', 'tout', 'une', 'votre', 'vos', 'vous' ],
-        _regexpword = /[^\s\.&;,'"!\?\d\(\)\+\[\]\\\…\-«»:\/]{3,}/g,
-        _words = {},
-        _showTitle = !this._config.excludeTitle,
-        _showDescription = !this._config.excludeDescription,
-        _excludePattern = this._config.excludePattern || null,
-        _tagCount = this._config.tagCount || 30;
-    if (typeof this._config.excludeWords !== "undefined" && this._config.excludeWords.length) {
-        IriSP._(this._config.excludeWords).each(function(_w) {
-            _stopWords.push(_w.toLowerCase());
-        });
-    }
-    
-    IriSP._(this._serializer._data.annotations).each(function(_annotation) {
-       if (_annotation.content && _annotation.content.description) {
-           var _txt = (_showTitle ? _annotation.content.title : '') + ' ' + (_showDescription ? _annotation.content.description : '')
-           IriSP._(_txt.toLowerCase().replace(_urlRegExp, '').match(_regexpword)).each(function(_mot) {
-               if (_stopWords.indexOf(_mot) == -1 && (_excludePattern == null || !_excludePattern.test(_mot))) {
-                   _words[_mot] = 1 + (_words[_mot] || 0);
-               }
-           })
-       } 
-    });
-    
-    _words = IriSP._(_words)
-        .chain()
-        .map(function(_v, _k) {
-            return {
-                "word" : _k,
-                "count" : _v
-            }
-        })
-        .filter(function(_v) {
-            return _v.count > 2;
-        })
-        .sortBy(function(_v) {
-            return - _v.count;
-        })
-        .first(_tagCount)
-        .value();
-    var _max = _words[0].count,
-        _min = Math.min(_words[_words.length - 1].count, _max - 1),
-        _scale = 16 / Math.sqrt(_max - _min),
-        _this = this,
-        _html = '<ul>'
-            + IriSP._(_words)
-                .chain()
-                .shuffle()
-                .map(function(_word) {
-                    var _size = 10 + _scale * Math.sqrt(_word.count - _min);
-                    return '<li class="Ldt-TraceMe" style="font-size:'
-                        + _size
-                        + 'px;">'
-                        + _word.word
-                        + '</li>'
-                })
-                .value()
-                .join("")
-            + '</ul>';
-    this.selector
-        .addClass("Ldt-TagCloud")
-        .html(_html);
-    this.selector.find("li").click(function() {
-        var _txt = this.textContent.replace(/(^[\s]+|[\s]+$)/g,'');
-        _this._Popcorn.trigger("IriSP.search.triggeredSearch", _txt);
-    });
-    this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) {
-        var _rgxp = new RegExp("(" + searchString.replace(/(\W)/g,'\\$1') + ")","gi");
-        this.selector.find("li").each(function(_i, _e) {
-            _e.innerHTML = searchString.length ?
-                _e.textContent.replace(_rgxp,'<span class="Ldt-TagCloud-actif Ldt-TraceMe">$1</span>')
-                : _e.textContent;
-        });
-    }));
-    this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.endsearch));
-    this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.endsearch));
-}
-
-IriSP.TagCloudWidget.prototype.endsearch = function() {
-    this.selector.find("li").each(function(_i, _e) {
-        _e.innerHTML = _e.textContent;
-    });
-}
--- a/src/js/widgets/tweetsWidget.js	Thu Apr 26 19:18:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/* a widget that displays tweet - used in conjunction with the polemicWidget */
-
-IriSP.TweetsWidget = function(Popcorn, config, Serializer) {
-  IriSP.Widget.call(this, Popcorn, config, Serializer);
-
-  this._displayingTweet = false;
-  this._timeoutId = undefined; 
-  this._hidden = false; /* hidden means that the createAnnotationWidget is shown */
-};
-
-
-IriSP.TweetsWidget.prototype = new IriSP.Widget();
-
-
-IriSP.TweetsWidget.prototype.drawTweet = function(annotation) {
-    if (this._hidden)
-      return;
-    
-    var title = IriSP.formatTweet(annotation.content.title);
-    var img = annotation.content.img.src;
-    if (typeof(img) === "undefined" || img === "" || img === "None") {
-      img = this.default_profile_picture;
-    }
-
-    var imageMarkup = IriSP.templToHTML("<img src='{{src}}' alt='user image'></img>", 
-                                       {src : img});
-    
-    if (typeof(IriSP.get_aliased(annotation.meta, ["dc:source", "source"]).content) !== "undefined") {
-      var tweetContents = JSON.parse(IriSP.get_aliased(annotation.meta, ["dc:source", "source"]).content);
-      var creator = tweetContents.user.screen_name;
-      var real_name = tweetContents.user.name;
-
-      imageMarkup = IriSP.templToHTML("<a href='http://twitter.com/{{creator}}'><img src='{{src}}' alt='user image'></img></a>", 
-                                       {src : img, creator: creator});
-            
-      var formatted_date = new Date(tweetContents.created_at).toLocaleDateString();
-      title = IriSP.templToHTML("<a class='Ldt-tweet_userHandle' href='http://twitter.com/{{creator}}'>@{{creator}}</a> - " + 
-                                "<div class='Ldt-tweet_realName'>{{real_name}}</div>" +
-                                "<div class='Ldt-tweet_tweetContents'>{{{ contents }}}</div>" +
-                                "<div class='Ldt-tweet_date'>{{ date }}</div>", 
-                                {creator: creator, real_name: real_name, contents : title, date : formatted_date});
-
-      this.selector.find(".Ldt-TweetReply").attr("href", "http://twitter.com/home?status=@" + creator + ":%20");
-
-
-      var rtText = Mustache.to_html("http://twitter.com/home?status=RT @{{creator}}: {{text}}",
-                                    {creator: creator, text: IriSP.encodeURI(annotation.content.title)});
-      this.selector.find(".Ldt-Retweet").attr("href", rtText);
-    }
-
-    this.selector.find(".Ldt-tweetContents").html(title);
-    this.selector.find(".Ldt-tweetAvatar").html(imageMarkup);
-    this.selector.show("blind", 250); 
-};
-
-IriSP.TweetsWidget.prototype.displayTweet = function(annotation) {
-  if (this._displayingTweet === false) {
-    this._displayingTweet = true;
-  } else {
-    window.clearTimeout(this._timeoutId);
-  }
-
-  this.drawTweet(annotation);
-
-  var time = this._Popcorn.currentTime();  
-  this._timeoutId = window.setTimeout(IriSP.wrap(this, this.clearPanel), this.tweet_display_period);
-};
-
-
-IriSP.TweetsWidget.prototype.clearPanel = function() {  
-    this._displayingTweet = false;
-    this._timeoutId = undefined;
-    this.closePanel();
-    
-};
-
-IriSP.TweetsWidget.prototype.closePanel = function() {
-    if (this._timeoutId != undefined) {
-      /* we're called from the "close window" link */
-      /* cancel the timeout */
-      window.clearTimeout(this._timeoutId);
-      this._timeoutId = null;
-    }
-    
-    this.selector.hide("blind", 400);
-    
-};
-
-/* cancel the timeout if the user clicks on the keep panel open button */
-IriSP.TweetsWidget.prototype.keepPanel = function() {
-    if (this._timeoutId != undefined) {
-      /* we're called from the "close window" link */
-      /* cancel the timeout */
-      window.clearTimeout(this._timeoutId);
-      this._timeoutId = null;
-    }
-};
-
-IriSP.TweetsWidget.prototype.draw = function() {
-  var _this = this;
-  
-  var tweetMarkup = IriSP.templToHTML(IriSP.tweetWidget_template, {"share_template" : IriSP.share_template});
-  this.selector.append(tweetMarkup);
-  this.selector.hide();
-  this.selector.find(".Ldt-tweetWidgetMinimize").click(IriSP.wrap(this, this.closePanel));
-  this.selector.find(".Ldt-tweetWidgetKeepOpen").click(IriSP.wrap(this, this.keepPanel));
-  
-  this._Popcorn.listen("IriSP.PolemicTweet.click", IriSP.wrap(this, this.PolemicTweetClickHandler));
-  this._Popcorn.listen("IriSP.PlayerWidget.AnnotateButton.clicked", 
-                        IriSP.wrap(this, this.handleAnnotateSignal));  
-};
-
-IriSP.TweetsWidget.prototype.PolemicTweetClickHandler = function(tweet_id) {  
-  var index, annotation;
-  for (index in this._serializer._data.annotations) {
-    annotation = this._serializer._data.annotations[index];
-    
-    if (annotation.id === tweet_id)
-      break;
-  }
-    
-  if (annotation.id !== tweet_id)
-      /* we haven't found it */
-      return;
-  
-  this.displayTweet(annotation);
-  return;
-};
-
-/** handle clicks on the annotate button by hiding/showing itself */
-IriSP.TweetsWidget.prototype.handleAnnotateSignal = function() {
-  if (this._hidden == false) {
-    this.selector.hide();
-    this._hidden = true;
-  } else {
-    if (this._displayingTweet !== false)
-      this.selector.show();
-      
-    
-    this._hidden = false;
-  }
-};
\ No newline at end of file
--- a/src/widgets/CreateAnnotation.js	Thu Apr 26 19:18:57 2012 +0200
+++ b/src/widgets/CreateAnnotation.js	Fri Apr 27 19:18:21 2012 +0200
@@ -7,17 +7,21 @@
 
 IriSP.Widgets.CreateAnnotation.prototype.defaults = {
     single_time_mode : false,
-    
+    show_title_field : true,
+    user_avatar : "https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png"
 }
 
 IriSP.Widgets.CreateAnnotation.prototype.messages = {
     "en": {
         "from_time" : "from",
         "to_time" : "to",
+        "at_time" : "at",
         "submit": "Submit",
         "add_keywords": "Add keywords",
         "add_polemic_keywords": "Add polemic keywords",
         "your_name": "Your name",
+        "no_title" : "Annotate this video",
+        "type_title": "Annotation title",
         "type_description": "Type the full description of your annotation here.",
         "wait_while_processing": "Please wait while your request is being processed...",
         "error_while_contacting": "An error happened while contacting the server. Your annotation has not been saved.",
@@ -31,10 +35,13 @@
     "fr": {
         "from_time" : "from",
         "to_time" : "à",
+        "at_time" : "à",
         "submit": "Envoyer",
         "add_keywords": "Ajouter des mots-clés",
         "add_polemic_keywords": "Ajouter des mots-clés polémiques",
         "your_name": "Votre nom",
+        "no_title" : "Annoter cette vidéo",
+        "type_title": "Titre de l'annotation",
         "type_description": "Rédigez le contenu de votre annotation ici.",
         "wait_while_processing": "Veuillez patienter pendant le traitement de votre requête...",
         "error_while_contacting": "Une erreur s'est produite en contactant le serveur. Votre annotation n'a pas été enregistrée",
@@ -48,12 +55,17 @@
 }
 
 IriSP.Widgets.CreateAnnotation.prototype.template =
-    '<div class="Ldt-CreateAnnotation">'
-    + '    <div class="Ldt-CreateAnnotation-Inner">'
+    '<div class="Ldt-CreateAnnotation"><div class="Ldt-CreateAnnotation-Inner">'
+    + '<form class="Ldt-CreateAnnotation-Screen Ldt-CreateAnnotation-Main">'
+    + '<h3>{{#show_title_field}}<input class="Ldt-CreateAnnotation-Title" placeholder="{{l10n.type_title}}" />{{/show_title_field}}'
+    + '{{^show_title_field}}<span class="Ldt-CreateAnnotation-NoTitle">{{l10n.no_title}}</span>{{/show_title_field}}'
+    + ' <span class="Ldt-CreateAnnotation-Times">{{#single_time_mode}}{{l10n.at_time}}{{/single_time_mode}}'
+    + '{{^single_time_mode}}{{l10n.from_time}}{{/single_time_mode}} <span class="Ldt-CreateAnnotation-Begin"></span>'
+    + ' {{^single_time_mode}}{{l10n.to_time}} <span class="Ldt-CreateAnnotation-End"></span>{{/single_time_mode}}</span></h3>'
+    + ''
     
-    
-    + '    </div>'
-    + '</div>'
+    + '</form>'
+    + '</div></div>'
     
 /*    
     + '        <div class="Ldt-CreateAnnotation-Screen Ldt-createAnnotation-startScreen">'
--- a/src/widgets/Mediafragment.js	Thu Apr 26 19:18:57 2012 +0200
+++ b/src/widgets/Mediafragment.js	Fri Apr 27 19:18:21 2012 +0200
@@ -2,7 +2,10 @@
     IriSP.Widgets.Widget.call(this, player, config);
     this.last_hash = "";
     window.onhashchange = this.functionWrapper("goToHash");
-    this.player.bindPopcorn("pause","setHashToTime");
+    this.bindPopcorn("pause","setHashToTime");
+    this.bindPopcorn("seeked","setHashToTime");
+    this.bindPopcorn("IriSP.Mediafragment.setHashToAnnotation","setHashToAnnotation");
+    this.blocked = false;
 }
 
 IriSP.Widgets.Mediafragment.prototype = new IriSP.Widgets.Widget();
@@ -28,17 +31,34 @@
 }
 
 IriSP.Widgets.Mediafragment.prototype.setHashToAnnotation = function(_annotationId) {
-    this.last_hash = '#id=' + this.source.unNamespace(_annotationId);
-    
+    this.setHash( '#id=' + this.source.unNamespace(_annotationId) );
 }
 
-IriSP.Widgets.Mediafragment.prototype.setHashToTime = function() {
-    this.last_hash = '#t=' + this.source.popcorn.currentTime();
+IriSP.Widgets.Mediafragment.prototype.setHashToTime = function(_time) {
+    _time = (typeof _time !== "undefined" ? _time : this.player.popcorn.currentTime() );
+    this.setHash( '#t=' + _time );
 }
 
 IriSP.Widgets.Mediafragment.prototype.setHash = function(_hash) {
-    if (this.last_hash !== _hash) {
+    if (!this.blocked && this.last_hash !== _hash) {
         this.last_hash = _hash;
         document.location.hash = _hash;
+        this.block();
     }
-}
\ No newline at end of file
+}
+
+IriSP.Widgets.Mediafragment.prototype.unblock = function() {
+    if (typeof this.blockTimeout !== "undefined") {
+        window.clearTimeout(this.blockTimeout);
+    }
+    this.blockTimeout = undefined;
+    this.blocked = false;
+}
+
+IriSP.Widgets.Mediafragment.prototype.block = function() {
+    if (typeof this.blockTimeout !== "undefined") {
+        window.clearTimeout(this.blockTimeout);
+    }
+    this.blocked = true;
+    this.blockTimeout = window.setTimeout(this.functionWrapper("unblock"), 1000);
+}
--- a/src/widgets/Polemic.js	Thu Apr 26 19:18:57 2012 +0200
+++ b/src/widgets/Polemic.js	Fri Apr 27 19:18:21 2012 +0200
@@ -185,7 +185,9 @@
             _this.tooltip.hide();
         })
         .click(function() {
-            _this.player.popcorn.trigger("IriSP.Tweet.show", IriSP.jQuery(this).attr("annotation-id"));
+            var _id = IriSP.jQuery(this).attr("annotation-id");
+            _this.player.popcorn.trigger("IriSP.Mediafragment.setHashToAnnotation", _id);
+            _this.player.popcorn.trigger("IriSP.Tweet.show", _id);
         });
     
     this.$zone.click(function(_e) {
--- a/src/widgets/Segments.js	Thu Apr 26 19:18:57 2012 +0200
+++ b/src/widgets/Segments.js	Fri Apr 27 19:18:21 2012 +0200
@@ -69,6 +69,7 @@
     .click(function() {
         var _el = IriSP.jQuery(this);
         _this.player.popcorn.currentTime(_el.attr("begin-seconds"));
+        _this.player.popcorn.trigger("IriSP.Mediafragment.setHashToAnnotation", _el.attr("segment-id"));
     });
 }
 
--- a/src/widgets/Slider.js	Thu Apr 26 19:18:57 2012 +0200
+++ b/src/widgets/Slider.js	Fri Apr 27 19:18:21 2012 +0200
@@ -34,6 +34,7 @@
         max: this.source.getDuration().getSeconds(),
         slide: function(event, ui) {
             _this.player.popcorn.currentTime(ui.value);
+            _this.player.popcorn.trigger("IriSP.Mediafragment.setHashToTime");
         }
     });