Migrated playerWidget and started annotationsListWidget new-model
authorveltr
Wed, 18 Apr 2012 18:58:44 +0200
branchnew-model
changeset 870 2c025db10a10
parent 868 a525cc2214e7
child 872 d777d05a16e4
Migrated playerWidget and started annotationsListWidget
src/css/LdtPlayer.css
src/js/defaults.js
src/js/init.js
src/js/model.js
src/js/pop.js
src/js/utils.js
src/js/widgets.js
src/js/widgets/annotationsListWidget.js
src/js/widgets/helloWorldWidget.js
src/js/widgets/playerWidget.js
src/templates/annotationsListWidget.html
src/templates/player.html
test/integration/polemic.htm
--- a/src/css/LdtPlayer.css	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/css/LdtPlayer.css	Wed Apr 18 18:58:44 2012 +0200
@@ -325,12 +325,12 @@
     height: 5px; margin: 9px 3px 0; background: #cccccc; border: 1px solid #999999; border-radius: 2px;
 }
 
-.Ldt-Ctrl-Volume-Cursor {
-    position: absolute; top: 2px; width: 6px; height: 19px; background: #a8a8a8; border: 1px solid #999999; border-radius: 2px;
+.Ldt-Ctrl-Volume-Control .ui-slider-handle {
+    width: 6px; height: 19px; background: #a8a8a8; border: 1px solid #999999; border-radius: 2px; top: -8px; margin-left: -4px;
     cursor: pointer;
 }
 
-.Ldt-Ctrl-Volume-Control:hover .Ldt-Ctrl-Volume-Cursor {
+.Ldt-Ctrl-Volume-Control:hover .ui-slider-handle {
      background: #F7268E;
 }
 
--- a/src/js/defaults.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/defaults.js	Wed Apr 18 18:58:44 2012 +0200
@@ -99,21 +99,21 @@
        lineWidth : 2
     },
     "AnnotationsListWidget" : {
-        ajax_mode : true, /* use ajax to get information about the annotations.
-         if set to false, only search in the annotations for the
-         current project. */
         /* the platform generates some funky urls. We replace them afterwards to point to the
          correct place - this setting will probably be overwritten by the platform
          implementers.
          Note that the player has to replace the variables between {{ and }} by its own values.
          */
-        ajax_url : "", //platform_url + "/ldtplatform/api/ldt/segments/{{media}}/{{begin}}/{{end}}",
-        ajax_granularity : 10000, /* how much ms should we look before and after the current timecode */
+        ajax_url : false, //platform_url + "/ldtplatform/api/ldt/segments/{{media}}/{{begin}}/{{end}}",
+        ajax_granularity : 300000, /* how much ms should we look before and after the current timecode */
         default_thumbnail : "http://ldt.iri.centrepompidou.fr/static/site/ldt/css/imgs/video_sequence.png",
         project_url : "", //platform_url + "/ldtplatform/ldt/front/player/"
         /* the beginning of a link to the new front */
         cinecast_version : false,
-        refresh_interval : 10000
+        annotation_type : false,
+        refresh_interval : 300000,
+        limit_count : 10,
+        newest_first : false
     },
     "StackGraphWidget" : {
          defaultcolor : "#585858",
--- a/src/js/init.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/init.js	Wed Apr 18 18:58:44 2012 +0200
@@ -19,7 +19,6 @@
 }
 
 IriSP.Metadataplayer.prototype.loadLibs = function() {
-    console.log("Loading Libs");
     // Localize jQuery variable
     IriSP.jQuery = null;
     var $L = $LAB.script(IriSP.getLib("jQuery")).script(IriSP.getLib("swfObject")).wait().script(IriSP.getLib("jQueryUI"));
@@ -52,7 +51,6 @@
     var _this = this;
     
     $L.wait(function() {
-        console.log("jQuery is loaded");
         IriSP.jQuery = window.jQuery.noConflict(true);
 
         var css_link_jquery = IriSP.jQuery("<link>", {
@@ -65,12 +63,10 @@
             type : "text/css",
             href : _this.config.gui.css
         });
-        console.log('Appending CSS');
 
         css_link_jquery.appendTo('head');
         css_link_custom.appendTo('head');
         
-        console.log(_this);
         _this.onLibsLoaded();
         
     });
@@ -83,7 +79,6 @@
     if (typeof _metadataInfo.url === "undefined" && typeof _metadataInfo.src !== "undefined") {
         _metadataInfo.url = _metadataInfo.src;
     }
-    console.log(_metadataInfo);
     if (typeof _metadataInfo.url !== "undefined" && typeof _metadataInfo.serializer !== "undefined") {
         return this.sourceManager.remoteSource(_metadataInfo);
     } else {
@@ -92,9 +87,7 @@
 }
 
 IriSP.Metadataplayer.prototype.onLibsLoaded = function() {
-    console.log("Libs Loaded");
     this.videoData = this.loadMetadata(this.video_metadata);
-    console.log(this.videoData);
     this.$ = IriSP.jQuery('#' + this.config.gui.container);
     this.$.css({
         "width": this.config.gui.width,
@@ -105,7 +98,6 @@
     }
       
     var _this = this;
-    console.log("calling OnLoad");
     this.videoData.onLoad(function() {
         _this.onVideoDataLoaded();
     });
@@ -115,26 +107,33 @@
     console.log("Video Data Loaded");
     if (typeof this.videoData !== "undefined" && typeof this.config.player.video === "undefined") {
         var _media = this.videoData.currentMedia;
+        console.log(_media);
         if (typeof _media !== "undefined") {
-            config.player.video = _media.video;
+            this.config.player.video = _media.video;
             if (typeof _media.streamer !== "undefined") {
-                config.player.streamer = _media.streamer;
-                config.player.video = _media.video.replace(_media.streamer,'');
+                this.config.player.streamer = _media.streamer;
+                this.config.player.video = _media.video.replace(_media.streamer,'');
             }
         }
         
     }
-    this.configurePopcorn(config.player);
+    this.configurePopcorn();
     this.widgets = [];
+    console.log("Now instantiating widgets");
     for(var i = 0; i < this.config.gui.widgets.length; i++) {
-        this.widgets.push(new IriSP.Widgets[_config.type](this, this.config.gui.widgets[i]));
+        var _widget = this.config.gui.widgets[i];
+        if (typeof IriSP[_widget.type] !== "undefined") {
+            this.widgets.push(new IriSP[_widget.type](this, _widget));
+        } else {
+            console.log("Error, Call to Undefined Widget Type");
+        }
     };
-    this.$('.Ldt-loader').detach();
+    this.$.find('.Ldt-loader').detach();
 }
 
 IriSP.Metadataplayer.prototype.configurePopcorn = function() {
     var pop,
-        ret = this.layoutDivs(),
+        ret = this.layoutDivs("video"),
         containerDiv = ret[0],
         spacerDiv = ret[1];
 
@@ -142,43 +141,45 @@
      * using the spacer.
      */
     IriSP.jQuery("#" + spacerDiv).css("height", Math.max(1, this.config.gui.spacer_div_height) + "px");
+    
+    console.log(this.config.player);
 
-    switch(options.type) {
+    switch(this.config.player.type) {
         /*
          todo : dynamically create the div/video tag which
          will contain the video.
          */
         case "html5":
             var tmpId = Popcorn.guid("video");
-            IriSP.jQuery("#" + containerDiv).append("<video src='" + options.video + "' id='" + tmpId + "'></video>");
+            IriSP.jQuery("#" + containerDiv).append("<video src='" + this.config.player.video + "' id='" + tmpId + "'></video>");
 
             if(options.hasOwnProperty("width"))
-                IriSP.jQuery("#" + containerDiv).css("width", options.width);
+                IriSP.jQuery("#" + containerDiv).css("width", this.config.player.width);
 
             if(options.hasOwnProperty("height"))
-                IriSP.jQuery("#" + containerDiv).css("height", options.height);
+                IriSP.jQuery("#" + containerDiv).css("height", this.config.player.height);
             pop = Popcorn("#" + tmpId);
             break;
 
         case "jwplayer":
-            var opts = IriSP.jQuery.extend({}, options);
+            var opts = IriSP.jQuery.extend({}, this.config.player);
             delete opts.container;
             delete opts.type;
             opts.file = opts.video;
             delete opts.video;
 
-            if(!options.hasOwnProperty("flashplayer")) {
+            if(!opts.hasOwnProperty("flashplayer")) {
                 opts.flashplayer = IriSP.jwplayer_swf_path;
             }
 
-            if(!options.hasOwnProperty("controlbar.position")) {
+            if(!opts.hasOwnProperty("controlbar.position")) {
                 opts["controlbar.position"] = "none";
             }
             pop = new IriSP.PopcornReplacement.jwplayer("#" + containerDiv, opts);
             break;
 
         case "youtube":
-            var opts = IriSP.jQuery.extend({}, options);
+            var opts = IriSP.jQuery.extend({}, this.config.player);
             delete opts.container;
             opts.controls = 0;
             opts.autostart = false;
@@ -191,12 +192,12 @@
             break;
 
         case "dailymotion":
-            pop = new IriSP.PopcornReplacement.dailymotion("#" + containerDiv, options);
+            pop = new IriSP.PopcornReplacement.dailymotion("#" + containerDiv, this.config.player);
             break;
 
         case "allocine":
             /* pass the options as-is to the allocine player and let it handle everything */
-            pop = new IriSP.PopcornReplacement.allocine("#" + containerDiv, options);
+            pop = new IriSP.PopcornReplacement.allocine("#" + containerDiv, this.config.player);
             break;
         
         default:
@@ -214,8 +215,8 @@
     if (typeof(_name) === "undefined") {
        _name = "";
     }
-    var newDiv = IriSP.guid(this.container + "_widget_" + _name + "_"),
-        spacerDiv = IriSP.guid("LdtPlayer_spacer_"),
+    var newDiv = IriSP._.uniqueId(this.config.gui.container + "_widget_" + _name + "_"),
+        spacerDiv = IriSP._.uniqueId("LdtPlayer_spacer_"),
         divTempl = "<div id='{{id}}' style='width: {{width}}px; position: relative; clear: both;'></div>",
         spacerTempl = "<div id='{{spacer_id}}' style='width: {{width}}px; position: relative; height: {{spacer_div_height}}px;'></div>",
         divHtml = Mustache.to_html( divTempl,
@@ -227,11 +228,11 @@
             {
                 spacer_id: spacerDiv,
                 width: this.config.gui.width,
-                spacer_div_height: this.config.gui.height
+                spacer_div_height: this.config.gui.spacer_div_height
             });
             
-    this.$.append(divCode);
-    this.$.append(spacerCode);
+    this.$.append(divHtml);
+    this.$.append(spacerHtml);
 
     return [newDiv, spacerDiv];
 };
--- a/src/js/model.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/model.js	Wed Apr 18 18:58:44 2012 +0200
@@ -5,7 +5,7 @@
     _SOURCE_STATUS_WAITING : 1,
     _SOURCE_STATUS_READY : 2,
     _ID_AUTO_INCREMENT : 0,
-    getAI : function() {
+    getUID : function() {
         return "autoid-" + (++this._ID_AUTO_INCREMENT);
     },
     isoToDate : function(_str) {
@@ -59,8 +59,9 @@
 IriSP.Model.List.prototype = new Array();
 
 IriSP.Model.List.prototype.getElement = function(_id) {
-    if (this.hasId(_id)) {
-        return this;
+    var _index = (IriSP._(this.idIndex).indexOf(_id));
+    if (_index !== -1) {
+        return this[_index];
     }
 }
 
@@ -100,15 +101,21 @@
     return _res;
 }
 
+IriSP.Model.List.prototype.slice = function(_start, _end) {
+    var _res = new IriSP.Model.List(this.directory);
+    _res.addElements(Array.prototype.slice.call(this, _start, _end));
+    return _res;
+}
+
 /* Array has a sort function, but it's not as interesting as Underscore.js's sortBy
  * and won't return a new IriSP.Model.List
  */
 IriSP.Model.List.prototype.sortBy = function(_callback) {
     var _this = this,
         _res = new IriSP.Model.List(this.directory);
-    _res.contents = IriSP._(this).sortBy(function(_value, _key) {
+    _res.addElements(IriSP._(this).sortBy(function(_value, _key) {
         return _callback(_value, _key, _this);
-    });
+    }));
     return _res;
 }
 
@@ -136,6 +143,12 @@
     });
 }
 
+IriSP.Model.List.prototype.getTitles = function() {
+    return this.map(function(_el) {
+        return _el.title;
+    });
+}
+
 IriSP.Model.List.prototype.addId = function(_id) {
     var _el = this.directory.getElement(_id)
     if (!this.hasId(_id) && typeof _el !== "undefined") {
@@ -166,8 +179,7 @@
 }
 
 IriSP.Model.List.prototype.addElements = function(_array) {
-    var _l = _array.length,
-        _this = this;
+    var _this = this;
     IriSP._(_array).forEach(function(_el) {
         _this.push(_el);
     });
@@ -238,10 +250,11 @@
     this.elementType = 'element';
     if (typeof _source !== "undefined") {
         if (typeof _id === "undefined" || !_id) {
-            _id = IriSP.Model.getAI();
+            _id = IriSP.Model.getUID();
         }
         this.source = _source;
-        this.id = _source.getNamespaced(_id).fullname;
+        this.namespacedId = _source.getNamespaced(_id)
+        this.id = this.namespacedId.fullname;
         this.title = "";
         this.description = "";
         this.source.directory.addElement(this);
@@ -364,6 +377,10 @@
     return this.getReference("tag");
 }
 
+IriSP.Model.Annotation.prototype.getTagTexts = function() {
+    return this.getTags().getTitles();
+}
+
 /* */
 
 IriSP.Model.Source = function(_config) {
@@ -376,7 +393,7 @@
         this.callbackQueue = [];
         this.contents = {};
         if (typeof this.namespace === "undefined") {
-            this.namespace = IriSP.Model.getAI();
+            this.namespace = IriSP.Model.getUID();
         }
         if (typeof this.namespaceUrl === "undefined") {
             this.namespaceUrl = (typeof this.url !== "undefined" ? this.url : this.namespaceUrl);
@@ -463,31 +480,39 @@
 }
 
 IriSP.Model.Source.prototype.get = function() {
-    this.status = IriSP.Model._SOURCE_STATUS_READY;
+    this.status = IriSP.Model._SOURCE_STATUS_WAITING;
+    this.handleCallbacks();
+}
+
+/* We defer the callbacks calls so they execute after the queue is cleared */
+IriSP.Model.Source.prototype.deferCallback = function(_callback) {
     var _this = this;
-    if (_this.callbackQueue.length) {
-        IriSP._(_this.callbackQueue).forEach(function(_callback) {
-            _callback.call(_this);
-        });
+    IriSP._.defer(function() {
+        _callback.call(_this);
+    });
+}
+
+IriSP.Model.Source.prototype.handleCallbacks = function() {
+    this.status = IriSP.Model._SOURCE_STATUS_READY;
+    while (this.callbackQueue.length) {
+        this.deferCallback(this.callbackQueue.splice(0,1)[0]);
     }
-    _this.callbackQueue = [];
+}
+
+IriSP.Model.Source.prototype.onLoad = function(_callback) {
+    if (this.status === IriSP.Model._SOURCE_STATUS_READY) {
+        this.deferCallback(_callback);
+    } else {
+        this.callbackQueue.push(_callback);
+    }
 }
 
 IriSP.Model.Source.prototype.serialize = function() {
     return this.serializer.serialize(this);
 }
 
-IriSP.Model.Source.prototype.onLoad = function(_callback) {
-    if (this.status === IriSP.Model._SOURCE_STATUS_READY) {
-        console.log("Called on load, Ready");
-        var _this = this;
-        IriSP._.defer(function() {
-            _callback.call(_this);
-        });        
-    } else {
-        console.log("Called on load, not ready");
-        this.callbackQueue.push(_callback);
-    }
+IriSP.Model.Source.prototype.deSerialize = function(_data) {
+    this.serializer.deSerialize(_data, this);
 }
 
 IriSP.Model.Source.prototype.getAnnotations = function() {
@@ -509,6 +534,13 @@
     }
 }
 
+IriSP.Model.Source.prototype.getAnnotationsByTypeTitle = function(_title) {
+    var _annType = this.getAnnotationTypeByTitle(_title);
+    if (typeof _annType !== "undefined") {
+        return _annType.getAnnotations();
+    }
+}
+
 IriSP.Model.Source.prototype.getDuration = function() {
     var _m = this.currentMedia;
     if (typeof _m !== "undefined") {
@@ -528,15 +560,8 @@
     this.status = IriSP.Model._SOURCE_STATUS_WAITING;
     var _this = this;
     IriSP.jQuery.getJSON(this.url, function(_result) {
-        _this.serializer.deSerialize(_result, _this);
-        console.log('Received data, we have '+_this.callbackQueue.length+' callbacks waiting');
-        if (_this.callbackQueue.length) {
-            IriSP._(_this.callbackQueue).forEach(function(_callback) {
-                _callback.call(_this);
-            });
-        }
-        _this.callbackQueue = [];
-        _this.status = IriSP.Model._SOURCE_STATUS_READY;
+        _this.deSerialize(_result);
+        _this.handleCallbacks();
     });
 }
 
--- a/src/js/pop.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/pop.js	Wed Apr 18 18:58:44 2012 +0200
@@ -8,13 +8,15 @@
  */
 IriSP.PopcornReplacement.player = function(container, options) {
   /* the jwplayer calls the callbacks in the global space so we need to 
-     preserve them using IriSP.wrap */
+     preserve them this way */
+    var _this = this;
+    
   this.callbacks = {
-      onReady:  IriSP.wrap(this, this.__initApi),
-      onTime:   IriSP.wrap(this, this.__timeHandler),
-      onPlay:   IriSP.wrap(this, this.__playHandler),
-      onPause:  IriSP.wrap(this, this.__pauseHandler),
-      onSeek:   IriSP.wrap(this, this.__seekHandler) 
+      onReady:  IriSP._.bind(this.__initApi, this),
+      onTime:   IriSP._.bind(this.__timeHandler, this),
+      onPlay:   IriSP._.bind(this.__playHandler, this),
+      onPause:  IriSP._.bind(this.__pauseHandler, this),
+      onSeek:   IriSP._.bind(this.__seekHandler, this) 
   };
   
   this.media = { 
@@ -81,23 +83,6 @@
   }
 };
 
-/*
-IriSP.PopcornReplacement.jwplayer = function(container, options) {
-  IriSP.PopcornReplacement._container = container.slice(1); //eschew the '#'
-  options.events = {
-      onReady: IriSP.PopcornReplacement.__initApi,
-      onTime: IriSP.PopcornReplacement.__timeHandler,
-      onPlay: IriSP.PopcornReplacement.__playHandler,
-      onPause: IriSP.PopcornReplacement.__pauseHandler,
-      onSeek: IriSP.PopcornReplacement.__seekHandler 
-      }
-    
-  jwplayer(IriSP.PopcornReplacement._container).setup(options);
-  IriSP.PopcornReplacement.media.duration = options.duration;
-  return IriSP.PopcornReplacement;
-};
-*/
-
 IriSP.PopcornReplacement.player.prototype.currentTime = function(time) {
   if (typeof(time) === "undefined") {        
       return this.playerFns.getPosition();            
--- a/src/js/utils.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/utils.js	Wed Apr 18 18:58:44 2012 +0200
@@ -1,36 +1,5 @@
 /* utils.js - various utils that don't belong anywhere else */
 
-/* trace function, for debugging */
-
-IriSP.traceNum = 0;
-IriSP.trace = function( msg, value ) {
-/*
-	if( IriSP.config.gui.debug === true ) {
-		IriSP.traceNum += 1;
-		IriSP.jQuery( "<div>"+IriSP.traceNum+" - "+msg+" : "+value+"</div>" ).appendTo( "#Ldt-output" );
-	}
-*/
-};
-
-/* used in callbacks - because in callbacks we lose "this",
-   we need to have a special function which wraps "this" in 
-   a closure. This way, the 
-*/   
-IriSP.wrap = function (obj, fn) {
-  return function() {    
-    var args = Array.prototype.slice.call(arguments, 0);
-    return fn.apply(obj, args);
-  }
-}
-
-/* convert a time to a percentage in the media */
-IriSP.timeToPourcent = function(time, timetotal){
-	var time = Math.abs(time);
-  var timetotal = Math.abs(timetotal);
-  
-	return Math.floor((time/timetotal) * 100);
-};
-
 IriSP.padWithZeros = function(num) {
   if (Math.abs(num) < 10) {
     return "0" + num.toString();
@@ -45,24 +14,6 @@
 IriSP.msToTime = function(ms) {
   return IriSP.secondsToTime(ms / 1000);
 }
-/* convert a number of seconds to a tuple of the form 
-   [hours, minutes, seconds]
-*/
-IriSP.secondsToTime = function(secs) {  
-  var hours = Math.abs(parseInt( secs / 3600 ) % 24);
-  var minutes = Math.abs(parseInt( secs / 60 ) % 60);
-  var seconds = parseFloat(Math.abs(secs % 60).toFixed(0));
-  
-  var toString_fn = function() {
-    var ret = "";
-    if (hours > 0)
-       ret = IriSP.padWithZeros(this.hours) + ":";
-    ret += IriSP.padWithZeros(this.minutes) + ":" + IriSP.padWithZeros(this.seconds);
-
-    return ret;
-  }
-  return {"hours" : hours, "minutes" : minutes, "seconds" : seconds, toString: toString_fn};
-};
 
 /* format a tweet - replaces @name by a link to the profile, #hashtag, etc. */
 IriSP.formatTweet = function(tweet) {
@@ -114,9 +65,9 @@
 /* shortcut to have global variables in templates */
 IriSP.templToHTML = function(template, values) {
   var params = IriSP.underscore.extend(
-      { "defaults" : IriSP.default_templates_vars,
-        "l10n" : IriSP.i18n.getMessages()
-        },
+      {
+          "l10n" : IriSP.i18n.getMessages()
+      },
       values);
   return Mustache.to_html(template, params);
 };
@@ -137,12 +88,6 @@
    return IriSP.jQuery('#' + IriSP.jqEscape(text));
  }  
 
-IriSP.__guidCounter = 0;
-IriSP.guid = function(prefix) {
-  IriSP.__guidCounter += 1;
-  return prefix + IriSP.__guidCounter;
-};
-
 /** returns an url to share on facebook */
 IriSP.mkFbUrl = function(url, text) {
   if (typeof(text) === "undefined")
@@ -164,22 +109,8 @@
   return "https://plusone.google.com/_/+1/confirm?hl=en&url=" + IriSP.shorten_url(url);
 };
 
-/** test if a value is null or undefined */
-IriSP.null_or_undefined = function(val) {
-  return (typeof(val) === "undefined" || val === null);
-};
-
 /** get a property that can have multiple names **/
 
-IriSP.get_aliased = function(_obj, _aliases) {
-    for (var _i = 0; _i < _aliases.length; _i++) {
-        if (typeof _obj[_aliases[_i]] !== "undefined") {
-            return _obj[_aliases[_i]];
-        }
-    }
-    return null;
-}
-
 /** issue a call to an url shortener and return the shortened url */
 IriSP.shorten_url = function(url) {
   return encodeURIComponent(url);
--- a/src/js/widgets.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/widgets.js	Wed Apr 18 18:58:44 2012 +0200
@@ -20,12 +20,12 @@
     
     /* Setting all the configuration options */
     var _type = config.type,
-        _config = IriSP._.defaults({}, config, _player.config.gui.default_options, IriSP.widgetsDefaults[_type]),
+        _config = IriSP._.defaults({}, config, player.config.gui.default_options, IriSP.widgetsDefaults[_type]),
         _this = this;
     
     /* Creating containers if needed */
     if (typeof _config.container === "undefined") {
-        var _divs = _player.layoutDivs(_type);
+        var _divs = player.layoutDivs(_type);
         _config.container = _divs[0];
         _config.spacer = _divs[1];
     }
@@ -40,31 +40,48 @@
     this.player = player;
     
     /* Getting metadata */
-    this.source = _player.loadMetadata(this.metadata);
+    this.source = player.loadMetadata(this.metadata);
     
     /* Call draw when loaded */
     this.source.onLoad(function() {
         _this.draw();
-    })
+    });
    
     /* Adding classes and html attributes */
-    this.selector = IriSP.jQuery(this.container);
-    this.selector.addClass("Ldt-TraceMe").addClass("Ldt-Widget").attr("widget-type", _type);
+    console.log(this.container);
+    this.$ = IriSP.jQuery('#' + this.container);
+    this.$.addClass("Ldt-TraceMe").addClass("Ldt-Widget").attr("widget-type", _type);
     
     /* Does the widget require other widgets ? */
     if (typeof this.requires !== "undefined") {
         for (var _i = 0; _i < this.requires.length; _i++) {
             var _subconfig = this.requires[_i],
                 _div = IriSP.jQuery('<div>');
-            _subconfig.container = IriSP.guid(this.container + '_' + _subconfig.type + '_');
+            _subconfig.container = IriSP._.uniqueId(this.container + '_' + _subconfig.type + '_');
             _div.id = _subconfig.container;
-            this.selector.append(_div);
-            this[_subconfig.type] = new IriSP.Widgets(_player, _subconfig);
+            this.$.append(_div);
+            this[_subconfig.type] = new IriSP.Widgets(player, _subconfig);
         }
     }
     
 };
 
+IriSP.Widget.prototype.functionWrapper = function(_name) {
+    var _this = this,
+        _function = this[_name];
+    if (typeof _function !== "undefined") {
+        return function() {
+            return _function.apply(_this, Array.prototype.slice.call(arguments, 0));
+        }
+    } else {
+        console.log("Error, Unknown function IriSP." + this.type + "." + _name)
+    }
+}
+
+IriSP.Widget.prototype.bindPopcorn = function(_popcornEvent, _functionName) {
+    this.player.popcorn.listen(_popcornEvent, this.functionWrapper(_functionName))
+}
+
 /**
  * This method responsible of drawing a widget on screen.
  */
--- a/src/js/widgets/annotationsListWidget.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/widgets/annotationsListWidget.js	Wed Apr 18 18:58:44 2012 +0200
@@ -1,23 +1,16 @@
-IriSP.AnnotationsListWidget = function(Popcorn, config, Serializer) {
-  IriSP.Widget.call(this, Popcorn, config, Serializer);
-  this.__counter = 0;
-  this.__oldList = [];
-  this.searchRe = null;
-  this._ajax_cache = [];
-  var _this = this;
-  
-  this._Popcorn.listen("IriSP.search", function(searchString) {
-      _this.searchHandler(searchString);
-  });
-  this._Popcorn.listen("IriSP.search.closed", function() {
-      _this.searchHandler(false);
-  });
-  this._Popcorn.listen("IriSP.search.cleared", function() {
-      _this.searchHandler(false);
-  });
+IriSP.AnnotationsListWidget = function(player, config) {
+    IriSP.Widget.call(this, player, config);
+    this.bindPopcorn("IriSP.search", "searchHandler");
+    this.bindPopcorn("IriSP.search.closed", "searchHandler");
+    this.bindPopcorn("IriSP.search.cleared", "searchHandler");
+    this.searchString = false;
+    this.lastIds = [];
+    var _this = this;
+    this.throttledRefresh = IriSP._.throttle(function() {
+        _this.refresh(false);
+    }, 1500);
 };
 
-
 IriSP.AnnotationsListWidget.prototype = new IriSP.Widget();
 
 IriSP.AnnotationsListWidget.prototype.clear = function() {
@@ -27,254 +20,293 @@
 };
 
 IriSP.AnnotationsListWidget.prototype.searchHandler = function(searchString) {
-  this.searchRe = (searchString && searchString.length) ? IriSP.regexpFromText(searchString) : null;
-  if (this.ajax_mode && !this.cinecast_version) {
-      var _this = this,
-        _annotations = (
-            this.searchRe === null
-            ? this._ajax_cache
-            : IriSP.underscore.filter(this._ajax_cache, function(_a) {
-               return (_this.searchRe.test(_a.desc) || _this.searchRe.test(_a.title)); 
-            })
-        );
-    this.do_redraw(_annotations);
-    if (_annotations.length) {
-        this._Popcorn.trigger("IriSP.search.matchFound");
-      } else {
-        this._Popcorn.trigger("IriSP.search.noMatchFound");
-      }    
-  } else {
-      this.drawList();
-  }
+    this.searchString = typeof searchString !== "undefined" ? searchString : '';
+    var _n = this.refresh(true);
+    if (this.searchString) {
+        if (_n) {
+            this.player.popcorn.trigger("IriSP.search.matchFound");
+        } else {
+            this.player.popcorn.trigger("IriSP.search.noMatchFound");
+        }
+    }
 }
-
 /** effectively redraw the widget - called by drawList */
 IriSP.AnnotationsListWidget.prototype.do_redraw = function(list) {
-    var _html = IriSP.templToHTML(
-        IriSP.annotationsListWidget_template, {
-            annotations: list
-        }),
-        _this = this;
-      
+/*    var _html = IriSP.templToHTML(IriSP.annotationsListWidget_template, {
+        annotations : list
+    }), _this = this;
+
     this.selector.html(_html);
-    
+
     this.selector.find('.Ldt-AnnotationsList-Tag-Li').click(function() {
-        _this._Popcorn.trigger("IriSP.search.triggeredSearch", IriSP.jQuery(this).text().trim());
+        _this.player.popcorn.trigger("IriSP.search.triggeredSearch", IriSP.jQuery(this).text().trim());
     })
-    
-    if (this.searchRe !== null) {
-        this.selector.find(".Ldt-AnnotationsList-Title a, .Ldt-AnnotationsList-Description")
-            .each(function()  {
-                var _$ = IriSP.jQuery(this);
-                _$.html(_$.text().trim().replace(_this.searchRe, '<span class="Ldt-AnnotationsList-highlight">$1</span>'))
-            })
-    }
+    if(this.searchRe !== null) {
+        this.selector.find(".Ldt-AnnotationsList-Title a, .Ldt-AnnotationsList-Description").each(function() {
+            var _$ = IriSP.jQuery(this);
+            _$.html(_$.text().trim().replace(_this.searchRe, '<span class="Ldt-AnnotationsList-highlight">$1</span>'))
+        })
+    } */
 };
 
 IriSP.AnnotationsListWidget.prototype.transformAnnotation = function(a) {
-    var _this = this;
+/*    var _this = this;
     return {
         "id" : a.id,
-        "title": this.cinecast_version ? IriSP.get_aliased(a.meta, ['creator_name', 'creator']) : a.content.title,
+        "title" : this.cinecast_version ? IriSP.get_aliased(a.meta, ['creator_name', 'creator']) : a.content.title,
         "desc" : this.cinecast_version ? a.content.data : a.content.description,
-        "begin": IriSP.msToTime(a.begin),
+        "begin" : IriSP.msToTime(a.begin),
         "end" : IriSP.msToTime(a.end),
-        "thumbnail" : (typeof a.meta == "object" && typeof a.meta.thumbnail == "string") ? a.meta.thumbnail : this.default_thumbnail,
-        "url" : (typeof a.meta == "object" && typeof a.meta.url == "string") ? a.meta.url : null,
-        "created_at" :(typeof a.meta == "object" && typeof a.meta.created == "string") ? Date.parse(a.meta.created.replace(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}\:\d{2}\:\d{2}).*$/,"$2/$3/$1 $4 UTC+0000")) : null,
-        "tags": typeof a.tags == "object"
-            ? IriSP.underscore(a.tags)
-                .chain()
-                .map(function(_t) {
-                    if (typeof _t == "string") {
-                        return _t.replace(/^.*:/,'#');
-                    } else {
-                        if (typeof _t['id-ref'] != "undefined") {
-                            var _f = IriSP.underscore.find(_this._serializer._data.tags, function(_tag) {
-                                return _tag.id == _t['id-ref'];
-                            });
-                            if (typeof _f != "undefined") {
-                                return IriSP.get_aliased(_f.meta, ['dc:title', 'title']);
-                            }
-                        }
+        "thumbnail" : ( typeof a.meta == "object" && typeof a.meta.thumbnail == "string") ? a.meta.thumbnail : this.default_thumbnail,
+        "url" : ( typeof a.meta == "object" && typeof a.meta.url == "string") ? a.meta.url : null,
+        "created_at" : ( typeof a.meta == "object" && typeof a.meta.created == "string") ? Date.parse(a.meta.created.replace(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}\:\d{2}\:\d{2}).*$/, "$2/$3/$1 $4 UTC+0000")) : null,
+        "tags" : typeof a.tags == "object" ? IriSP.underscore(a.tags).chain().map(function(_t) {
+            if( typeof _t == "string") {
+                return _t.replace(/^.*:/, '#');
+            } else {
+                if( typeof _t['id-ref'] != "undefined") {
+                    var _f = IriSP.underscore.find(_this._serializer._data.tags, function(_tag) {
+                        return _tag.id == _t['id-ref'];
+                    });
+                    if( typeof _f != "undefined") {
+                        return IriSP.get_aliased(_f.meta, ['dc:title', 'title']);
                     }
-                    return null;
-                })
-                .filter(function(_t) {
-                    return _t !== null && _t !== ""
-                })
-                .value()
-            : []
-    }    
+                }
+            }
+            return null;
+        }).filter(function(_t) {
+            return _t !== null && _t !== ""
+        }).value() : []
+    } */
 }
-
 /** draw the annotation list */
 IriSP.AnnotationsListWidget.prototype.drawList = function(force_redraw) {
-  var _this = this;
-  
-//  var view_type = this._serializer.getContributions();
-  var annotations = this._serializer._data.annotations;
-  var currentTime = this._Popcorn.currentTime();
-  var list = [];
+/*    var _this = this;
+
+    //  var view_type = this._serializer.getContributions();
+    var annotations = this._serializer._data.annotations;
+    var currentTime = this.player.popcorn.currentTime();
+    var list = [];
 
-/*  if (typeof(view_type) === "undefined") {    
-    return;
-} */
-  for (i = 0; i < annotations.length; i++) {
-    var obj = this.transformAnnotation(annotations[i]);
-    obj.iterator = i;
-    obj.distance = Math.abs((annotations[i].end + annotations[i].begin) / 2000 - currentTime);
-    if (!this.cinecast_version || annotations[i].type == "cinecast:UserAnnotation") {
-        list.push(obj);
+    for( i = 0; i < annotations.length; i++) {
+        var obj = this.transformAnnotation(annotations[i]);
+        obj.iterator = i;
+        obj.distance = Math.abs((annotations[i].end + annotations[i].begin) / 2000 - currentTime);
+        if(!this.cinecast_version || annotations[i].type == "cinecast:UserAnnotation") {
+            list.push(obj);
+        }
+
     }
-    
-  }
-  
-    if (this.searchRe !== null) {
+
+    if(this.searchRe !== null) {
         list = list.filter(function(_a) {
-            return (_this.searchRe.test(_a.desc) || _this.searchRe.test(_a.title)); 
+            return (_this.searchRe.test(_a.desc) || _this.searchRe.test(_a.title));
         });
-        if (list.length) {
-            this._Popcorn.trigger("IriSP.search.matchFound");
-          } else {
-            this._Popcorn.trigger("IriSP.search.noMatchFound");
-          }
+        if(list.length) {
+            this.player.popcorn.trigger("IriSP.search.matchFound");
+        } else {
+            this.player.popcorn.trigger("IriSP.search.noMatchFound");
+        }
     }
-  list = IriSP.underscore(list)
-    .chain()
-    .sortBy(function(_o) {
+    list = IriSP.underscore(list).chain().sortBy(function(_o) {
         return _o.distance;
-    })
-    .first(10)
-    .sortBy(function(_o) {
-        return (_this.cinecast_version ? - _o.created_at : _o.iterator);
-    })
-    .value();
-  var idList = IriSP.underscore.pluck(list, "id").sort();
+    }).first(10).sortBy(function(_o) {
+        return (_this.cinecast_version ? -_o.created_at : _o.iterator);
+    }).value();
+    var idList = IriSP.underscore.pluck(list, "id").sort();
 
-  if (!IriSP.underscore.isEqual(this.__oldList, idList) || this.lastSearch !== this.searchRe || typeof(force_redraw) !== "undefined") {
-    this.do_redraw(list);
-    this.__oldList = idList;
-    this.lastSearch = this.searchRe;
-  }
-   /* save for next call */
-  
-  
+    if(!IriSP.underscore.isEqual(this.__oldList, idList) || this.lastSearch !== this.searchRe || typeof (force_redraw) !== "undefined") {
+        this.do_redraw(list);
+        this.__oldList = idList;
+        this.lastSearch = this.searchRe;
+    }
+    /* save for next call */
+
 };
 
 IriSP.AnnotationsListWidget.prototype.ajaxRedraw = function(timecode) {
 
-  /* the seeked signal sometimes passes an argument - depending on if we're using
+    /* the seeked signal sometimes passes an argument - depending on if we're using
      our popcorn lookalike or the real thing - if it's the case, use it as it's
      more precise than currentTime which sometimes contains the place we where at */
-  if (IriSP.null_or_undefined(timecode) || typeof(timecode) != "number") {
-     var tcode = this._Popcorn.currentTime();     
-   } else {
-     var tcode = timecode;     
-  }
-   
-  
-  /* the platform gives us a special url - of the type : http://path/{{media}}/{{begin}}/{{end}}
+    if(IriSP.null_or_undefined(timecode) || typeof (timecode) != "number") {
+        var tcode = this.player.popcorn.currentTime();
+    } else {
+        var tcode = timecode;
+    }
+
+    /* the platform gives us a special url - of the type : http://path/{{media}}/{{begin}}/{{end}}
      we double the braces using regexps and we feed it to mustache to build the correct url
      we have to do that because the platform only knows at run time what view it's displaying.
-  */
-     
-  var media_id = this.currentMedia()["id"];
-  var duration = this.getDuration();
-  
-  var begin_timecode = (Math.floor(tcode) - 300) * 1000;
-  if (begin_timecode < 0)
-    begin_timecode = 0;
-    
-  var end_timecode = (Math.floor(tcode) + 300) * 1000;
-  if (end_timecode > duration)
-    end_timecode = duration;
-  
-  var templ = Mustache.to_html(this.ajax_url, {media: media_id, begin: begin_timecode,
-                                 end: end_timecode});
+     */
+
+    var media_id = this.currentMedia()["id"];
+    var duration = this.getDuration();
+
+    var begin_timecode = (Math.floor(tcode) - 300) * 1000;
+    if(begin_timecode < 0)
+        begin_timecode = 0;
+
+    var end_timecode = (Math.floor(tcode) + 300) * 1000;
+    if(end_timecode > duration)
+        end_timecode = duration;
 
-  /* we create on the fly a serializer to get the ajax */
-  var serializer = new IriSP.JSONSerializer(IriSP.__dataloader, templ);
-  serializer.sync(IriSP.wrap(this, function(json) { this.processJson(json, serializer) }));
+    var templ = Mustache.to_html(this.ajax_url, {
+        media : media_id,
+        begin : begin_timecode,
+        end : end_timecode
+    });
+
+    /* we create on the fly a serializer to get the ajax */
+    var serializer = new IriSP.JSONSerializer(IriSP.__dataloader, templ);
+    serializer.sync(IriSP.wrap(this, function(json) {
+        this.processJson(json, serializer)
+    }));
 };
-
 /** process the received json - it's a bit hackish */
 IriSP.AnnotationsListWidget.prototype.processJson = function(json, serializer) {
-  /* FIXME: DRY the whole thing */
-  var annotations = serializer._data.annotations;
-  if (IriSP.null_or_undefined(annotations))
-    return;
-  
-  /*
-  commented in case we wanted to discriminate against some annotation types.
-  var view_types = serializer.getIds("Contributions");
-  */
-  var l = [];
-  
-  var media = this.currentMedia()["id"];
-  
-  for (i = 0; i < annotations.length; i++) {
-    var obj = this.transformAnnotation(annotations[i])
-      if (typeof obj.url == "undefined" || !obj.url) {
-          /* only if the annotation isn't present in the document create an
+    /* FIXME: DRY the whole thing */
+/*    var annotations = serializer._data.annotations;
+    if(IriSP.null_or_undefined(annotations))
+        return;
+
+    /*
+     commented in case we wanted to discriminate against some annotation types.
+     var view_types = serializer.getIds("Contributions");
+     */
+    var l = [];
+
+    var media = this.currentMedia()["id"];
+
+    for( i = 0; i < annotations.length; i++) {
+        var obj = this.transformAnnotation(annotations[i])
+        if( typeof obj.url == "undefined" || !obj.url) {
+            /* only if the annotation isn't present in the document create an
              external link */
-          if (this.annotations_ids.indexOf(obj.id.toLowerCase()) == -1) {
-            // braindead url; jacques didn't want to create a new one in the platform,
-            // so we append the cutting id to the url.
-            obj.url = this.project_url + "/" + media + "/" + 
-                         annotations[i].meta.project + "/" +
-                         annotations[i].meta["id-ref"] + '#id=' + annotations[i].id;
-                         
-            // obj.url = document.location.href.split("#")[0] + "/" + annotation.meta.project;
-          }
-          }
-      l.push(obj);
-  }
-  this._ajax_cache = l;
-  this.do_redraw(l);
+            if(this.annotations_ids.indexOf(obj.id.toLowerCase()) == -1) {
+                // braindead url; jacques didn't want to create a new one in the platform,
+                // so we append the cutting id to the url.
+                obj.url = this.project_url + "/" + media + "/" + annotations[i].meta.project + "/" + annotations[i].meta["id-ref"] + '#id=' + annotations[i].id;
+
+                // obj.url = document.location.href.split("#")[0] + "/" + annotation.meta.project;
+            }
+        }
+        l.push(obj);
+    }
+    this._ajax_cache = l;
+    this.do_redraw(l);
 };
+
+IriSP.AnnotationsListWidget.prototype.ajaxSource = function() {
+    var _url = Mustache.to_html(this.ajax_url, {
+        media : this.source.currentMedia.namespacedId.name,
+        begin : 0,
+        end : 0
+    });
+    console.log(_url);
+}
+
+IriSP.AnnotationsListWidget.prototype.refresh = function(_forceRedraw) {
+    if (this.currentSource.status !== IriSP.Model._SOURCE_STATUS_READY) {
+        return 0;
+    }
+    var _this = this,
+        _list = undefined,
+        _currentTime = this.player.popcorn.currentTime();
+    if (typeof _currentTime == "undefined") {
+        _currentTime = 0;
+    }
+    if (this.annotation_type) {
+        _list = this.currentSource.getAnnotationsByTypeTitle(this.annotation_type);
+    }
+    if (typeof _list === "undefined") {
+        _list = this.currentSource.getAnnotations();
+    }
+    if (this.searchString) {
+        _list = _list.searchByTextFields(this.searchString);
+    }
+    if (this.limit_count) {
+        _list = _list.sortBy(function(_annotation) {
+            return Math.abs(_annotation.begin.getSeconds() - _currentTime);
+        }).slice(0, this.limit_count)
+    }
+    if (this.newest_first) {
+        _list = _list.sortBy(function(_annotation) {
+            return -_annotation.created.valueOf();
+        });
+    } else {
+        _list = _list.sortBy(function(_annotation) {
+            return _annotation.begin.milliseconds;
+        });
+    }
+    var _ids = _list.idIndex;
+    if (!_forceRedraw && IriSP._.isEqual(_ids, this.lastIds)) {
+        return _list.length;
+    }
+    
+    /* This part only gets executed if the list needs updating */
+    this.lastIds = _ids;
+   
+    var _html = IriSP.templToHTML(
+        IriSP.annotationsListWidget_template,
+        {
+            annotations : _list.map(function(_annotation) {
+                var _res = {
+                    id : _annotation.id,
+                    title : _annotation.title.replace(_annotation.description,''),
+                    description : _annotation.description,
+                    begin : _annotation.begin.toString(),
+                    end : _annotation.end.toString(),
+                    thumbnail : typeof _annotation.thumbnail !== "undefined" ? _annotation.thumbnail : _this.default_thumbnail,
+                    url : typeof _annotation.url !== "undefined" ? _annotation.thumbnail : '#' + _annotation.namespacedId.name,
+                    tags : _annotation.getTagTexts()
+                }
+                return _res;
+            })
+        });
+
+    this.$.html(_html);
+
+    this.$.find('.Ldt-AnnotationsList-Tag-Li').click(function() {
+        _this.player.popcorn.trigger("IriSP.search.triggeredSearch", IriSP.jQuery(this).text().replace(/(^\s+|\s+$)/g,''));
+    })
+    
+    if(this.searchString) {
+        var _searchRe = new RegExp('(' + this.searchString.replace(/(\W)/gm,'\\$1') + ')','gim');
+        this.$.find(".Ldt-AnnotationsList-Title a, .Ldt-AnnotationsList-Description").each(function() {
+            var _$ = IriSP.jQuery(this);
+            _$.html(_$.text().replace(/(^\s+|\s+$)/g,'').replace(_searchRe, '<span class="Ldt-AnnotationsList-highlight">$1</span>'))
+        })
+    }
+    
+    return _list.length;
+}
+
 IriSP.AnnotationsListWidget.prototype.draw = function() {
-  
-  /* build a table of the annotations present in the document for faster 
-     lookup
-  */
-  this.annotations_ids = IriSP.underscore(this._serializer._data.annotations).map(function(_a) {
-    return _a.id.toLowerCase();
-  });
-  
-  var _this = this;
+    var _this = this;
+    
+    if (this.ajax_url && this.ajax_granularity) {
+        this.ajaxSource();
+    } else {
+        this.currentSource = this.source;
+    }
+    
+    if (this.refresh_interval) {
+        window.setInterval(function() {
+            _this.currentSource.get()
+        }, this.refresh_interval);
+    }
     
-    if (!this.ajax_mode || this.cinecast_version) {
-        var _throttled = IriSP.underscore.throttle(function() {
-            _this.drawList();
-        }, 1500);
-        _throttled();
-        this._Popcorn.listen("IriSP.createAnnotationWidget.addedAnnotation", _throttled);
-        this._Popcorn.listen("timeupdate", _throttled);
-        if (this.cinecast_version) {
-            window.setInterval(function() {
-                var _tmpSerializer = new IriSP.JSONSerializer(IriSP.__dataloader,  _this._config.metadata.src, true);
-                _tmpSerializer.sync(function(json) {
-                    IriSP.underscore(json.annotations).each(function(_a) {
-                        var _j = _this.annotations_ids.indexOf(_a.id);
-                        if (_j == -1) {
-                            _this._serializer._data.annotations.push(_a);
-                            _this.annotations_ids.push(_a.id);
-                        } else {
-                            _this._serializer._data.annotations[_j] = _a;
-                        }
-                        _throttled();
-                    });
-                }, true); // true is for force_refresh
-            },this.refresh_interval);
-        }
-  } else {
-    /* update the widget when the video has finished loading and when it's seeked and paused */
-    this._Popcorn.listen("seeked", IriSP.wrap(this, this.ajaxRedraw));
-    this._Popcorn.listen("loadedmetadata", IriSP.wrap(this, this.ajaxRedraw));
-    this._Popcorn.listen("paused", IriSP.wrap(this, this.ajaxRedraw));
+    var _events = [
+        "IriSP.createAnnotationWidget.addedAnnotation",
+        "timeupdate",
+        "seeked",
+        "loadedmetadata"
+    ];
+    for (var _i = 0; _i < _events.length; _i++) {
+        this.player.popcorn.listen(_events[_i], this.throttledRefresh);
+    }
     
-    this._Popcorn.listen("IriSP.createAnnotationWidget.addedAnnotation", IriSP.wrap(this, this.ajaxRedraw));
-  }
+    this.throttledRefresh();
 
-};
\ No newline at end of file
+};
--- a/src/js/widgets/helloWorldWidget.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/widgets/helloWorldWidget.js	Wed Apr 18 18:58:44 2012 +0200
@@ -1,15 +1,30 @@
-IriSP.HelloWorldWidget = function(Popcorn, config, Serializer) {
-  IriSP.Widget.call(this, Popcorn, config, Serializer);
+IriSP.i18n.addMessages({
+    "fr": {
+        "Hello" : "Bonjour,"
+    },
+    "en" : {
+        "Hello" : "Hello,"
+    }
+})
+
+IriSP.HelloWorldWidget = function(player, config) {
+    console.log("Calling IriSP.Widget's constructor from IriSP.HelloWorldWidget");
+    IriSP.Widget.call(this, player, config);
+    if (typeof this.text == "undefined") {
+        this.text = 'world'
+    }
 }
 
 IriSP.HelloWorldWidget.prototype = new IriSP.Widget();
 
 IriSP.HelloWorldWidget.prototype.draw = function() {
-    this.selector
-        .append('Hello, world')
-        .css({
-            "text-align" : "center",
-            "padding": "10px 0",
-            "font-size" : "14px"
-        });
+    var _tmpl = '<p>{{l10n.Hello}} {{text}}</p><p>Looks like we have {{source.contents.annotation.length}} annotations in this feed</p>'
+        _html = IriSP.templToHTML(_tmpl, this);
+    this.$.append(_html);
+    this.$.find('p').css({
+        "text-align" : "center",
+        "margin": "10px 0",
+        "font-size" : "14px"
+    });
+    console.log("HelloWorldWidget was drawn");
 }
--- a/src/js/widgets/playerWidget.js	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/js/widgets/playerWidget.js	Wed Apr 18 18:58:44 2012 +0200
@@ -34,49 +34,49 @@
 );
 
 
-IriSP.PlayerWidget = function(Popcorn, config, Serializer) {
-  IriSP.Widget.call(this, Popcorn, config, Serializer);
+IriSP.PlayerWidget = function(player, config) {
+  IriSP.Widget.call(this, player, config);
   
-  this._searchBlockOpen = false;
   this._searchLastValue = "";
 };
 
 IriSP.PlayerWidget.prototype = new IriSP.Widget();
 
 IriSP.PlayerWidget.prototype.draw = function() {
-  var self = this;
-  var width = this.width;
-	var height = this.height;
-	var heightS = this.height-20;
-	  
-	var playerTempl = IriSP.templToHTML(IriSP.player_template, this._config);
-  this.selector.append(playerTempl);		
-	
-  this.selector.children(".Ldt-controler").show();
+    var _this = this,
+        _html = IriSP.templToHTML(IriSP.player_template, this);
+    
+    this.$.append(_html);
+    
+    // Define blocks
+    this.$playButton = this.$.find(".Ldt-CtrlPlay");
+    this.$searchBlock = this.$.find(".LdtSearch");
+    this.$searchInput = this.$.find(".LdtSearchInput");
+    this.$volumeBar = this.$.find(".Ldt-Ctrl-Volume-Bar");
     
-  // handle clicks by the user on the video.
-  this._Popcorn.listen("play", IriSP.wrap(this, this.playButtonUpdater));
-  this._Popcorn.listen("pause", IriSP.wrap(this, this.playButtonUpdater));
+    // handle events
+    this.bindPopcorn("play","playButtonUpdater");
+    this.bindPopcorn("pause","playButtonUpdater");
+    this.bindPopcorn("volumechange","volumeUpdater");
+    this.bindPopcorn("timeupdate","timeDisplayUpdater");
+    this.bindPopcorn("loadedmetadata","timeDisplayUpdater");
+    this.bindPopcorn("IriSP.search.matchFound","searchMatch");
+    this.bindPopcorn("IriSP.search.noMatchFound","searchNoMatch");
+    this.bindPopcorn("IriSP.search.triggeredSearch","triggeredSearch");
+    
+    // handle clicks
+    this.$playButton.click(this.functionWrapper("playHandler"));
+    
+    this.$.find(".Ldt-CtrlAnnotate").click(function() {
+        _this.player.popcorn.trigger("IriSP.PlayerWidget.AnnotateButton.clicked");
+    });
+    this.$.find(".Ldt-CtrlSearch").click(this.functionWrapper("searchButtonHandler"));
+    
+    this.$searchInput.keyup(this.functionWrapper("searchHandler") );
   
-  this._Popcorn.listen("volumechange", IriSP.wrap(this, this.volumeUpdater));
-
-  this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater));  
-  // update the time display for the first time.
-  this._Popcorn.listen("loadedmetadata", IriSP.wrap(this, this.timeDisplayUpdater));
-  
-  this._Popcorn.listen("IriSP.search.matchFound", IriSP.wrap(this, this.searchMatch));
-  this._Popcorn.listen("IriSP.search.noMatchFound", IriSP.wrap(this, this.searchNoMatch));
-  this._Popcorn.listen("IriSP.search.triggeredSearch", IriSP.wrap(this, this.triggeredSearch));
-  
-  
-  this.selector.find(".Ldt-CtrlPlay").click(function() { self.playHandler.call(self); });
-  this.selector.find(".Ldt-CtrlAnnotate").click(function() 
-                                            { self._Popcorn.trigger("IriSP.PlayerWidget.AnnotateButton.clicked"); });
-  this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); });
-  
-	var _volctrl = this.selector.find(".Ldt-Ctrl-Volume-Control");
-    this.selector.find('.Ldt-CtrlSound')
-        .click(function() { self.muteHandler.call(self); } )
+	var _volctrl = this.$.find(".Ldt-Ctrl-Volume-Control");
+    this.$.find('.Ldt-CtrlSound')
+        .click(this.functionWrapper("muteHandler"))
         .mouseover(function() {
             _volctrl.show();
         })
@@ -89,51 +89,44 @@
         _volctrl.hide();
     });
   
-  /*
-  var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position();
-  var searchBox = Mustache.to_html(IriSP.search_template, {margin_left : searchButtonPos.left + "px"});
-  this.selector.find(".Ldt-CtrlSearch").after(searchBox);
-  */
-  
-  // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget)
-  this.selector.hover(function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOver"); }, 
-                      function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOut"); });
-  this.selector.find(".Ldt-Ctrl-Volume-Cursor").draggable({
-      axis: "x",
-      drag: function(event, ui) {
-          var _vol = Math.max(0, Math.min( 1, ui.position.left / (ui.helper.parent().width() - ui.helper.outerWidth())));
-          ui.helper.attr("title",IriSP.i18n.getMessage('volume')+': ' + Math.floor(100*_vol) + '%');
-          self._Popcorn.volume(_vol);
-      },
-      containment: "parent"
-  });
- 
- setTimeout(function() {
-     self.volumeUpdater();
- }, 1000); /* some player - jwplayer notable - save the state of the mute button between sessions */
+    
+    // Allow Volume Cursor Dragging
+    this.$volumeBar.slider({
+        slide: function(event, ui) {
+            _this.$volumeBar.attr("title",IriSP.i18n.getMessage('volume')+': ' + ui.value + '%');
+            _this.player.popcorn.volume(ui.value / 100);
+        },
+        stop: this.functionWrapper("volumeUpdater")
+    });
+
+    // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget)
+    this.$.hover(
+        function() {
+            _this.player.popcorn.trigger("IriSP.PlayerWidget.MouseOver");
+        }, 
+        function() {
+            _this.player.popcorn.trigger("IriSP.PlayerWidget.MouseOut");
+        });
+    setTimeout(this.functionWrapper("volumeUpdater"), 1000);
+    /* some players - including jwplayer - save the state of the mute button between sessions */
 };
 
 /* Update the elasped time div */
 IriSP.PlayerWidget.prototype.timeDisplayUpdater = function() {
+    var _curTime = this.player.popcorn.roundTime();
+    if (typeof this._previousSecond !== "undefined" && _curTime === this._previousSecond) {
+        return;
+    }
   
-  if (this._previousSecond === undefined) {
-    this._previousSecond = this._Popcorn.roundTime();
-  }
-  else {
-    /* we're still in the same second, so it's not necessary to update time */
-    if (this._Popcorn.roundTime() == this._previousSecond)
-      return;
-      
-  }
+    // we get it at each call because it may change.
+    var _totalTime = this.source.getDuration(),
+        _elapsedTime = new IriSP.Model.Time();
+        
+    _elapsedTime.setSeconds(_curTime);
   
-  // we get it at each call because it may change.
-  var duration = this.getDuration() / 1000; 
-  var totalTime = IriSP.secondsToTime(duration);
-  var elapsedTime = IriSP.secondsToTime(this._Popcorn.currentTime());
-  
-  this.selector.find(".Ldt-ElapsedTime").html(elapsedTime.toString());
-  this.selector.find(".Ldt-TotalTime").html(totalTime.toString());
-  this._previousSecond = this._Popcorn.roundTime();
+    this.$.find(".Ldt-ElapsedTime").html(_elapsedTime.toString());
+    this.$.find(".Ldt-TotalTime").html(_totalTime.toString());
+    this._previousSecond = _curTime;
 };
 
 /* update the icon of the button - separate function from playHandler
@@ -141,42 +134,46 @@
    the jwplayer window) we have to change the icon without playing/pausing
 */
 IriSP.PlayerWidget.prototype.playButtonUpdater = function() {
-  var status = this._Popcorn.media.paused;
+    
+    var status = this.player.popcorn.media.paused;
   
-  if ( status == true ){
+    if (status) {
     /* the background sprite is changed by adding/removing the correct classes */
-    this.selector.find(".Ldt-CtrlPlay").attr("title", IriSP.i18n.getMessage('play'));
-    this.selector.find(".Ldt-CtrlPlay").removeClass("Ldt-CtrlPlay-PauseState").addClass("Ldt-CtrlPlay-PlayState");
-  } else {
-    this.selector.find(".Ldt-CtrlPlay").attr("title", IriSP.i18n.getMessage('pause'));
-    this.selector.find(".Ldt-CtrlPlay").removeClass("Ldt-CtrlPlay-PlayState").addClass("Ldt-CtrlPlay-PauseState");
-  }  
-
-  return;
+        this.$playButton
+            .attr("title", IriSP.i18n.getMessage('play'))
+            .removeClass("Ldt-CtrlPlay-PauseState")
+            .addClass("Ldt-CtrlPlay-PlayState");
+    } else {
+        this.$playButton
+            .attr("title", IriSP.i18n.getMessage('pause'))
+            .removeClass("Ldt-CtrlPlay-PlayState")
+            .addClass("Ldt-CtrlPlay-PauseState");
+    }
 };
 
 
 IriSP.PlayerWidget.prototype.playHandler = function() {
-  var status = this._Popcorn.media.paused;
+    
+    var status = this.player.popcorn.media.paused;
   
-  if ( status == true ){        
-    this._Popcorn.play();   
-  } else {
-    this._Popcorn.pause();
-  }  
+    if (status) {        
+        this.player.popcorn.play();   
+    } else {
+        this.player.popcorn.pause();
+    }  
 };
 
 IriSP.PlayerWidget.prototype.muteHandler = function() {
-  this._Popcorn.mute(!this._Popcorn.muted());
+    this.player.popcorn.mute(!this.player.popcorn.muted());
 };
 
 IriSP.PlayerWidget.prototype.volumeUpdater = function() {
-    var _muted = this._Popcorn.muted(),
-        _vol = this._Popcorn.volume();
+    var _muted = this.player.popcorn.muted(),
+        _vol = this.player.popcorn.volume();
     if (_vol === false) {
         _vol = .5;
     }
-    var _soundCtl = this.selector.find(".Ldt-CtrlSound");
+    var _soundCtl = this.$.find(".Ldt-CtrlSound");
     _soundCtl.removeClass("Ldt-CtrlSound-Mute Ldt-CtrlSound-Half Ldt-CtrlSound-Full");
     if (_muted) {        
         _soundCtl.attr("title", IriSP.i18n.getMessage('unmute'))
@@ -185,77 +182,60 @@
         _soundCtl.attr("title", IriSP.i18n.getMessage('mute'))
             .addClass(_vol < .5 ? "Ldt-CtrlSound-Half" : "Ldt-CtrlSound-Full" )
     }
-    var _cursor = this.selector.find(".Ldt-Ctrl-Volume-Cursor");
-    _cursor.css({
-        "left": ( _muted ? 0 : Math.floor(_vol * (_cursor.parent().width() - _cursor.outerWidth())) ) + "px"
-    })
+    this.$volumeBar.slider("value", _muted ? 0 : 100 * _vol);
 };
 
 IriSP.PlayerWidget.prototype.showSearchBlock = function() {
-  var self = this;
-  
-  if (this._searchBlockOpen == false) {
-    this.selector.find(".LdtSearch").show("blind", { direction: "horizontal"}, 100);
-    this.selector.find(".LdtSearchInput").css('background-color','#fff');
+    this.$searchBlock.show("blind", { direction: "horizontal"}, 100);
+    this.$searchInput.css('background-color','#fff');
    
-    this._searchBlockOpen = true;           
-    this.selector.find(".LdtSearchInput").bind('keyup', null, function() { self.searchHandler.call(self); } );
-    this.selector.find(".LdtSearchInput").focus();
+    this.$searchInput.focus();
     
-    // we need this variable because some widget can find a match in
-    // their data while at the same time other's don't. As we want the
+    // we need this variable because some widgets can find a match in
+    // their data while at the same time others don't. As we want the
     // search field to become green when there's a match, we need a 
     // variable to remember that we had one.
     this._positiveMatch = false;
 
     // tell the world the field is open
-    this._Popcorn.trigger("IriSP.search.open");     
-	}
+    this.player.popcorn.trigger("IriSP.search.open");
 };
 
 IriSP.PlayerWidget.prototype.hideSearchBlock = function() {
- if (this._searchBlockOpen == true) {
-    this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value');
-    this.selector.find(".LdtSearchInput").attr('value','');
-    this.selector.find(".LdtSearch").hide("blind", { direction: "horizontal"}, 75);
-    
-    // unbind the watcher event.
-    this.selector.find(".LdtSearchInput").unbind('keypress set');
-    this._searchBlockOpen = false;
+    this._searchLastValue = this.$searchInput.val();
+    this.$searchInput.val('');
+    this.$searchBlock.hide("blind", { direction: "horizontal"}, 75);
 
     this._positiveMatch = false;
     
-    this._Popcorn.trigger("IriSP.search.closed");
-	}
+    this.player.popcorn.trigger("IriSP.search.closed");
 };
 
 /** react to clicks on the search button */
 IriSP.PlayerWidget.prototype.searchButtonHandler = function() {
-  var self = this;
-
-  /* show the search field if it is not shown */
-  if ( this._searchBlockOpen == false ) {
-    this.showSearchBlock();
-    this.selector.find(".LdtSearchInput").attr('value', this._searchLastValue);      
-    this._Popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural.
+    
+    if ( this.$searchBlock.is(":hidden") ) {
+        this.showSearchBlock();
+        this.$searchInput.val(this._searchLastValue);      
+        this.player.popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural.
 	} else {
-    this.hideSearchBlock();
-  }
+        this.hideSearchBlock();
+    }
 };
 
 /** this handler is called whenever the content of the search
    field changes */
 IriSP.PlayerWidget.prototype.searchHandler = function() {
-  this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value');
-  this._positiveMatch = false;
+    this._searchLastValue = this.$searchInput.val();
+    this._positiveMatch = false;
   
-  // do nothing if the search field is empty, instead of highlighting everything.
-  if (this._searchLastValue == "") {
-    this._Popcorn.trigger("IriSP.search.cleared");
-    this.selector.find(".LdtSearchInput").css('background-color','');
-  } else {
-    this._Popcorn.trigger("IriSP.search", this._searchLastValue);
-  }
+    // do nothing if the search field is empty, instead of highlighting everything.
+    if (this._searchLastValue == "") {
+        this.player.popcorn.trigger("IriSP.search.cleared");
+        this.$searchInput.css('background-color','');
+    } else {
+        this.player.popcorn.trigger("IriSP.search", this._searchLastValue);
+    }
 };
 
 /**
@@ -263,22 +243,23 @@
   highlight a match.
 */
 IriSP.PlayerWidget.prototype.searchMatch = function() {
-  this._positiveMatch = true;
-  this.selector.find(".LdtSearchInput").css('background-color','#e1ffe1');
+    this._positiveMatch = true;
+    this.$searchInput.css('background-color','#e1ffe1');
 };
 
 /** the same, except that no value could be found */
 IriSP.PlayerWidget.prototype.searchNoMatch = function() {
-  if (this._positiveMatch !== true)
-    this.selector.find(".LdtSearchInput").css('background-color', "#d62e3a");
+    if (this._positiveMatch !== true) {
+        this.$searchInput.css('background-color', "#d62e3a");
+    }
 };
 
 /** react to an IriSP.Player.triggeredSearch - that is, when
     a widget ask the PlayerWidget to do a search on his behalf */
 IriSP.PlayerWidget.prototype.triggeredSearch = function(searchString) {
-  this.showSearchBlock();
-  this.selector.find(".LdtSearchInput").attr('value', searchString);      
-  this._Popcorn.trigger("IriSP.search", searchString); // trigger the search to make it more natural.
+    this.showSearchBlock();
+    this.$searchInput.attr('value', searchString);      
+    this.player.popcorn.trigger("IriSP.search", searchString); // trigger the search to make it more natural.
 };
 
 
--- a/src/templates/annotationsListWidget.html	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/templates/annotationsListWidget.html	Wed Apr 18 18:58:44 2012 +0200
@@ -3,8 +3,6 @@
     <ul class='Ldt-AnnotationsList-ul'>
         {{#annotations}}
         <li id='Ldt-Annotation-li-{{id}}' class='Ldt-AnnotationsList-li Ldt-TraceMe'>
-            {{^url}} <a href='#id={{id}}'> {{/url}}
-            {{! otherwise link to url }}
             {{#url}} <a href='{{url}}'> {{/url}}
                 <img class='Ldt-AnnotationsList-Thumbnail' src='{{thumbnail}}' />
             </a>
@@ -14,16 +12,12 @@
                 <span class='Ldt-AnnotationsList-End'>{{end}}</span>
             </div>
             <div class='Ldt-AnnotationsList-Title'>
-            {{! if the url is not present, it means that the annotation exists
-            in the current project }}
+            {{#url}} <a href='{{url}}'> {{/url}}
                 {{title}}
+            </a>
             </div>
             <div class='Ldt-AnnotationsList-Description'>
-            {{^url}} <a href='#id={{id}}'> {{/url}}
-            {{! otherwise link to url }}
-            {{#url}} <a href='{{url}}'> {{/url}}
-                {{desc}}
-                </a>
+                {{description}}
             </div>
             {{#tags.length}}
             <ul class='Ldt-AnnotationsList-Tags'>
--- a/src/templates/player.html	Tue Apr 17 20:19:46 2012 +0200
+++ b/src/templates/player.html	Wed Apr 18 18:58:44 2012 +0200
@@ -27,6 +27,5 @@
 	</div>
 	<div class='Ldt-Ctrl-Volume-Control' title='{{l10n.volume_control}}'>
 	    <div class='Ldt-Ctrl-Volume-Bar'></div>
-	    <div class='Ldt-Ctrl-Volume-Cursor'></div>
 	</div>
 </div>
--- a/test/integration/polemic.htm	Tue Apr 17 20:19:46 2012 +0200
+++ b/test/integration/polemic.htm	Wed Apr 18 18:58:44 2012 +0200
@@ -24,12 +24,12 @@
   IriSP.libFiles.defaultDir = "/metadataplayer/src/js/libs/";
 IriSP.jwplayer_swf_path = "../libs/player.swf";
     var _metadata = {
-        url: 'polemic_fr.json',
+        url: 'http://ldt.iri.centrepompidou.fr/ldtplatform/ldt/cljson/id/13b0aa52-336b-11e0-b233-00145ea49a02?callback=?',
         format: 'ldt'
     };
     var _config = {            
-        gui:{
-            width:640,
+        gui: {
+        width:640,
             height:800,              
             container:'LdtPlayer',
 			default_options: {
@@ -58,7 +58,6 @@
             {type: "SparklineWidget",
              width: 640,
              height: 50},
-            {type: "SliderWidget"},
             {type: "PlayerWidget"},
             {type: "SegmentsWidget",
              requires: [{
@@ -73,15 +72,23 @@
             {type: "TweetsWidget"},
             {type: "createAnnotationWidget"},
             {type: "TagCloudWidget",
-            excludeWords: ['#museoweb']},
-            {type: "AnnotationsListWidget",
-            container: "AnnotationsListContainer",
-            ajax_mode: false}, */
+            excludeWords: ['#museoweb']},, */
 //            {type: "TraceWidget"}
+                {
+                    type: "PlayerWidget"
+                },
+                {
+                    type: "HelloWorldWidget"
+                },
+                {
+                    type: "AnnotationsListWidget",
+                /*    ajax_url : "http://ldt.iri.centrepompidou.fr/ldt/api/ldt/segments/{{media}}/{{begin}}/{{end}}", */
+                    container: "AnnotationsListContainer"
+                }
             ]
         },
       player:{
-          type:'jwplayer', // player type - 
+          type:'jwplayer', // player type
           live: true, 
           height: 300, 
           width: 640,