finished AnnotationsList and started New PolemicWidget new-model
authorveltr
Thu, 19 Apr 2012 19:20:41 +0200
branchnew-model
changeset 872 d777d05a16e4
parent 870 2c025db10a10
child 874 38b65761a7d5
finished AnnotationsList and started New PolemicWidget
src/js/defaults.js
src/js/model.js
src/js/serializers/CinecastSerializer.js
src/js/serializers/PlatformSerializer.js
src/js/widgets.js
src/js/widgets/annotationsListWidget.js
src/js/widgets/polemicNewWidget.js
test/integration/polemic.htm
test/model/test.html
--- a/src/js/defaults.js	Wed Apr 18 18:58:44 2012 +0200
+++ b/src/js/defaults.js	Thu Apr 19 19:20:41 2012 +0200
@@ -104,20 +104,25 @@
          implementers.
          Note that the player has to replace the variables between {{ and }} by its own values.
          */
-        ajax_url : false, //platform_url + "/ldtplatform/api/ldt/segments/{{media}}/{{begin}}/{{end}}",
+        ajax_url : false,
+        /* URL when the annotations are to be reloaded from an LDT-like segment API
+         * e.g. http://ldt.iri.centrepompidou.fr/ldtplatform/api/ldt/segments/{{media}}/{{begin}}/{{end}}?callback=?
+         */
         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 */
+        foreign_url : "",
+        /* URL when the annotation is not in the current project,
+         * e.g. http://ldt.iri.centrepompidou.fr/ldtplatform/ldt/front/player/{{media}}/{{project}}/{{annotationType}}#id={{annotation}}
+         */
         cinecast_version : false,
         annotation_type : false,
-        refresh_interval : 300000,
+        refresh_interval : 0,
         limit_count : 10,
         newest_first : false
     },
     "StackGraphWidget" : {
-         defaultcolor : "#585858",
-         tags : [
+        defaultcolor : "#585858",
+        tags : [
             {
                 "keywords" : [ "++" ],
                 "description" : "positif",
@@ -140,5 +145,34 @@
             }
         ],
         streamgraph : false
+    },
+    "PolemicNewWidget" : {
+        element_width : 5,
+        element_height : 5,
+        annotation_type : "tweet",
+        defaultcolor : "#585858",
+        foundcolor : "#fc00ff",
+        tags : [
+            {
+                "keywords" : [ "++" ],
+                "description" : "positif",
+                "color" : "#1D973D"
+            },
+            {
+                "keywords" : [ "--" ],
+                "description" : "negatif",
+                "color" : "#CE0A15"
+            },
+            {
+                "keywords" : [ "==" ],
+                "description" : "reference",
+                "color" : "#C5A62D"  
+            },
+            {
+                "keywords" : [ "??" ],
+                "description" : "question",
+                "color" : "#036AAE"
+            }
+        ]
     }
 }
\ No newline at end of file
--- a/src/js/model.js	Wed Apr 18 18:58:44 2012 +0200
+++ b/src/js/model.js	Thu Apr 19 19:20:41 2012 +0200
@@ -8,6 +8,20 @@
     getUID : function() {
         return "autoid-" + (++this._ID_AUTO_INCREMENT);
     },
