From 422a87e1e664ea86edf3e628d465ac700af404d0 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Fri, 7 Nov 2014 17:36:05 +0000 Subject: Order tabs by recency, when no query terms. --- background_scripts/completion.coffee | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 23696185..9b22cd29 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -259,6 +259,29 @@ class DomainCompleter # Suggestions from the Domain completer have the maximum relevancy. They should be shown first in the list. computeRelevancy: -> 1 +# TabCache associates a timestamp with each tab. +class TabCache + constructor: -> + @timestamp = 1 + @cache = {} + + chrome.tabs.onActivated.addListener (activeInfo) => @add activeInfo.tabId + chrome.tabs.onRemoved.addListener (tabId) => @remove tabId + + chrome.tabs.onReplaced.addListener (addedTabId, removedTabId) => + @remove removedTabId + @add addedTabId + + add: (tabId) -> @cache[tabId] = ++@timestamp + remove: (tabId) -> delete @cache[tabId] + + # Recently-visited tabs get a higher score (except the current tab, which gets a low score). + recencyScore: (tabId) -> + @cache[tabId] ||= 1 + if @cache[tabId] == @timestamp then 0.0 else @cache[tabId] / @timestamp + +tabCache = new TabCache() + # Searches through all open tabs, matching on title and URL. class TabCompleter filter: (queryTerms, onComplete) -> @@ -274,7 +297,10 @@ class TabCompleter onComplete(suggestions) computeRelevancy: (suggestion) -> - RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title) + if 0 < suggestion.queryTerms.length + RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title) + else + tabCache.recencyScore suggestion.tabId # A completer which will return your search engines class SearchEngineCompleter -- cgit v1.2.3 From 7d7efb77270c6cd9527e788bdae9a862ced59d81 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Fri, 7 Nov 2014 18:41:06 +0000 Subject: Order tabs; tidy up. --- background_scripts/completion.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 9b22cd29..141c4ad7 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -259,8 +259,8 @@ class DomainCompleter # Suggestions from the Domain completer have the maximum relevancy. They should be shown first in the list. computeRelevancy: -> 1 -# TabCache associates a timestamp with each tab. -class TabCache +# TabRecency associates a timestamp with each tab id. +class TabRecency constructor: -> @timestamp = 1 @cache = {} @@ -280,7 +280,7 @@ class TabCache @cache[tabId] ||= 1 if @cache[tabId] == @timestamp then 0.0 else @cache[tabId] / @timestamp -tabCache = new TabCache() +tabRecency = new TabRecency() # Searches through all open tabs, matching on title and URL. class TabCompleter @@ -300,7 +300,7 @@ class TabCompleter if 0 < suggestion.queryTerms.length RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title) else - tabCache.recencyScore suggestion.tabId + tabRecency.recencyScore suggestion.tabId # A completer which will return your search engines class SearchEngineCompleter -- cgit v1.2.3 From a61de15c2f21e2a27f09b088dea09c1cefe699d1 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sat, 8 Nov 2014 06:51:44 +0000 Subject: Tabs order; add tests. --- background_scripts/completion.coffee | 1 + tests/unit_tests/completion_test.coffee | 20 +++++++++++++++++++- tests/unit_tests/test_chrome_stubs.coffee | 4 ++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 141c4ad7..af1613fc 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -573,3 +573,4 @@ root.SearchEngineCompleter = SearchEngineCompleter root.HistoryCache = HistoryCache root.RankingUtils = RankingUtils root.RegexpCache = RegexpCache +root.TabRecency = TabRecency diff --git a/tests/unit_tests/completion_test.coffee b/tests/unit_tests/completion_test.coffee index 811436a9..ee758dbb 100644 --- a/tests/unit_tests/completion_test.coffee +++ b/tests/unit_tests/completion_test.coffee @@ -1,8 +1,8 @@ require "./test_helper.js" extend(global, require "../../lib/utils.js") extend(global, require "../../background_scripts/completion.js") +extend global, require "./test_chrome_stubs.js" -global.chrome = {} global.document = createElement: -> {} @@ -399,6 +399,24 @@ context "RegexpCache", should "search for a string with a prefix/suffix (negative case)", -> assert.isTrue "hound dog".search(RegexpCache.get("do", "\\b", "\\b")) == -1 +context "TabRecency", + setup -> + @tabRecency = new TabRecency() + @tabRecency.add 3 + @tabRecency.add 2 + @tabRecency.add 1 + @tabRecency.add 4 + + should "give a high score to the most recent tab", -> + assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 1 + assert.isTrue @tabRecency.recencyScore(3) < @tabRecency.recencyScore 1 + assert.isTrue @tabRecency.recencyScore(2) < @tabRecency.recencyScore 1 + + should "give a low score to the current tab", -> + assert.isTrue @tabRecency.recencyScore(1) > @tabRecency.recencyScore 4 + assert.isTrue @tabRecency.recencyScore(2) > @tabRecency.recencyScore 4 + assert.isTrue @tabRecency.recencyScore(3) > @tabRecency.recencyScore 4 + # A convenience wrapper around completer.filter() so it can be called synchronously in tests. filterCompleter = (completer, queryTerms) -> results = [] diff --git a/tests/unit_tests/test_chrome_stubs.coffee b/tests/unit_tests/test_chrome_stubs.coffee index 2abd26c9..80750337 100644 --- a/tests/unit_tests/test_chrome_stubs.coffee +++ b/tests/unit_tests/test_chrome_stubs.coffee @@ -30,6 +30,10 @@ exports.chrome = addListener: () -> true onActiveChanged: addListener: () -> true + onActivated: + addListener: () -> true + onReplaced: + addListener: () -> true query: () -> true windows: -- cgit v1.2.3 From 1e9687d667febe575db1c66aeaaca7e8954bc31f Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sat, 8 Nov 2014 07:07:06 +0000 Subject: Tabs order; more tests. --- tests/unit_tests/completion_test.coffee | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/unit_tests/completion_test.coffee b/tests/unit_tests/completion_test.coffee index ee758dbb..dc4f3848 100644 --- a/tests/unit_tests/completion_test.coffee +++ b/tests/unit_tests/completion_test.coffee @@ -404,9 +404,20 @@ context "TabRecency", @tabRecency = new TabRecency() @tabRecency.add 3 @tabRecency.add 2 + @tabRecency.add 9 @tabRecency.add 1 + @tabRecency.remove 9 @tabRecency.add 4 + should "have entries for active tabs", -> + assert.isTrue @tabRecency.cache[1] + assert.isTrue @tabRecency.cache[2] + assert.isTrue @tabRecency.cache[3] + assert.isTrue @tabRecency.cache[4] + + should "not have entries for removed tabs", -> + assert.isFalse @tabRecency.cache[9] + should "give a high score to the most recent tab", -> assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 1 assert.isTrue @tabRecency.recencyScore(3) < @tabRecency.recencyScore 1 @@ -417,6 +428,17 @@ context "TabRecency", assert.isTrue @tabRecency.recencyScore(2) > @tabRecency.recencyScore 4 assert.isTrue @tabRecency.recencyScore(3) > @tabRecency.recencyScore 4 + should "rank tabs by recency", -> + assert.isTrue @tabRecency.recencyScore(3) < @tabRecency.recencyScore 2 + assert.isTrue @tabRecency.recencyScore(2) < @tabRecency.recencyScore 1 + @tabRecency.add 3 + @tabRecency.add 4 # Making 3 the most recent tab which isn't the current tab. + assert.isTrue @tabRecency.recencyScore(1) < @tabRecency.recencyScore 3 + assert.isTrue @tabRecency.recencyScore(2) < @tabRecency.recencyScore 3 + assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 3 + assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 1 + assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 2 + # A convenience wrapper around completer.filter() so it can be called synchronously in tests. filterCompleter = (completer, queryTerms) -> results = [] -- cgit v1.2.3 From 5492249ba4f36e40c8dcb4eff9916fa29bf0f94a Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 9 Nov 2014 06:20:48 +0000 Subject: Tabs order; minor style changes. --- background_scripts/completion.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index af1613fc..3fea9ee9 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -259,7 +259,7 @@ class DomainCompleter # Suggestions from the Domain completer have the maximum relevancy. They should be shown first in the list. computeRelevancy: -> 1 -# TabRecency associates a timestamp with each tab id. +# TabRecency associates a logical timestamp with each tab id. class TabRecency constructor: -> @timestamp = 1 @@ -297,10 +297,10 @@ class TabCompleter onComplete(suggestions) computeRelevancy: (suggestion) -> - if 0 < suggestion.queryTerms.length + if suggestion.queryTerms.length RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title) else - tabRecency.recencyScore suggestion.tabId + tabRecency.recencyScore(suggestion.tabId) # A completer which will return your search engines class SearchEngineCompleter -- cgit v1.2.3