src/js/serializers/JSONSerializer.js
branchnew-model
changeset 866 3bf7aa8216e5
parent 864 5e76a06b961c
child 868 a525cc2214e7
equal deleted inserted replaced
864:5e76a06b961c 866:3bf7aa8216e5
     1 /** @class This class implement a serializer for the JSON-Cinelab format
       
     2     @params DataLoader a dataloader reference
       
     3     @url the url from which to get our cinelab
       
     4  */
       
     5 IriSP.JSONSerializer = function(DataLoader, url) {
       
     6   IriSP.Serializer.call(this, DataLoader, url);
       
     7 };
       
     8 
       
     9 IriSP.JSONSerializer.prototype = new IriSP.Serializer();
       
    10 
       
    11 /** serialize data */
       
    12 IriSP.JSONSerializer.prototype.serialize = function(data) {
       
    13   return JSON.stringify(data);
       
    14 };
       
    15 
       
    16 /** deserialize data */
       
    17 IriSP.JSONSerializer.prototype.deserialize = function(data) {
       
    18   return JSON.parse(data);
       
    19 };
       
    20 
       
    21 /** load JSON-cinelab data and also sort the annotations by start time
       
    22     @param callback function to call when the data is ready.
       
    23  */
       
    24 IriSP.JSONSerializer.prototype.sync = function(callback, force_refresh) {
       
    25   /* we don't have to do much because jQuery handles json for us */
       
    26 
       
    27   var self = this;
       
    28 
       
    29   var fn = function(data) {
       
    30 	  //TODO: seems taht data can be null here
       
    31 	  if (data !== null) {
       
    32 		  self._data = data;  
       
    33 	      if (typeof(self._data["annotations"]) === "undefined" ||
       
    34 	          self._data["annotations"] === null)
       
    35 	          self._data["annotations"] = [];
       
    36 	      
       
    37 	      // sort the data too       
       
    38 	      self._data["annotations"].sort(function(a, b) 
       
    39 	          { var a_begin = +a.begin;
       
    40 	            var b_begin = +b.begin;
       
    41 	            return a_begin - b_begin;
       
    42 	          });
       
    43 	  }     
       
    44       callback(data);      
       
    45   };
       
    46   this._DataLoader.get(this._url, fn, force_refresh);
       
    47 };
       
    48 
       
    49 /** @return the metadata about the media being read FIXME: always return the first media. */
       
    50 IriSP.JSONSerializer.prototype.currentMedia = function() {  
       
    51   return (typeof this._data.medias == "object" && this._data.medias.length) ? this._data.medias[0] : IriSP.__jsonMetadata.medias[0];
       
    52 };
       
    53 
       
    54 IriSP.JSONSerializer.prototype.getDuration = function() {
       
    55     var _m = this.currentMedia();
       
    56     if (_m === null || typeof _m.meta == "undefined") {
       
    57         return 0;
       
    58     }
       
    59     return +(IriSP.get_aliased(_m.meta, ["dc:duration", "duration"]) || 0);
       
    60 }
       
    61 
       
    62 
       
    63 /** searches for an annotation which matches title, description and keyword 
       
    64    "" matches any field. 
       
    65    Note: it ignores tweets.
       
    66    @return a list of matching ids.
       
    67 */    
       
    68 IriSP.JSONSerializer.prototype.searchAnnotations = function(title, description, keyword) {
       
    69     /* we can have many types of annotations. We want search to only look for regular segments */
       
    70     /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either
       
    71        null or undefined.
       
    72     */
       
    73     var view;
       
    74 
       
    75     if (typeof(this._data.views) !== "undefined" && this._data.views !== null)
       
    76        view = this._data.views[0];
       
    77 
       
    78     var searchViewType = "";
       
    79 
       
    80     if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) {
       
    81             searchViewType = view.annotation_types[0];
       
    82     }
       
    83 
       
    84     var filterfn = function(annotation) {
       
    85       if( searchViewType  != "" && 
       
    86           typeof(annotation.meta) !== "undefined" && 
       
    87           typeof(annotation.meta["id-ref"]) !== "undefined" &&
       
    88           annotation.meta["id-ref"] !== searchViewType) {
       
    89         return true; // don't pass
       
    90       } else {
       
    91           return false;
       
    92       }
       
    93     };
       
    94 
       
    95     return this.searchAnnotationsFilter(title, description, keyword, filterfn);
       
    96 
       
    97 };
       
    98 
       
    99 /* only look for tweets */
       
   100 IriSP.JSONSerializer.prototype.searchTweets = function(title, description, keyword) {
       
   101     /* we can have many types of annotations. We want search to only look for regular segments */
       
   102     /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either
       
   103        null or undefined.
       
   104     */
       
   105     
       
   106     var searchViewType = this.getTweets();
       
   107     if (typeof(searchViewType) === "undefined") {
       
   108       var view;
       
   109       
       
   110       if (typeof(this._data.views) !== "undefined" && this._data.views !== null)
       
   111          view = this._data.views[0];    
       
   112 
       
   113       if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) {
       
   114               searchViewType = view.annotation_types[0];
       
   115       }
       
   116     }
       
   117     var filterfn = function(annotation) {
       
   118       if( searchViewType  != "" && 
       
   119           typeof(annotation.meta) !== "undefined" && 
       
   120           typeof(annotation.meta["id-ref"]) !== "undefined" &&
       
   121           annotation.meta["id-ref"] === searchViewType) {
       
   122         return false; // pass
       
   123       } else {
       
   124           return true;
       
   125       }
       
   126     };
       
   127 
       
   128     return this.searchAnnotationsFilter(title, description, keyword, filterfn);
       
   129 
       
   130 };
       
   131 
       
   132 /**
       
   133   search an annotation according to its title, description and keyword
       
   134   @param filter a function to filter the results with. Used to select between annotation types.
       
   135  */    
       
   136 IriSP.JSONSerializer.prototype.searchAnnotationsFilter = function(title, description, keyword, filter) {
       
   137 
       
   138     var rTitle;
       
   139     var rDescription;
       
   140     var rKeyword;
       
   141     /* match anything if given the empty string */
       
   142     if (title == "")
       
   143       title = ".*";
       
   144     if (description == "")
       
   145       description = ".*";
       
   146     if (keyword == "")
       
   147       keyword = ".*";
       
   148     
       
   149     rTitle = new RegExp(title, "i");  
       
   150     rDescription = new RegExp(description, "i");  
       
   151     rKeyword = new RegExp(keyword, "i");  
       
   152     
       
   153     var ret_array = [];
       
   154     
       
   155     var i;
       
   156     for (i in this._data.annotations) {
       
   157       var annotation = this._data.annotations[i];
       
   158       
       
   159       /* filter the annotations whose type is not the one we want */
       
   160       if (filter(annotation)) {
       
   161           continue;
       
   162       }
       
   163       
       
   164       if (rTitle.test(annotation.content.title) && 
       
   165           rDescription.test(annotation.content.description)) {
       
   166           /* FIXME : implement keyword support */
       
   167           ret_array.push(annotation);
       
   168       }
       
   169     }
       
   170     
       
   171     return ret_array;
       
   172 };
       
   173 
       
   174 /** breaks a string in words and searches each of these words. Returns an array
       
   175    of objects with the id of the annotation and its number of occurences.
       
   176    
       
   177    @param searchString a string of words.
       
   178    FIXME: optimize ? seems to be n^2 in the worst case.
       
   179 */
       
   180 IriSP.JSONSerializer.prototype.searchOccurences = function(searchString) {
       
   181   var ret = { };
       
   182   var keywords = searchString.split(/\s+/);
       
   183   
       
   184   for (var i in keywords) {
       
   185     var keyword = keywords[i];
       
   186     
       
   187     // search this keyword in descriptions and title
       
   188     var found_annotations = []
       
   189     found_annotations = found_annotations.concat(this.searchAnnotations(keyword, "", ""));
       
   190     found_annotations = found_annotations.concat(this.searchAnnotations("", keyword, ""));
       
   191     
       
   192     for (var j in found_annotations) {
       
   193       var current_annotation = found_annotations[j];
       
   194       
       
   195       if (!ret.hasOwnProperty(current_annotation.id)) {
       
   196         ret[current_annotation.id] = 1;
       
   197       } else {
       
   198         ret[current_annotation.id] += 1;
       
   199       }
       
   200       
       
   201     }
       
   202 
       
   203   };
       
   204   
       
   205   return ret;
       
   206 };
       
   207 
       
   208 /** breaks a string in words and searches each of these words. Returns an array
       
   209    of objects with the id of the annotation and its number of occurences.
       
   210    
       
   211    FIXME: optimize ? seems to be n^2 in the worst case.
       
   212 */
       
   213 IriSP.JSONSerializer.prototype.searchTweetsOccurences = function(searchString) {
       
   214   var ret = { };
       
   215   var keywords = searchString.split(/\s+/);
       
   216   
       
   217   for (var i in keywords) {
       
   218     var keyword = keywords[i];
       
   219     
       
   220     // search this keyword in descriptions and title
       
   221     var found_annotations = []
       
   222     found_annotations = found_annotations.concat(this.searchTweets(keyword, "", ""));
       
   223     found_annotations = found_annotations.concat(this.searchTweets("", keyword, ""));
       
   224     
       
   225     for (var j in found_annotations) {
       
   226       var current_annotation = found_annotations[j];
       
   227       
       
   228       if (!ret.hasOwnProperty(current_annotation.id)) {
       
   229         ret[current_annotation.id] = 1;
       
   230       } else {
       
   231         ret[current_annotation.id] += 1;
       
   232       }
       
   233       
       
   234     }
       
   235 
       
   236   };
       
   237   
       
   238   return ret;
       
   239 };
       
   240 
       
   241 /** returns all the annotations that are displayable at the moment 
       
   242    NB: only takes account the first type of annotations - ignores tweets 
       
   243    currentTime is in seconds.
       
   244    
       
   245    @param currentTime the time at which we search.
       
   246    @param (optional) the if of the type of the annotations we want to get.
       
   247  */
       
   248 
       
   249 IriSP.JSONSerializer.prototype.currentAnnotations = function(currentTime, id) {
       
   250   var view;
       
   251   var currentTimeMs = 1000 * currentTime;
       
   252 
       
   253   if (typeof(id) === "undefined") {
       
   254       var legal_ids = this.getNonTweetIds();
       
   255   } else {
       
   256       legal_ids = [id];
       
   257   }
       
   258   
       
   259   var ret_array = [];
       
   260   
       
   261   var i;
       
   262   
       
   263   for (i in this._data.annotations) {
       
   264     var annotation = this._data.annotations[i];
       
   265     
       
   266     if (IriSP.underscore.include(legal_ids, annotation.meta["id-ref"]) && 
       
   267         annotation.begin <= currentTimeMs &&
       
   268         annotation.end >= currentTimeMs)
       
   269           ret_array.push(annotation);
       
   270   }
       
   271  
       
   272   if (ret_array == []) {
       
   273     console.log("ret_array empty, ", legal_ids);
       
   274   }
       
   275   
       
   276   return ret_array;
       
   277 };
       
   278 
       
   279 /** return the current chapitre
       
   280     @param currentTime the current time, in seconds.
       
   281 */
       
   282 IriSP.JSONSerializer.prototype.currentChapitre = function(currentTime) {
       
   283   return this.currentAnnotations(currentTime, this.getChapitrage())[0];
       
   284 };
       
   285 
       
   286 /** returns a list of ids of tweet lines (aka: groups in cinelab) */
       
   287 IriSP.JSONSerializer.prototype.getTweetIds = function() {
       
   288   if (IriSP.null_or_undefined(this._data.lists) || IriSP.null_or_undefined(this._data.lists) ||
       
   289       IriSP.null_or_undefined(this._data.views) || IriSP.null_or_undefined(this._data.views[0]))
       
   290     return [];
       
   291 
       
   292   
       
   293   /* Get the displayable types
       
   294      We've got to jump through a few hoops because the json sometimes defines
       
   295      fields with underscores and sometimes with dashes
       
   296   */
       
   297   var annotation_types = IriSP.get_aliased(this._data.views[0], ["annotation_types", "annotation-types"]);
       
   298   if (annotation_types === null) {
       
   299       console.log("neither view.annotation_types nor view.annotation-types are defined");      
       
   300       return;
       
   301   }
       
   302 
       
   303   var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]);    
       
   304   if (available_types === null) {
       
   305       console.log("neither view.annotation_types nor view.annotation-types are defined");      
       
   306       return;
       
   307   }
       
   308   
       
   309   var potential_types = [];
       
   310   
       
   311   // Get the list of types which contain "Tw" in their content
       
   312   for (var i = 0; i < available_types.length; i++) {
       
   313     if (/Tw/i.test(IriSP.get_aliased(available_types[i], ['dc:title', 'title']))) {
       
   314       potential_types.push(available_types[i].id);
       
   315     }
       
   316   }
       
   317   
       
   318   // Get the intersection of both.
       
   319   var tweetsId = IriSP.underscore.intersection(annotation_types, potential_types);
       
   320   
       
   321   return tweetsId;
       
   322 };
       
   323 
       
   324 /** this function returns a list of lines which are not tweet lines */
       
   325 IriSP.JSONSerializer.prototype.getNonTweetIds = function() {
       
   326   if (IriSP.null_or_undefined(this._data.lists) || IriSP.null_or_undefined(this._data.lists) ||
       
   327       IriSP.null_or_undefined(this._data.views) || IriSP.null_or_undefined(this._data.views[0]))
       
   328     return [];
       
   329 
       
   330   /* Get the displayable types
       
   331      We've got to jump through a few hoops because the json sometimes defines
       
   332      fields with underscores and sometimes with dashes
       
   333   */
       
   334   var annotation_types = IriSP.get_aliased(this._data.views[0], ["annotation_types", "annotation-types"]);
       
   335   if (annotation_types === null) {
       
   336       console.log("neither view.annotation_types nor view.annotation-types are defined");      
       
   337       return;
       
   338   }
       
   339 
       
   340   var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]);    
       
   341   if (available_types === null) {
       
   342       console.log("neither view.annotation_types nor view.annotation-types are defined");      
       
   343       return;
       
   344   }
       
   345 
       
   346   var potential_types = [];
       
   347   
       
   348   // Get the list of types which do not contain "Tw" in their content
       
   349   for (var i = 0; i < available_types.length; i++) {
       
   350     if (!(/Tw/i.test(IriSP.get_aliased(available_types[i], ['dc:title', 'title'])))) {
       
   351       potential_types.push(available_types[i].id);
       
   352     }
       
   353   }
       
   354 
       
   355   // Get the intersection of both.
       
   356   var nonTweetsId = IriSP.underscore.intersection(annotation_types, potential_types);
       
   357   
       
   358   return nonTweetsId;
       
   359   
       
   360 };
       
   361 
       
   362 /** return the id of the ligne de temps which contains name
       
   363     @param name of the ligne de temps
       
   364 */
       
   365 IriSP.JSONSerializer.prototype.getId = function(name) {
       
   366    var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]);  
       
   367    
       
   368   if (available_types == null)
       
   369     return;
       
   370 
       
   371   name = name.toUpperCase();
       
   372   var e;  
       
   373   e = IriSP.underscore.find(available_types, 
       
   374     function(entry) {
       
   375         if (IriSP.get_aliased(entry, ['dc:title', 'title']) === null)
       
   376           return false;
       
   377         return (entry["dc:title"].toUpperCase().indexOf(name) !== -1);
       
   378     });
       
   379   
       
   380   if (typeof(e) === "undefined")
       
   381     return;
       
   382     
       
   383   var id = e.id;
       
   384 
       
   385   return id;
       
   386 };
       
   387 
       
   388 /** return the list of id's of the ligne de temps which contains name
       
   389     @param name of the ligne de temps
       
   390 */
       
   391 IriSP.JSONSerializer.prototype.getIds = function(name) {
       
   392    var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]);  
       
   393    
       
   394   if (available_types == null)
       
   395     return;
       
   396 
       
   397   name = name.toUpperCase();
       
   398   var e = [];  
       
   399   e = IriSP.underscore.filter(available_types, 
       
   400                                   function(entry) { return (IriSP.get_aliased(entry, ['dc:title', 'title']).toUpperCase().indexOf(name) !== -1) });
       
   401   return IriSP.underscore.pluck(e, "id");  
       
   402 };
       
   403 
       
   404 /** return the id of the ligne de temps named "Chapitrage" */
       
   405 IriSP.JSONSerializer.prototype.getChapitrage = function() {
       
   406   var val = this.getId("Chapitrage");
       
   407   if (typeof(val) === "undefined")
       
   408     val = this.getId("Chapter");   
       
   409   if (typeof(val) === "undefined")
       
   410     val = this.getId("Chapit");
       
   411   if (typeof(val) === "undefined")
       
   412     val = this.getId("Chap");
       
   413     
       
   414   return val;
       
   415 };
       
   416 
       
   417 /** return the id of the ligne de temps named "Tweets" */
       
   418 IriSP.JSONSerializer.prototype.getTweets = function() {
       
   419   var val = this.getId("Tweets");
       
   420   if (typeof(val) === "undefined")
       
   421     val = this.getId("Tweet");
       
   422   if (typeof(val) === "undefined")
       
   423     val = this.getId("Twitter");
       
   424   if (typeof(val) === "undefined")
       
   425     val = this.getId("twit");
       
   426   if (typeof(val) === "undefined")
       
   427     val = this.getId("Polemic");
       
   428   
       
   429   return val;
       
   430 };
       
   431 
       
   432 /** return the id of the ligne de temps named "Contributions" */
       
   433 IriSP.JSONSerializer.prototype.getContributions = function() {
       
   434   var val = this.getId("Contribution");
       
   435   if (typeof(val) === "undefined")
       
   436     val = this.getId("Particip");   
       
   437   if (typeof(val) === "undefined")
       
   438     val = this.getId("Contr");
       
   439   if (typeof(val) === "undefined")
       
   440     val = this.getId("Publ");
       
   441     
       
   442   return val;
       
   443 };