diff -r 7b55777486c3 -r 75ba66457232 src/js/serializers/JSONSerializer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/js/serializers/JSONSerializer.js Fri Apr 06 16:55:34 2012 +0200 @@ -0,0 +1,443 @@ +/** @class This class implement a serializer for the JSON-Cinelab format + @params DataLoader a dataloader reference + @url the url from which to get our cinelab + */ +IriSP.JSONSerializer = function(DataLoader, url) { + IriSP.Serializer.call(this, DataLoader, url); +}; + +IriSP.JSONSerializer.prototype = new IriSP.Serializer(); + +/** serialize data */ +IriSP.JSONSerializer.prototype.serialize = function(data) { + return JSON.stringify(data); +}; + +/** deserialize data */ +IriSP.JSONSerializer.prototype.deserialize = function(data) { + return JSON.parse(data); +}; + +/** load JSON-cinelab data and also sort the annotations by start time + @param callback function to call when the data is ready. + */ +IriSP.JSONSerializer.prototype.sync = function(callback, force_refresh) { + /* we don't have to do much because jQuery handles json for us */ + + var self = this; + + var fn = function(data) { + //TODO: seems taht data can be null here + if (data !== null) { + self._data = data; + if (typeof(self._data["annotations"]) === "undefined" || + self._data["annotations"] === null) + self._data["annotations"] = []; + + // sort the data too + self._data["annotations"].sort(function(a, b) + { var a_begin = +a.begin; + var b_begin = +b.begin; + return a_begin - b_begin; + }); + } + callback(data); + }; + this._DataLoader.get(this._url, fn, force_refresh); +}; + +/** @return the metadata about the media being read FIXME: always return the first media. */ +IriSP.JSONSerializer.prototype.currentMedia = function() { + return (typeof this._data.medias == "object" && this._data.medias.length) ? this._data.medias[0] : IriSP.__jsonMetadata.medias[0]; +}; + +IriSP.JSONSerializer.prototype.getDuration = function() { + var _m = this.currentMedia(); + if (_m === null || typeof _m.meta == "undefined") { + return 0; + } + return +(IriSP.get_aliased(_m.meta, ["dc:duration", "duration"]) || 0); +} + + +/** searches for an annotation which matches title, description and keyword + "" matches any field. + Note: it ignores tweets. + @return a list of matching ids. +*/ +IriSP.JSONSerializer.prototype.searchAnnotations = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var searchViewType = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] !== searchViewType) { + return true; // don't pass + } else { + return false; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/* only look for tweets */ +IriSP.JSONSerializer.prototype.searchTweets = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + + var searchViewType = this.getTweets(); + if (typeof(searchViewType) === "undefined") { + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + } + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] === searchViewType) { + return false; // pass + } else { + return true; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/** + search an annotation according to its title, description and keyword + @param filter a function to filter the results with. Used to select between annotation types. + */ +IriSP.JSONSerializer.prototype.searchAnnotationsFilter = function(title, description, keyword, filter) { + + var rTitle; + var rDescription; + var rKeyword; + /* match anything if given the empty string */ + if (title == "") + title = ".*"; + if (description == "") + description = ".*"; + if (keyword == "") + keyword = ".*"; + + rTitle = new RegExp(title, "i"); + rDescription = new RegExp(description, "i"); + rKeyword = new RegExp(keyword, "i"); + + var ret_array = []; + + var i; + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (filter(annotation)) { + continue; + } + + if (rTitle.test(annotation.content.title) && + rDescription.test(annotation.content.description)) { + /* FIXME : implement keyword support */ + ret_array.push(annotation); + } + } + + return ret_array; +}; + +/** breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + @param searchString a string of words. + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchAnnotations(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchAnnotations("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/** breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchTweetsOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchTweets(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchTweets("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/** returns all the annotations that are displayable at the moment + NB: only takes account the first type of annotations - ignores tweets + currentTime is in seconds. + + @param currentTime the time at which we search. + @param (optional) the if of the type of the annotations we want to get. + */ + +IriSP.JSONSerializer.prototype.currentAnnotations = function(currentTime, id) { + var view; + var currentTimeMs = 1000 * currentTime; + + if (typeof(id) === "undefined") { + var legal_ids = this.getNonTweetIds(); + } else { + legal_ids = [id]; + } + + var ret_array = []; + + var i; + + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + if (IriSP.underscore.include(legal_ids, annotation.meta["id-ref"]) && + annotation.begin <= currentTimeMs && + annotation.end >= currentTimeMs) + ret_array.push(annotation); + } + + if (ret_array == []) { + console.log("ret_array empty, ", legal_ids); + } + + return ret_array; +}; + +/** return the current chapitre + @param currentTime the current time, in seconds. +*/ +IriSP.JSONSerializer.prototype.currentChapitre = function(currentTime) { + return this.currentAnnotations(currentTime, this.getChapitrage())[0]; +}; + +/** returns a list of ids of tweet lines (aka: groups in cinelab) */ +IriSP.JSONSerializer.prototype.getTweetIds = function() { + if (IriSP.null_or_undefined(this._data.lists) || IriSP.null_or_undefined(this._data.lists) || + IriSP.null_or_undefined(this._data.views) || IriSP.null_or_undefined(this._data.views[0])) + return []; + + + /* Get the displayable types + We've got to jump through a few hoops because the json sometimes defines + fields with underscores and sometimes with dashes + */ + var annotation_types = IriSP.get_aliased(this._data.views[0], ["annotation_types", "annotation-types"]); + if (annotation_types === null) { + console.log("neither view.annotation_types nor view.annotation-types are defined"); + return; + } + + var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]); + if (available_types === null) { + console.log("neither view.annotation_types nor view.annotation-types are defined"); + return; + } + + var potential_types = []; + + // Get the list of types which contain "Tw" in their content + for (var i = 0; i < available_types.length; i++) { + if (/Tw/i.test(IriSP.get_aliased(available_types[i], ['dc:title', 'title']))) { + potential_types.push(available_types[i].id); + } + } + + // Get the intersection of both. + var tweetsId = IriSP.underscore.intersection(annotation_types, potential_types); + + return tweetsId; +}; + +/** this function returns a list of lines which are not tweet lines */ +IriSP.JSONSerializer.prototype.getNonTweetIds = function() { + if (IriSP.null_or_undefined(this._data.lists) || IriSP.null_or_undefined(this._data.lists) || + IriSP.null_or_undefined(this._data.views) || IriSP.null_or_undefined(this._data.views[0])) + return []; + + /* Get the displayable types + We've got to jump through a few hoops because the json sometimes defines + fields with underscores and sometimes with dashes + */ + var annotation_types = IriSP.get_aliased(this._data.views[0], ["annotation_types", "annotation-types"]); + if (annotation_types === null) { + console.log("neither view.annotation_types nor view.annotation-types are defined"); + return; + } + + var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]); + if (available_types === null) { + console.log("neither view.annotation_types nor view.annotation-types are defined"); + return; + } + + var potential_types = []; + + // Get the list of types which do not contain "Tw" in their content + for (var i = 0; i < available_types.length; i++) { + if (!(/Tw/i.test(IriSP.get_aliased(available_types[i], ['dc:title', 'title'])))) { + potential_types.push(available_types[i].id); + } + } + + // Get the intersection of both. + var nonTweetsId = IriSP.underscore.intersection(annotation_types, potential_types); + + return nonTweetsId; + +}; + +/** return the id of the ligne de temps which contains name + @param name of the ligne de temps +*/ +IriSP.JSONSerializer.prototype.getId = function(name) { + var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]); + + if (available_types == null) + return; + + name = name.toUpperCase(); + var e; + e = IriSP.underscore.find(available_types, + function(entry) { + if (IriSP.get_aliased(entry, ['dc:title', 'title']) === null) + return false; + return (entry["dc:title"].toUpperCase().indexOf(name) !== -1); + }); + + if (typeof(e) === "undefined") + return; + + var id = e.id; + + return id; +}; + +/** return the list of id's of the ligne de temps which contains name + @param name of the ligne de temps +*/ +IriSP.JSONSerializer.prototype.getIds = function(name) { + var available_types = IriSP.get_aliased(this._data, ["annotation_types", "annotation-types"]); + + if (available_types == null) + return; + + name = name.toUpperCase(); + var e = []; + e = IriSP.underscore.filter(available_types, + function(entry) { return (IriSP.get_aliased(entry, ['dc:title', 'title']).toUpperCase().indexOf(name) !== -1) }); + return IriSP.underscore.pluck(e, "id"); +}; + +/** return the id of the ligne de temps named "Chapitrage" */ +IriSP.JSONSerializer.prototype.getChapitrage = function() { + var val = this.getId("Chapitrage"); + if (typeof(val) === "undefined") + val = this.getId("Chapter"); + if (typeof(val) === "undefined") + val = this.getId("Chapit"); + if (typeof(val) === "undefined") + val = this.getId("Chap"); + + return val; +}; + +/** return the id of the ligne de temps named "Tweets" */ +IriSP.JSONSerializer.prototype.getTweets = function() { + var val = this.getId("Tweets"); + if (typeof(val) === "undefined") + val = this.getId("Tweet"); + if (typeof(val) === "undefined") + val = this.getId("Twitter"); + if (typeof(val) === "undefined") + val = this.getId("twit"); + if (typeof(val) === "undefined") + val = this.getId("Polemic"); + + return val; +}; + +/** return the id of the ligne de temps named "Contributions" */ +IriSP.JSONSerializer.prototype.getContributions = function() { + var val = this.getId("Contribution"); + if (typeof(val) === "undefined") + val = this.getId("Particip"); + if (typeof(val) === "undefined") + val = this.getId("Contr"); + if (typeof(val) === "undefined") + val = this.getId("Publ"); + + return val; +}; \ No newline at end of file