+    regexpFromTextOrArray : function(_textOrArray) {
+        function escapeText(_text) {
+            return _text.replace(/([\\\*\+\?\|\{\[\}\]\(\)\^\$\.\#\/])/gm, '\\$1');
+        }
+        return new RegExp( '('
+            + (
+                typeof _textOrArray === "string"
+                ? escapeText(_textOrArray)
+                : IriSP._(_textOrArray).map(escapeText).join("|")
+            )
+            + ')',
+            'gim'
+        );
+    },
     isoToDate : function(_str) {
         // http://delete.me.uk/2005/03/iso8601.html
         var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
@@ -52,7 +66,7 @@
     this.directory = _directory;
     this.idIndex = [];
     if (typeof _directory == "undefined") {
-        throw("Error : new IriSP.Model.List(directory): directory is undefined");
+        throw "Error : new IriSP.Model.List(directory): directory is undefined";
     }
 }
 
@@ -107,6 +121,13 @@
     return _res;
 }
 
+IriSP.Model.List.prototype.splice = function(_start, _end) {
+    var _res = new IriSP.Model.List(this.directory);
+    _res.addElements(Array.prototype.splice.call(this, _start, _end));
+    this.idIndex.splice(_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
  */
@@ -123,21 +144,21 @@
  * here we can search by these criteria
  */
 IriSP.Model.List.prototype.searchByTitle = function(_text) {
-    var _rgxp = new RegExp('(' + _text.replace(/(\W)/gm,'\\$1') + ')','gim');
+    var _rgxp = IriSP.Model.regexpFromTextOrArray(_text);
     return this.filter(function(_element) {
         return _rgxp.test(_element.title);
     });
 }
 
 IriSP.Model.List.prototype.searchByDescription = function(_text) {
-    var _rgxp = new RegExp('(' + _text.replace(/(\W)/gm,'\\$1') + ')','gim');
+    var _rgxp = IriSP.Model.regexpFromTextOrArray(_text);
     return this.filter(function(_element) {
         return _rgxp.test(_element.description);
     });
 }
 
 IriSP.Model.List.prototype.searchByTextFields = function(_text) {
-    var _rgxp = new RegExp('(' + _text.replace(/(\W)/gm,'\\$1') + ')','gim');
+    var _rgxp =  IriSP.Model.regexpFromTextOrArray(_text);
     return this.filter(function(_element) {
         return _rgxp.test(_element.description) || _rgxp.test(_element.title);
     });
@@ -158,8 +179,8 @@
 }
 
 IriSP.Model.List.prototype.push = function(_el) {
-    if (typeof this.directory.getElement(_el.id) === "undefined") {
-        this.directory.addElement(_el);
+    if (typeof _el === "undefined") {
+        return;
     }
     var _index = (IriSP._(this.idIndex).indexOf(_el.id));
     if (_index === -1) {
@@ -185,6 +206,31 @@
     });
 }
 
+IriSP.Model.List.prototype.removeId = function(_id) {
+    var _index = (IriSP._(this.idIndex).indexOf(_id));
+    if (_index !== -1) {
+        this.splice(_index,1);
+    }
+}
+
+IriSP.Model.List.prototype.removeElement = function(_el) {
+    this.removeId(_el.id);
+}
+
+IriSP.Model.List.prototype.removeIds = function(_list) {
+    var _this = this;
+    IriSP._(_list).forEach(function(_id) {
+        _this.removeId(_id);
+    });
+}
+
+IriSP.Model.List.prototype.removeElements = function(_list) {
+    var _this = this;
+    IriSP._(_list).forEach(function(_el) {
+        _this.removeElement(_el);
+    });
+}
+
 /* A simple time management object, that helps converting millisecs to seconds and strings,
  * without the clumsiness of the original Date object.
  */
@@ -210,6 +256,10 @@
     } 
 }
 
+IriSP.Model.Time.prototype.valueOf = function() {
+    return this.milliseconds;
+}
+
 IriSP.Model.Time.prototype.toString = function() {
     function pad(_n) {
         var _res = _n.toString();
@@ -234,13 +284,38 @@
     this.source = _source;
     if (typeof _idRef === "object") {
         this.isList = true;
-        this.contents = new IriSP.Model.List(this.source.directory);
-        this.contents.addIds(IriSP._(_idRef).map(function(_id) {
+        this.id = IriSP._(_idRef).map(function(_id) {
             return _source.getNamespaced(_id).fullname;
-        }));
+        });
     } else {
         this.isList = false;
-        this.contents = this.source.directory.getElement(_source.getNamespaced(_idRef).fullname);
+        this.id = _source.getNamespaced(_idRef).fullname;
+    }
+    this.refresh();
+}
+
+IriSP.Model.Reference.prototype.refresh = function() {
+    if (this.isList) {
+        this.contents = new IriSP.Model.List(this.source.directory);
+        this.contents.addIds(this.id);
+    } else {
+        this.contents = this.source.directory.getElement(this.id);
+    }
+    
+}
+
+IriSP.Model.Reference.prototype.getContents = function() {
+    if (typeof this.contents === "undefined" || (this.isList && this.contents.length != this.id.length)) {
+        this.refresh();
+    }
+    return this.contents;
+}
+
+IriSP.Model.Reference.prototype.isOrHasId = function(_idRef) {
+    if (this.isList) {
+        return (IriSP._(this.id).indexOf(_idRef) !== -1)
+    } else {
+        return (this.id == _idRef);
     }
 }
 
@@ -248,17 +323,18 @@
 
 IriSP.Model.Element = function(_id, _source) {
     this.elementType = 'element';
-    if (typeof _source !== "undefined") {
-        if (typeof _id === "undefined" || !_id) {
-            _id = IriSP.Model.getUID();
-        }
-        this.source = _source;
-        this.namespacedId = _source.getNamespaced(_id)
-        this.id = this.namespacedId.fullname;
-        this.title = "";
-        this.description = "";
-        this.source.directory.addElement(this);
+    if (typeof _source === "undefined") {
+        return;
+    }
+    if (typeof _id === "undefined" || !_id) {
+        _id = IriSP.Model.getUID();
     }
+    this.source = _source;
+    this.namespacedId = _source.getNamespaced(_id)
+    this.id = this.namespacedId.fullname;
+    this.title = "";
+    this.description = "";
+    this.source.directory.addElement(this);
 }
 
 IriSP.Model.Element.prototype.toString = function() {
@@ -271,20 +347,16 @@
 
 IriSP.Model.Element.prototype.getReference = function(_elementType) {
     if (typeof this[_elementType] !== "undefined") {
-        return this[_elementType].contents;
+        return this[_elementType].getContents();
     }
 }
 
-IriSP.Model.Element.prototype.getRelated = function(_elementType) {
+IriSP.Model.Element.prototype.getRelated = function(_elementType, _global) {
+    _global = (typeof _global !== "undefined" && _global);
     var _this = this;
-    return this.source.getList(_elementType).filter(function(_el) {
+    return this.source.getList(_elementType, _global).filter(function(_el) {
         var _ref = _el[_this.elementType];
-        if (_ref.isList) {
-            return _ref.contents.hasId(_this.id);
-        }
-        else {
-            return _ref.contents.id === _this.id;
-        }
+        return _ref.isOrHasId(_this.id);
     });
 }
 
@@ -393,12 +465,26 @@
         this.callbackQueue = [];
         this.contents = {};
         if (typeof this.namespace === "undefined") {
-            this.namespace = IriSP.Model.getUID();
+            this.namespace = "metadataplayer";
+        } else {
+            if (typeof this.namespaceUrl === "undefined" && typeof this.url !== "undefined") {
+                var _matches = this.url.match(/(^[^?&]+|[^?&][a-zA-Z0-9_%=?]+)/g),
+                    _url = _matches[0];
+                if (_matches.length > 1) {
+                    _matches = IriSP._(_matches.slice(1)).reject(function(_txt) {
+                        return /\?$/.test(_txt);
+                    });
+                }
+                if (_matches.length > 0) {
+                    _url += '?' + _matches.join('&');
+                }
+                this.namespaceUrl = _url;
+            }
         }
         if (typeof this.namespaceUrl === "undefined") {
-            this.namespaceUrl = (typeof this.url !== "undefined" ? this.url : this.namespaceUrl);
+            this.namespaceUrl = "http://ldt.iri.centrepompidou.fr/";
         }
-        this.directory.namespaces[this.namespace] = this.namespaceUrl;
+        this.directory.addNamespace(this.namespace, this.namespaceUrl);
         this.get();
     }
 }
@@ -421,7 +507,9 @@
 }
     
 IriSP.Model.Source.prototype.unNamespace = function(_id) {
-    return _id.replace(this.namespace + ':', '');
+    if (typeof _id !== "undefined") {
+        return _id.replace(this.namespace + ':', '');
+    }
 }
 
 IriSP.Model.Source.prototype.addList = function(_listId, _contents) {
@@ -431,10 +519,11 @@
     this.contents[_listId].addElements(_contents);
 }
 
-IriSP.Model.Source.prototype.getList = function(_listId) {
-    if (typeof this.contents[_listId] === "undefined") {
+IriSP.Model.Source.prototype.getList = function(_listId, _global) {
+    _global = (typeof _global !== "undefined" && _global);
+    if (_global || typeof this.contents[_listId] === "undefined") {
         return this.directory.getGlobalList().filter(function(_e) {
-            return (_e.elType === _listId);
+            return (_e.elementType === _listId);
         });
     } else {
         return this.contents[_listId];
@@ -515,30 +604,29 @@
     this.serializer.deSerialize(_data, this);
 }
 
-IriSP.Model.Source.prototype.getAnnotations = function() {
-    return this.getList("annotation");
+IriSP.Model.Source.prototype.getAnnotations = function(_global) {
+    _global = (typeof _global !== "undefined" && _global);
+    return this.getList("annotation", _global);
 }
 
-IriSP.Model.Source.prototype.getMedias = function() {
-    return this.getList("media");
-}
-
-IriSP.Model.Source.prototype.getAnnotationTypes = function() {
-    return this.getList("annotationType");
+IriSP.Model.Source.prototype.getMedias = function(_global) {
+    _global = (typeof _global !== "undefined" && _global);
+    return this.getList("media", _global);
 }
 
-IriSP.Model.Source.prototype.getAnnotationTypeByTitle = function(_title) {
-    var _res = this.getAnnotationTypes().searchByTitle(_title);
-    if (_res.length) {
-        return _res[0];
-    }
+IriSP.Model.Source.prototype.getAnnotationTypes = function(_global) {
+    _global = (typeof _global !== "undefined" && _global);
+    return this.getList("annotationType", _global);
 }
 
-IriSP.Model.Source.prototype.getAnnotationsByTypeTitle = function(_title) {
-    var _annType = this.getAnnotationTypeByTitle(_title);
-    if (typeof _annType !== "undefined") {
-        return _annType.getAnnotations();
-    }
+IriSP.Model.Source.prototype.getAnnotationsByTypeTitle = function(_title, _global) {
+    _global = (typeof _global !== "undefined" && _global);
+    var _res = new IriSP.Model.List(this.directory),
+        _annTypes = this.getAnnotationTypes(_global).searchByTitle(_title);
+    _annTypes.forEach(function(_annType) {
+        _res.addElements(_annType.getAnnotations(_global));
+    })
+    return _res;
 }
 
 IriSP.Model.Source.prototype.getDuration = function() {
@@ -559,7 +647,7 @@
 IriSP.Model.RemoteSource.prototype.get = function() {
     this.status = IriSP.Model._SOURCE_STATUS_WAITING;
     var _this = this;
-    IriSP.jQuery.getJSON(this.url, function(_result) {
+    this.serializer.loadData(this.url, function(_result) {
         _this.deSerialize(_result);
         _this.handleCallbacks();
     });
@@ -573,6 +661,10 @@
     this.namespaces = {};
 }
 
+IriSP.Model.Directory.prototype.addNamespace = function(_namespace, _url) {
+    this.namespaces[_namespace] = _url;
+}
+
 IriSP.Model.Directory.prototype.remoteSource = function(_properties) {
     var _config = IriSP._({ directory: this }).extend(_properties);
     if (typeof this.remoteSources[_properties.url] === "undefined") {
--- a/src/js/serializers/CinecastSerializer.js	Wed Apr 18 18:58:44 2012 +0200
+++ b/src/js/serializers/CinecastSerializer.js	Thu Apr 19 19:20:41 2012 +0200
@@ -116,15 +116,15 @@
                     },
                     begin : _data.begin.milliseconds,
                     end : _data.begin.milliseconds,
-                    media : _source.unNamespace(_data.media.contents),
-                    type : _source.unNamespace(_data.annotationType.contents),
+                    media : _source.unNamespace(_data.media.id),
+                    type : _source.unNamespace(_data.annotationType.id),
                     meta : {
                         created : IriSP.Model.dateToIso(_data.created),
                         creator : _data.creator,
                         creator_name : _data.title
                     },
-                    tags : _data.getTags().map(function(_el) {
-                        return _source.unNamespace(_el.id)
+                    tags : _data.tag.id.map(function(_id) {
+                        return _source.unNamespace(_id)
                     })
                 }
             }
@@ -154,7 +154,13 @@
         });
         return _res;
     },
+    loadData : function(_url, _callback) {
+        IriSP.jQuery.getJSON(_url, _callback)
+    },
     deSerialize : function(_data, _source) {
+        if (typeof _data !== "object" && _data === null) {
+            return;
+        }
         if (typeof _data.imports !== "undefined") {
             IriSP._(_data.imports).forEach(function(_import) {
                 _source.directory.namespaces[_import.id] = _import.url;
--- a/src/js/serializers/PlatformSerializer.js	Wed Apr 18 18:58:44 2012 +0200
+++ b/src/js/serializers/PlatformSerializer.js	Thu Apr 19 19:20:41 2012 +0200
@@ -77,8 +77,8 @@
             serialized_name : "annotations",
             deserializer : function(_data, _source) {
                 var _res = new IriSP.Model.Annotation(_data.id, _source);
-                _res.title = _data.content.title;
-                _res.description = _data.content.description;
+                _res.title = _data.content.title || "";
+                _res.description = _data.content.description || "";
                 _res.created = IriSP.Model.isoToDate(_data.meta["dc:created"]);
                 var _c = parseInt(_data.color).toString(16);
                 while (_c.length < 6) {
@@ -91,6 +91,7 @@
                 _res.setBegin(_data.begin);
                 _res.setEnd(_data.end);
                 _res.creator = _data.meta["dc:creator"];
+                _res.project = _data.meta.project;
                 return _res;
             },
             serializer : function(_data, _source) {
@@ -100,13 +101,14 @@
                         title : _data.title,
                         description : _data.description
                     },
-                    media : _source.unNamespace(_data.media.contents),
+                    media : _source.unNamespace(_data.media.id),
                     meta : {
-                        "id-ref" : _source.unNamespace(_data.annotationType.contents),
+                        "id-ref" : _source.unNamespace(_data.annotationType.id),
                         "dc:created" : IriSP.Model.dateToIso(_data.created),
-                        "dc:creator" : _data.creator
+                        "dc:creator" : _data.creator,
+                        project : _source.projectId
                     },
-                    tags : _data.getTags().map(function(_el, _id) {
+                    tags : IriSP._(_data.tag.id).map(function(_d) {
                        return {
                            "id-ref" : _source.unNamespace(_id)
                        } 
@@ -127,7 +129,13 @@
         });
         return _res;
     },
+    loadData : function(_url, _callback) {
+        IriSP.jQuery.getJSON(_url, _callback)
+    },
     deSerialize : function(_data, _source) {
+        if (typeof _data !== "object" && _data === null) {
+            return;
+        }
         IriSP._(this.types).forEach(function(_type, _typename) {
             var _listdata = _data[_type.serialized_name];
             if (typeof _listdata !== "undefined") {
@@ -144,6 +152,10 @@
             }
         });
         
+        if (typeof _data.meta !== "undefined") {
+            _source.projectId = _data.meta.id;
+        }
+        
         if (typeof _data.meta !== "undefined" && typeof _data.meta.main_media !== "undefined" && typeof _data.meta.main_media["id-ref"] !== "undefined") {
             _source.setCurrentMediaId(_data.meta.main_media["id-ref"]);
         }
--- a/src/js/widgets.js	Wed Apr 18 18:58:44 2012 +0200
+++ b/src/js/widgets.js	Thu Apr 19 19:20:41 2012 +0200
@@ -34,6 +34,10 @@
        _this[_key] = _value;
     });
     
+    if (typeof this.width === "undefined") {
+        this.width = player.config.gui.width;
+    }
+    
     /* Setting this.player at the end in case it's been overriden
      * by a configuration option of the same name :-(
      */
--- a/src/js/widgets/annotationsListWidget.js	Wed Apr 18 18:58:44 2012 +0200
+++ b/src/js/widgets/annotationsListWidget.js	Thu Apr 19 19:20:41 2012 +0200
@@ -30,198 +30,38 @@
         }
     }
 }
-/** 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;
 
-    this.selector.html(_html);
-
-    this.selector.find('.Ldt-AnnotationsList-Tag-Li').click(function() {
-        _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>'))
-        })
-    } */
-};
-
-IriSP.AnnotationsListWidget.prototype.transformAnnotation = function(a) {
-/*    var _this = this;
-    return {
-        "id" : a.id,
-        "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),
-        "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']);
-                    }
-                }
-            }
-            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.player.popcorn.currentTime();
-    var list = [];
-
-    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) {
-        list = list.filter(function(_a) {
-            return (_this.searchRe.test(_a.desc) || _this.searchRe.test(_a.title));
-        });
-        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) {
-        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();
-
-    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
-     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.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
-    });
-
-    /* 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
-             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);
-};
+//obj.url = this.project_url + "/" + media + "/" + annotations[i].meta.project + "/" + annotations[i].meta["id-ref"] + '#id=' + annotations[i].id;
 
 IriSP.AnnotationsListWidget.prototype.ajaxSource = function() {
+    var _currentTime = this.player.popcorn.currentTime(),
+        _duration = this.source.getDuration();
+    if (typeof _currentTime == "undefined") {
+        _currentTime = 0;
+    }
+    this.lastAjaxQuery = _currentTime;
+    _currentTime = Math.floor(1000 * _currentTime);
     var _url = Mustache.to_html(this.ajax_url, {
         media : this.source.currentMedia.namespacedId.name,
-        begin : 0,
-        end : 0
+        begin : Math.max(0, _currentTime - this.ajax_granularity),
+        end : Math.min(_duration.milliseconds, _currentTime + this.ajax_granularity)
     });
-    console.log(_url);
+    this.currentSource = this.player.loadMetadata(IriSP._.defaults({
+        "url" : _url
+    }, this.metadata));
 }
 
 IriSP.AnnotationsListWidget.prototype.refresh = function(_forceRedraw) {
+    _forceRedraw = (typeof _forceRedraw !== "undefined" && _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();
-    }
+    var _list = this.annotation_type ? this.currentSource.getAnnotationsByTypeTitle(this.annotation_type, true) : this.currentSource.getAnnotations();
     if (this.searchString) {
         _list = _list.searchByTextFields(this.searchString);
     }
@@ -236,49 +76,71 @@
         });
     } else {
         _list = _list.sortBy(function(_annotation) {
-            return _annotation.begin.milliseconds;
+            return _annotation.begin;
         });
     }
-    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;
+    var _ids = _list.idIndex;
+    
+    if (_forceRedraw || !IriSP._.isEqual(_ids, this.lastIds)) {
+        /* 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 _url = (
+                        ( typeof _annotation.url !== "undefined" )
+                        ? _annotation.url
+                        : (
+                            ( typeof _this.source.projectId !== "undefined" && typeof _annotation.project !== "undefined" && _this.source.projectId !== _annotation.project )
+                            ? Mustache.to_html(
+                                this.foreign_url,
+                                {
+                                    project : _annotation.project,
+                                    media : _annotation.media.id.replace(/^.*:/,''),
+                                    annotation : _annotation.namespacedId.name,
+                                    annotationType : _annotation.annotationType.id.replace(/^.*:/,'')
+                                }
+                            )
+                            : '#id=' + _annotation.namespacedId.name
+                            )
+                    );
+                    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 : _url,
+                        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>'))
             })
-        });
-
-    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>'))
-        })
+        }
     }
     
+    if (this.ajax_url && this.ajax_granularity) {
+        if (Math.abs(_currentTime - this.lastAjaxQuery) > this.ajax_granularity / 2) {
+            this.ajaxSource();
+        }
+    }
     return _list.length;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/js/widgets/polemicNewWidget.js	Thu Apr 19 19:20:41 2012 +0200
@@ -0,0 +1,174 @@
+IriSP.PolemicNewWidget = 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.bindPopcorn("timeupdate", "onTimeupdate");
+    this.sliceCount = Math.floor( this.width / this.element_width );
+    this.$zone = IriSP.jQuery('<div>');
+    this.$.append(this.$zone);
+};
+
+IriSP.PolemicNewWidget.prototype = new IriSP.Widget();
+
+IriSP.PolemicNewWidget.prototype.searchHandler = function(searchString) {
+    this.searchString = typeof searchString !== "undefined" ? searchString : '';
+    var _found = 0,
+        _re = IriSP.Model.regexpFromTextOrArray(searchString)
+        _this = this;
+    this.$tweets.each(function() {
+        var _el = IriSP.jQuery(this);
+        if (_this.searchString) {
+            if (_re.test(_el.attr("title"))) {
+                _el.css({
+                    "background" : _this.foundcolor,
+                    "opacity" : 1
+                });
+                _found++;
+            } else {
+                _el.css({
+                    "background" : _el.attr("polemic-color"),
+                    "opacity" : .6
+                });
+            }
+        } else {
+            _el.css({
+                "background" : _el.attr("polemic-color"),
+                "opacity" : 1
+            });
+        }
+    });
+    if (this.searchString) {
+        if (_found) {
+            this.player.popcorn.trigger("IriSP.search.matchFound");
+        } else {
+            this.player.popcorn.trigger("IriSP.search.noMatchFound");
+        }
+    }
+}
+
+IriSP.PolemicNewWidget.prototype.draw = function() {
+    var _slices = [],
+        _duration = this.source.getDuration(),
+        _max = 0,
+        _list = this.annotation_type ? this.source.getAnnotationsByTypeTitle(this.annotation_type) : this.source.getAnnotations();
+    
+    for (var _i = 0; _i < this.sliceCount; _i++) {
+        var _begin = new IriSP.Model.Time(_i*_duration/this.sliceCount),
+            _end = new IriSP.Model.Time((_i+1)*_duration/this.sliceCount),
+            _count = 0,
+            _res = {
+                annotations : _list.filter(function(_annotation) {
+                    return _annotation.begin >= _begin && _annotation.end < _end;
+                }),
+                polemicStacks : []
+            }
+            
+        for (var _j = 0; _j < this.tags.length; _j++) {
+            var _polemic = _res.annotations.searchByDescription(this.tags[_j].keywords);
+            _count += _polemic.length;
+            _res.polemicStacks.push(_polemic);
+        }
+        for (var _j = 0; _j < this.tags.length; _j++) {
+            _res.annotations.removeElements(_res.polemicStacks[_j]);
+        }
+        _count += _res.annotations.length;
+        _max = Math.max(_max, _count);
+        _slices.push(_res);
+    }
+    this.height = (_max ? (_max + 2) * this.element_height : 0);
+    console.log(this.height);
+    this.$zone.css({
+        width: this.width + "px",
+        height: this.height + "px",
+        position: "relative"
+    });
+    
+    this.$elapsed = IriSP.jQuery('<div>')
+        .css({
+            background: '#cccccc',
+            position: "absolute",
+            top: 0,
+            left: 0,
+            width: 0,
+            height: "100%"
+        });
+        
+    this.$zone.append(this.$elapsed);
+    
+    var _x = 0,
+        _this = this;
+    
+    function displayElement(_x, _y, _color, _id, _title) {
+        var _el = IriSP.jQuery('<div>')
+            .attr({
+                title : _title,
+                "pos-x" : _x,
+                "pos-y" : _y,
+                "polemic-color" : _color,
+                "annotation-id" : _id
+            })
+            .css({
+                position: "absolute",
+                width: (_this.element_width-1) + "px",
+                height: _this.element_height + "px",
+                left: _x + "px",
+                top: _y + "px",
+                background: _color
+            })
+            .addClass("Ldt-Polemic-TweetDiv");
+        _this.$zone.append(_el);
+        return _el;
+    }
+    
+    IriSP._(_slices).forEach(function(_slice) {
+        var _y = _this.height;
+        _slice.annotations.forEach(function(_annotation) {
+            _y -= _this.element_height;
+            displayElement(_x, _y, _this.defaultcolor, _annotation.namespacedId.name, _annotation.title);
+        });
+        IriSP._(_slice.polemicStacks).forEach(function(_annotations, _j) {
+            var _color = _this.tags[_j].color;
+            _annotations.forEach(function(_annotation) {
+                _y -= _this.element_height;
+                displayElement(_x, _y, _color, _annotation.namespacedId.name, _annotation.title);
+            });
+        });
+        _x += _this.element_width;
+    });
+    
+    this.$tweets = this.$.find(".Ldt-Polemic-TweetDiv");
+    
+    this.$position = IriSP.jQuery('<div>')
+        .css({
+            background: '#fc00ff',
+            position: "absolute",
+            top: 0,
+            left: "-1px",
+            width: "2px",
+            height: "100%"
+        });
+        
+    this.$zone.append(this.$position);
+    
+    this.$tweets.click(function(_e) {
+        //TODO: Display Tweet in Tweet Widget
+    });
+    
+    //TODO: Mouseover a tweet to display tooltip
+    
+    this.$zone.click(function(_e) {
+        var _x = _e.pageX - _this.$zone.offset().left;
+        _this.player.popcorn.currentTime(_this.source.getDuration().getSeconds() * _x / _this.width);
+    });
+}
+
+IriSP.PolemicNewWidget.prototype.onTimeupdate = function() {
+    var _x = Math.floor( this.width * this.player.popcorn.currentTime() / this.source.getDuration().getSeconds());
+    this.$elapsed.css({
+        width:  _x + "px"
+    });
+    this.$position.css({
+        left: (_x - 1) + "px"
+    })
+}
--- a/test/integration/polemic.htm	Wed Apr 18 18:58:44 2012 +0200
+++ b/test/integration/polemic.htm	Thu Apr 19 19:20:41 2012 +0200
@@ -29,7 +29,7 @@
     };
     var _config = {            
         gui: {
-        width:640,
+            width:640,
             height:800,              
             container:'LdtPlayer',
 			default_options: {
@@ -78,11 +78,16 @@
                     type: "PlayerWidget"
                 },
                 {
+                    type: "PolemicNewWidget"
+                },
+                {
                     type: "HelloWorldWidget"
                 },
                 {
                     type: "AnnotationsListWidget",
-                /*    ajax_url : "http://ldt.iri.centrepompidou.fr/ldt/api/ldt/segments/{{media}}/{{begin}}/{{end}}", */
+                    ajax_url : "http://ldt.iri.centrepompidou.fr/ldtplatform/api/ldt/segments/{{media}}/{{begin}}/{{end}}?callback=?",
+                    foreign_url : "http://ldt.iri.centrepompidou.fr/ldtplatform/ldt/front/player/{{media}}/{{project}}/{{annotationType}}#id={{annotation}}",
+                    annotation_type : "tweet",
                     container: "AnnotationsListContainer"
                 }
             ]
--- a/test/model/test.html	Wed Apr 18 18:58:44 2012 +0200
+++ b/test/model/test.html	Thu Apr 19 19:20:41 2012 +0200
@@ -19,7 +19,7 @@
             var _source = _directory.remoteSource({
                 //url: "../integration/polemic_fr.json",
                 url : '../integration/allocine_dossier_independant/json_examples/movie32.json',
-                namespace: "metadataplayer",
+                namespace: "cinecast",
                 serializer: IriSP.serializers.cinecast
             });
             function showExport() {