# HG changeset patch # User hamidouk # Date 1322843510 -3600 # Node ID 5766e8238aaf7819a05cbe98f030660e3537a7d4 # Parent c3a08790e8c881ca10113214c1f00d13ca765e73 search in twitter feed now works. diff -r c3a08790e8c8 -r 5766e8238aaf src/js/serializers/JSONSerializer.js --- a/src/js/serializers/JSONSerializer.js Fri Dec 02 10:56:38 2011 +0100 +++ b/src/js/serializers/JSONSerializer.js Fri Dec 02 17:31:50 2011 +0100 @@ -39,9 +39,9 @@ /* this function searches for an annotation which matches title, description and keyword "" matches any field. + Note: it ignores tweets. */ 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. @@ -57,10 +57,61 @@ 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 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 false; // pass + } else { + return true; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/* + the previous function call this one, which is more general: + */ +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 = ".*"; @@ -80,11 +131,10 @@ var annotation = this._data.annotations[i]; /* filter the annotations whose type is not the one we want */ - if (searchViewType != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" - && annotation.meta["id-ref"] !== searchViewType) { + if (filter(annotation)) { continue; } - + if (rTitle.test(annotation.content.title) && rDescription.test(annotation.content.description)) { /* FIXME : implement keyword support */ @@ -128,6 +178,39 @@ 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; +}; + /* takes the currentTime and 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. diff -r c3a08790e8c8 -r 5766e8238aaf src/js/widgets/polemicWidget.js --- a/src/js/widgets/polemicWidget.js Fri Dec 02 10:56:38 2011 +0100 +++ b/src/js/widgets/polemicWidget.js Fri Dec 02 17:31:50 2011 +0100 @@ -31,10 +31,18 @@ this.PaperSlider; this.heightOfChart; this.tweets = new Array(); - this.svgElements = new Array(); + this.svgElements = {}; // Make and define the Raphael area this.paper = Raphael(document.getElementById(this._id), config.width, config.height); + + this.oldSearchMatches = []; + + // event handlers + this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) { this.searchHandler(searchString); })); + this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.searchFieldClosedHandler)); + this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.searchFieldClearedHandler)); + }; IriSP.PolemicWidget.prototype = new IriSP.Widget(); @@ -269,14 +277,16 @@ var e = this.paper.rect(x, y, frameSize - margin, TweetHeight /* height */) .attr({stroke:"#00","stroke-width":0.1, fill: colors[j]}); - this.svgElements.push(e); addEheight += TweetHeight; + e.color = colors[j]; e.time = frames[i].mytweetsID[k].timeframe; e.title = frames[i].mytweetsID[k].title; e.id = frames[i].mytweetsID[k].cinecast_id; + this.svgElements[e.id] = e; + e.mouseover(function(element) { return function (event) { // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery. self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.clientX - 106, event.clientY - 160); @@ -341,4 +351,55 @@ this.sliderTip.attr("x", time * (this.width / (duration / 1000))); }; - +IriSP.PolemicWidget.prototype.searchHandler = function(searchString) { + + if (searchString == "") + return; + + var matches = this._serializer.searchTweetsOccurences(searchString); + + if (IriSP.countProperties(matches) > 0) { + this._Popcorn.trigger("IriSP.PolemicWidget.matchFound"); + } else { + this._Popcorn.trigger("IriSP.PolemicWidget.noMatchFound"); + } + + for (var id in matches) { + var factor = 0.5 + matches[id] * 0.2; + if (this.svgElements.hasOwnProperty(id)) { + this.svgElements[id].attr({fill: "#fc00ff"}); + } + } + + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + if (!matches.hasOwnProperty(id)) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + } + + this.oldSearchMatches = matches; +}; + +IriSP.PolemicWidget.prototype.searchFieldClearedHandler = function() { + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + +}; + +IriSP.PolemicWidget.prototype.searchFieldClosedHandler = function() { + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + +}; +