From cc6c64fa5729a07be4567b2ca11bfadec6b02be2 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Fri, 15 May 2015 07:27:26 +0100
Subject: Give the vomnibar a (kind of) history.
---
background_scripts/completion.coffee | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 5755bfaf..2ee4a666 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -226,12 +226,23 @@ class HistoryCompleter
@currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }
results = []
HistoryCache.use (history) =>
+ searchUrl = Settings.get "searchUrl"
+ searchUrlTerminator = new RegExp "[/]"
results =
if queryTerms.length > 0
history.filter (entry) -> RankingUtils.matches(queryTerms, entry.url, entry.title)
else
[]
onComplete results.map (entry) =>
+ # If this history URL starts with the search URL, we reconstruct the original search terms, and insert
+ # them into the vomnibar when this suggestion is selected.
+ insertText =
+ if entry.url.startsWith searchUrl
+ try
+ entry.url[searchUrl.length..].split(searchUrlTerminator)[0].split("+").map(decodeURIComponent).join " "
+ catch
+ null
+
new Suggestion
queryTerms: queryTerms
type: "history"
@@ -239,6 +250,7 @@ class HistoryCompleter
title: entry.title
relevancyFunction: @computeRelevancy
relevancyData: entry
+ insertText: insertText
computeRelevancy: (suggestion) ->
historyEntry = suggestion.relevancyData
--
cgit v1.2.3
From b425d1804912ceb654e3b0070d9f2a2eb65a751e Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Fri, 15 May 2015 07:57:46 +0100
Subject: Give the vomnibar a (kind of) history (relevancy).
---
background_scripts/completion.coffee | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 2ee4a666..fd0a4c51 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -256,6 +256,14 @@ class HistoryCompleter
historyEntry = suggestion.relevancyData
recencyScore = RankingUtils.recencyScore(historyEntry.lastVisitTime)
wordRelevancy = RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
+ if suggestion.insertText?
+ # If this suggestion matches a previous search with the default search engine, then we also score the
+ # previous query terms themselves (suggestion.insertText) and, if that score is higher, then we use it
+ # in place of the wordRelevancy score. Because the query terms are shorter than the original URL, this
+ # has the side effect of boosting the wordRelevancy score for previous searches with the default search
+ # engine.
+ wordRelevancy = Math.max wordRelevancy,
+ RankingUtils.wordRelevancy suggestion.queryTerms, suggestion.insertText, suggestion.title
# Average out the word score and the recency. Recency has the ability to pull the score up, but not down.
(wordRelevancy + Math.max recencyScore, wordRelevancy) / 2
--
cgit v1.2.3
From 6a322975f561764d1a4ecb8ebd32edea12909e80 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Fri, 15 May 2015 08:17:16 +0100
Subject: Give the vomnibar a (kind of) history (autoSelect).
If we insert the text of hostory completions into the vomnibar input,
then when the completions change, we'll pick up the arbitrary text of
whatever happens to be the current selection. So we need to always
reset the selection when the vomnibar updates. This eliminates the need
for the previous autoSelect logic.
---
background_scripts/completion.coffee | 1 -
pages/vomnibar.coffee | 15 ++-------------
2 files changed, 2 insertions(+), 14 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index fd0a4c51..ac234787 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -504,7 +504,6 @@ class SearchEngineCompleter
title: queryTerms.join " "
relevancy: 1
autoSelect: custom
- forceAutoSelect: custom
highlightTerms: not haveCompletionEngine
mkSuggestion = (suggestion) ->
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index a20ae7f3..07eb39bb 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -67,22 +67,12 @@ class VomnibarUI
@completionList.style.display = ""
@input.value = ""
@completions = []
- @previousAutoSelect = null
@previousInputValue = null
@customSearchMode = null
@selection = @initialSelectionValue
@keywords = []
updateSelection: ->
- # We retain global state here (previousAutoSelect) to tell if a search item (for which autoSelect is set)
- # has just appeared or disappeared. If that happens, we set @selection to 0 or -1.
- if 0 < @completions.length
- @selection = 0 if @completions[0].autoSelect and not @previousAutoSelect
- @selection = -1 if @previousAutoSelect and not @completions[0].autoSelect
- @previousAutoSelect = @completions[0].autoSelect
- else
- @previousAutoSelect = null
-
# For custom search engines, we suppress the leading term (e.g. the "w" of "w query terms") within the
# vomnibar input.
if @lastReponse.customSearchMode and not @customSearchMode?
@@ -185,20 +175,19 @@ class VomnibarUI
callback: (@lastReponse) =>
{ results } = @lastReponse
@completions = results
+ @selection = if @completions[0]?.autoSelect then 0 else @initialSelectionValue
# Update completion list with the new suggestions.
@completionList.innerHTML = @completions.map((completion) -> "
#{completion.html}").join("")
@completionList.style.display = if @completions.length > 0 then "block" else ""
@selection = Math.min @completions.length - 1, Math.max @initialSelectionValue, @selection
- @previousAutoSelect = null if @completions[0]?.autoSelect and @completions[0]?.forceAutoSelect
@updateSelection()
callback?()
updateOnInput: =>
@completer.cancel()
- # If the user types, then don't reset any previous text, and restart auto select.
+ # If the user types, then don't reset any previous text, and reset the selection.
if @previousInputValue?
@previousInputValue = null
- @previousAutoSelect = null
@selection = -1
@update false
--
cgit v1.2.3
From ff1f7ac546d387a283a7421ba714c0d566d1f006 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Fri, 15 May 2015 10:28:38 +0100
Subject: Add ? to the list of query-term separators.
---
background_scripts/completion.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index ac234787..8000c62b 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -227,7 +227,7 @@ class HistoryCompleter
results = []
HistoryCache.use (history) =>
searchUrl = Settings.get "searchUrl"
- searchUrlTerminator = new RegExp "[/]"
+ searchUrlTerminator = new RegExp "[?/]"
results =
if queryTerms.length > 0
history.filter (entry) -> RankingUtils.matches(queryTerms, entry.url, entry.title)
--
cgit v1.2.3
From 623f770324ae86edd3a8d1817164a79656967ade Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Fri, 15 May 2015 10:46:24 +0100
Subject: Add comment explaining why we use try/catch.
---
background_scripts/completion.coffee | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 8000c62b..011fbdfb 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -235,13 +235,14 @@ class HistoryCompleter
[]
onComplete results.map (entry) =>
# If this history URL starts with the search URL, we reconstruct the original search terms, and insert
- # them into the vomnibar when this suggestion is selected.
+ # them into the vomnibar when this suggestion is selected. We use try/catch because
+ # decodeURIComponent() throw an error.
insertText =
- if entry.url.startsWith searchUrl
- try
+ try
+ if entry.url.startsWith searchUrl
entry.url[searchUrl.length..].split(searchUrlTerminator)[0].split("+").map(decodeURIComponent).join " "
- catch
- null
+ catch
+ null
new Suggestion
queryTerms: queryTerms
--
cgit v1.2.3
From ae44f35a653e76a2efbcb29f83c3fefa0ee0ab78 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Fri, 15 May 2015 10:52:40 +0100
Subject: Better explaination of query-term extract.
---
background_scripts/completion.coffee | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 011fbdfb..82a8f310 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -236,10 +236,11 @@ class HistoryCompleter
onComplete results.map (entry) =>
# If this history URL starts with the search URL, we reconstruct the original search terms, and insert
# them into the vomnibar when this suggestion is selected. We use try/catch because
- # decodeURIComponent() throw an error.
+ # decodeURIComponent() can throw an error.
insertText =
try
if entry.url.startsWith searchUrl
+ # This maps "https://www.google.ie/search?q=star+wars&..." to "star wars".
entry.url[searchUrl.length..].split(searchUrlTerminator)[0].split("+").map(decodeURIComponent).join " "
catch
null
--
cgit v1.2.3
From 93000bc401417954c8d9c1f52ef449292c2cd6fa Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Fri, 15 May 2015 11:02:49 +0100
Subject: Use query text as title, if necessary and possible.
---
background_scripts/completion.coffee | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 82a8f310..c9a03629 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -245,6 +245,10 @@ class HistoryCompleter
catch
null
+ # If this history item does not have a title and we found its query text above, then use its query
+ # text as its title.
+ entry.title ||= insertText if insertText?
+
new Suggestion
queryTerms: queryTerms
type: "history"
--
cgit v1.2.3
From 9742cee10745f256c66b52608090ddcc5107f33d Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sat, 16 May 2015 12:29:33 +0100
Subject: Add insertText visual indicator.
---
background_scripts/completion.coffee | 7 +++++--
pages/vomnibar.css | 7 +++++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index c9a03629..66546708 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -45,14 +45,17 @@ class Suggestion
return @html if @html
relevancyHtml = if @showRelevancy then "#{@computeRelevancy()}" else ""
# NOTE(philc): We're using these vimium-specific class names so we don't collide with the page's CSS.
+ insertTextClass = if @insertText then "vomnibarInsertText" else "vomnibarNoInsertText"
+ insertTextIndicator = "﹢" # A small plus sign.
+ insertTextIndicator = "﹥" # A small "greater than" sign.
@html =
"""
- #{@type}
+ #{insertTextIndicator}#{@type}
#{@highlightQueryTerms Utils.escapeHtml @title}
- #{@highlightQueryTerms Utils.escapeHtml @shortenUrl()}
+ #{insertTextIndicator}#{@highlightQueryTerms Utils.escapeHtml @shortenUrl()}
#{relevancyHtml}
"""
diff --git a/pages/vomnibar.css b/pages/vomnibar.css
index 9fdc43ba..b1ed0252 100644
--- a/pages/vomnibar.css
+++ b/pages/vomnibar.css
@@ -145,3 +145,10 @@
* on the eye for this purpose. */
background-color: #E6EEFB;
}
+
+.vomnibarInsertText {
+}
+
+.vomnibarNoInsertText {
+ visibility: hidden;
+}
--
cgit v1.2.3
From c09e70364118264804510ee4b06f3ff8d38933b1 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sat, 16 May 2015 12:57:58 +0100
Subject: Refactor query extraction to Utils.extractQuery().
If we go with this and #1662, then we can share the utility.
---
background_scripts/completion.coffee | 20 ++++++--------------
lib/utils.coffee | 15 +++++++++++++++
2 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 66546708..eb80f3cd 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -230,26 +230,18 @@ class HistoryCompleter
results = []
HistoryCache.use (history) =>
searchUrl = Settings.get "searchUrl"
- searchUrlTerminator = new RegExp "[?/]"
results =
if queryTerms.length > 0
history.filter (entry) -> RankingUtils.matches(queryTerms, entry.url, entry.title)
else
[]
onComplete results.map (entry) =>
- # If this history URL starts with the search URL, we reconstruct the original search terms, and insert
- # them into the vomnibar when this suggestion is selected. We use try/catch because
- # decodeURIComponent() can throw an error.
- insertText =
- try
- if entry.url.startsWith searchUrl
- # This maps "https://www.google.ie/search?q=star+wars&..." to "star wars".
- entry.url[searchUrl.length..].split(searchUrlTerminator)[0].split("+").map(decodeURIComponent).join " "
- catch
- null
-
- # If this history item does not have a title and we found its query text above, then use its query
- # text as its title.
+ # This entry's URL might match the default search engine, in which case we'll insert its query text
+ # into the vomnibar input whenever this entry is selected.
+ insertText = Utils.extractQuery searchUrl, entry.url
+
+ # If this history item does not have a title and we successfully extracted query text above, then use
+ # that text in lieu of a title.
entry.title ||= insertText if insertText?
new Suggestion
diff --git a/lib/utils.coffee b/lib/utils.coffee
index cbc937b6..cd466b9b 100644
--- a/lib/utils.coffee
+++ b/lib/utils.coffee
@@ -114,6 +114,21 @@ Utils =
searchUrl += "%s" unless 0 <= searchUrl.indexOf "%s"
searchUrl.replace /%s/g, @createSearchQuery query
+ # Extract a query from url if it appears to be a URL created by createSearchQuery.
+ # For example, map "https://www.google.ie/search?q=star+wars&foo&bar" to "star wars".
+ extractQuery: do =>
+ queryTerminator = new RegExp "[?/]"
+ httpProtocolRegexp = new RegExp "^https?://"
+ (searchUrl, url) ->
+ url = url.replace httpProtocolRegexp
+ searchUrl = searchUrl.split("%s")[0].replace httpProtocolRegexp
+ # We use try/catch because decodeURIComponent can throw an exception.
+ try
+ if url.startsWith searchUrl
+ url[searchUrl.length..].split(queryTerminator)[0].split("+").map(decodeURIComponent).join " "
+ catch
+ null
+
# Converts :string into a Google search if it's not already a URL. We don't bother with escaping characters
# as Chrome will do that for us.
convertToUrl: (string) ->
--
cgit v1.2.3
From 69cd8c08375cdf5df8636748f6f479552d780b8f Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 06:11:45 +0100
Subject: TabToOpen: tab to open vomnibar.
`o` then `Tab` opens the vomnibar completionlist with history
completions (the only completions) ranked by recently only. Hence, the
most recent requests are at the top.
This is a (far) simpler approach than #1662 which catches the most
important use case (repeat a search with an edited query).
---
background_scripts/completion.coffee | 7 ++++++-
pages/vomnibar.coffee | 19 ++++++++++++++-----
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index eb80f3cd..80b47055 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -225,7 +225,7 @@ class BookmarkCompleter
RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
class HistoryCompleter
- filter: ({ queryTerms }, onComplete) ->
+ filter: ({ queryTerms, tabToOpen }, onComplete) ->
@currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }
results = []
HistoryCache.use (history) =>
@@ -233,6 +233,9 @@ class HistoryCompleter
results =
if queryTerms.length > 0
history.filter (entry) -> RankingUtils.matches(queryTerms, entry.url, entry.title)
+ else if tabToOpen
+ # opens the completion list, even without a query.
+ history
else
[]
onComplete results.map (entry) =>
@@ -256,6 +259,8 @@ class HistoryCompleter
computeRelevancy: (suggestion) ->
historyEntry = suggestion.relevancyData
recencyScore = RankingUtils.recencyScore(historyEntry.lastVisitTime)
+ # If there are no query terms, then relevancy is based on recency alone.
+ return recencyScore if suggestion.queryTerms.length == 0
wordRelevancy = RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
if suggestion.insertText?
# If this suggestion matches a previous search with the default search engine, then we also score the
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index 07eb39bb..731ebed2 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -71,6 +71,7 @@ class VomnibarUI
@customSearchMode = null
@selection = @initialSelectionValue
@keywords = []
+ @tabToOpen = false
updateSelection: ->
# For custom search engines, we suppress the leading term (e.g. the "w" of "w query terms") within the
@@ -125,9 +126,13 @@ class VomnibarUI
if (action == "dismiss")
@hide()
else if action in [ "tab", "down" ]
- @selection += 1
- @selection = @initialSelectionValue if @selection == @completions.length
- @updateSelection()
+ if @input.value.trim().length == 0 and action == "tab" and not @tabToOpen
+ @tabToOpen = true
+ @update true
+ else
+ @selection += 1
+ @selection = @initialSelectionValue if @selection == @completions.length
+ @updateSelection()
else if (action == "up")
@selection -= 1
@selection = @completions.length - 1 if @selection < @initialSelectionValue
@@ -150,12 +155,16 @@ class VomnibarUI
completion = @completions[@selection]
@hide -> completion.performAction openInNewTab
else if action == "delete"
- if @customSearchMode? and @input.value.length == 0
+ inputIsEmpty = @input.value.length == 0
+ if inputIsEmpty and @customSearchMode?
# Normally, with custom search engines, the keyword (e,g, the "w" of "w query terms") is suppressed.
# If the input is empty, then reinstate the keyword (the "w").
@input.value = @customSearchMode
@customSearchMode = null
@updateCompletions()
+ else if inputIsEmpty and @tabToOpen
+ @tabToOpen = false
+ @update true
else
return true # Do not suppress event.
@@ -172,6 +181,7 @@ class VomnibarUI
updateCompletions: (callback = null) ->
@completer.filter
query: @getInputValueAsQuery()
+ tabToOpen: @tabToOpen
callback: (@lastReponse) =>
{ results } = @lastReponse
@completions = results
@@ -275,7 +285,6 @@ class BackgroundCompleter
queryTerms: query.trim().split(/\s+/).filter (s) -> 0 < s.length
# We don't send these keys.
callback: null
- mayUseVomnibarCache: null
reset: ->
@keywords = []
--
cgit v1.2.3
From c2eb404ad87689ac886e1ddbab2c62d7d7a1be9d Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 06:34:59 +0100
Subject: TabToOpen: tweaks
---
pages/vomnibar.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index 731ebed2..18ad5945 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -161,7 +161,7 @@ class VomnibarUI
# If the input is empty, then reinstate the keyword (the "w").
@input.value = @customSearchMode
@customSearchMode = null
- @updateCompletions()
+ @update true
else if inputIsEmpty and @tabToOpen
@tabToOpen = false
@update true
--
cgit v1.2.3
From 378bb6cf68e410aa0b68f15796aa395de61d18e1 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 07:55:11 +0100
Subject: TabToOpen: insert queries for custom search engines.
---
background_scripts/completion.coffee | 38 ++++++++++++++++++++++++------------
1 file changed, 25 insertions(+), 13 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 80b47055..69cb10de 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -239,14 +239,6 @@ class HistoryCompleter
else
[]
onComplete results.map (entry) =>
- # This entry's URL might match the default search engine, in which case we'll insert its query text
- # into the vomnibar input whenever this entry is selected.
- insertText = Utils.extractQuery searchUrl, entry.url
-
- # If this history item does not have a title and we successfully extracted query text above, then use
- # that text in lieu of a title.
- entry.title ||= insertText if insertText?
-
new Suggestion
queryTerms: queryTerms
type: "history"
@@ -254,7 +246,6 @@ class HistoryCompleter
title: entry.title
relevancyFunction: @computeRelevancy
relevancyData: entry
- insertText: insertText
computeRelevancy: (suggestion) ->
historyEntry = suggestion.relevancyData
@@ -418,6 +409,7 @@ class SearchEngineCompleter
triageRequest: (request) ->
@searchEngines.use (engines) =>
{ queryTerms, query } = request
+ request.searchEngines = engines
keyword = queryTerms[0]
# Note. For a keyword "w", we match "w search terms" and "w ", but not "w" on its own.
if keyword and engines[keyword] and (1 < queryTerms.length or /\s$/.test query)
@@ -444,6 +436,7 @@ class SearchEngineCompleter
searchUrl: url
description: description
searchUrlPrefix: url.split("%s")[0]
+ insertTextPrefix: "#{keyword} "
callback engines
@@ -495,7 +488,7 @@ class SearchEngineCompleter
# We only accept suggestions:
# - from this completer, or
# - from other completers, but then only if their URL matches this search engine and matches this
- # query (that is only if their URL could have been generated by this search engine).
+ # query (that is only if their URL could have been generated by this search engine).
suggestions.filter (suggestion) ->
suggestion.type == description or
# This is a suggestion for the same search engine.
@@ -511,6 +504,7 @@ class SearchEngineCompleter
relevancy: 1
autoSelect: custom
highlightTerms: not haveCompletionEngine
+ isSearchSuggestion: true
mkSuggestion = (suggestion) ->
new Suggestion
@@ -521,6 +515,7 @@ class SearchEngineCompleter
relevancy: relevancy *= 0.9
insertText: suggestion
highlightTerms: false
+ isSearchSuggestion: true
cachedSuggestions =
if haveCompletionEngine then CompletionSearch.complete searchUrl, queryTerms else null
@@ -551,6 +546,20 @@ class SearchEngineCompleter
console.log "fetched suggestions:", suggestions.length, query if SearchEngineCompleter.debug
onComplete suggestions.map mkSuggestion
+ postProcessSuggestions: (request, suggestions) ->
+ return unless request.searchEngines
+ engines = (engine for _, engine of request.searchEngines)
+ engines.sort (a,b) -> b.searchUrl.length - a.searchUrl.length
+ engines.push insertTextPrefix: "", searchUrl: Settings.get "searchUrl"
+ for suggestion in suggestions
+ unless suggestion.isSearchSuggestion or suggestion.insertText
+ for engine in engines
+ if suggestion.insertText = Utils.extractQuery engine.searchUrl, suggestion.url
+ suggestion.insertText = "#{engine.insertTextPrefix}#{suggestion.insertText}"
+ suggestion.title ||= suggestion.insertText
+ break
+ delete request.searchEngines
+
# A completer which calls filter() on many completers, aggregates the results, ranks them, and returns the top
# 10. All queries from the vomnibar come through a multi completer.
class MultiCompleter
@@ -594,7 +603,7 @@ class MultiCompleter
# Post results, unless there are none and we will be running a continuation. This avoids
# collapsing the vomnibar briefly before expanding it again, which looks ugly.
unless suggestions.length == 0 and shouldRunContinuations
- suggestions = @prepareSuggestions queryTerms, suggestions
+ suggestions = @prepareSuggestions request, queryTerms, suggestions
onComplete
results: suggestions
mayCacheResults: continuations.length == 0
@@ -611,7 +620,7 @@ class MultiCompleter
jobs.onReady =>
suggestions = filter suggestions for filter in filters
- suggestions = @prepareSuggestions queryTerms, suggestions
+ suggestions = @prepareSuggestions request, queryTerms, suggestions
# We post these results even if a new query has started. The vomnibar will not display them
# (because they're arriving too late), but it will cache them.
onComplete
@@ -623,7 +632,7 @@ class MultiCompleter
if @mostRecentQuery
@filter @mostRecentQuery...
- prepareSuggestions: (queryTerms, suggestions) ->
+ prepareSuggestions: (request, queryTerms, suggestions) ->
# Compute suggestion relevancies and sort.
suggestion.computeRelevancy queryTerms for suggestion in suggestions
suggestions.sort (a, b) -> b.relevancy - a.relevancy
@@ -638,6 +647,9 @@ class MultiCompleter
break if count++ == @maxResults
seenUrls[url] = suggestion
+ # Give each completer an opportunity to tweak the suggestions.
+ completer.postProcessSuggestions? request, suggestions for completer in @completers
+
# Generate HTML for the remaining suggestions and return them.
suggestion.generateHtml() for suggestion in suggestions
suggestions
--
cgit v1.2.3
From 9ae3ef93a4c4e00081bae65bc3c23cf08b9cff9a Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 08:51:18 +0100
Subject: TabToOpen: use search-engine description as suggestion type.
---
background_scripts/completion.coffee | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 69cb10de..be37a1fa 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -556,7 +556,8 @@ class SearchEngineCompleter
for engine in engines
if suggestion.insertText = Utils.extractQuery engine.searchUrl, suggestion.url
suggestion.insertText = "#{engine.insertTextPrefix}#{suggestion.insertText}"
- suggestion.title ||= suggestion.insertText
+ suggestion.title = suggestion.insertText
+ suggestion.type = engine.description ? "search"
break
delete request.searchEngines
--
cgit v1.2.3
From 832be3c2059870e0930ece3ea88377034e237119 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 09:03:05 +0100
Subject: TabToOpen: reactivate previous custom search engine.
Note: There's still an unpleasant flicker when this happens.
TBD: Fix this.
---
background_scripts/completion.coffee | 4 ++--
pages/vomnibar.coffee | 6 +++++-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index be37a1fa..25c31be1 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -550,12 +550,12 @@ class SearchEngineCompleter
return unless request.searchEngines
engines = (engine for _, engine of request.searchEngines)
engines.sort (a,b) -> b.searchUrl.length - a.searchUrl.length
- engines.push insertTextPrefix: "", searchUrl: Settings.get "searchUrl"
+ engines.push insertTextPrefix: null, searchUrl: Settings.get "searchUrl"
for suggestion in suggestions
unless suggestion.isSearchSuggestion or suggestion.insertText
for engine in engines
if suggestion.insertText = Utils.extractQuery engine.searchUrl, suggestion.url
- suggestion.insertText = "#{engine.insertTextPrefix}#{suggestion.insertText}"
+ suggestion.insertPrefixOnInput = engine.insertTextPrefix
suggestion.title = suggestion.insertText
suggestion.type = engine.description ? "search"
break
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index 18ad5945..2caec140 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -195,11 +195,15 @@ class VomnibarUI
updateOnInput: =>
@completer.cancel()
+ updateSynchronously = false
+ if 0 < @selection and @completions[@selection].insertPrefixOnInput
+ @input.value = @completions[@selection].insertPrefixOnInput + @input.value
+ updateSynchronously = true
# If the user types, then don't reset any previous text, and reset the selection.
if @previousInputValue?
@previousInputValue = null
@selection = -1
- @update false
+ @update updateSynchronously
clearUpdateTimer: ->
if @updateTimer?
--
cgit v1.2.3
From 913806699a2cc66aea4489137a84189e01afd9da Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 09:30:37 +0100
Subject: TabToOpen: reactivate custom search engines.
When the user begins editing the inserted text from a
custom-search-engine suggestion, we reactivate the original
custom-search-engine mode.
---
background_scripts/completion.coffee | 8 ++++----
pages/vomnibar.coffee | 18 +++++++++---------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 25c31be1..d5c6c23a 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -436,7 +436,6 @@ class SearchEngineCompleter
searchUrl: url
description: description
searchUrlPrefix: url.split("%s")[0]
- insertTextPrefix: "#{keyword} "
callback engines
@@ -550,14 +549,15 @@ class SearchEngineCompleter
return unless request.searchEngines
engines = (engine for _, engine of request.searchEngines)
engines.sort (a,b) -> b.searchUrl.length - a.searchUrl.length
- engines.push insertTextPrefix: null, searchUrl: Settings.get "searchUrl"
+ engines.push keyword: null, description: "search", searchUrl: Settings.get "searchUrl"
for suggestion in suggestions
unless suggestion.isSearchSuggestion or suggestion.insertText
for engine in engines
if suggestion.insertText = Utils.extractQuery engine.searchUrl, suggestion.url
- suggestion.insertPrefixOnInput = engine.insertTextPrefix
+ suggestion.customSearchMode = engine.keyword
suggestion.title = suggestion.insertText
- suggestion.type = engine.description ? "search"
+ console.log suggestion.insertText, engine unless engine.description
+ suggestion.type = engine.description ? "custom search"
break
delete request.searchEngines
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index 2caec140..c4b22911 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -86,7 +86,7 @@ class VomnibarUI
# typing.
if 0 <= @selection and @completions[@selection].insertText?
@previousInputValue ?= @input.value
- @input.value = @completions[@selection].insertText + (if @selection == 0 then "" else " ")
+ @input.value = @completions[@selection].insertText
else if @previousInputValue?
@input.value = @previousInputValue
@previousInputValue = null
@@ -193,11 +193,11 @@ class VomnibarUI
@updateSelection()
callback?()
- updateOnInput: =>
+ onInput: =>
+ @tabToOpen = false
@completer.cancel()
- updateSynchronously = false
- if 0 < @selection and @completions[@selection].insertPrefixOnInput
- @input.value = @completions[@selection].insertPrefixOnInput + @input.value
+ if 0 <= @selection and @completions[@selection].customSearchMode and not @customSearchMode
+ @customSearchMode = @completions[@selection].customSearchMode
updateSynchronously = true
# If the user types, then don't reset any previous text, and reset the selection.
if @previousInputValue?
@@ -210,14 +210,14 @@ class VomnibarUI
window.clearTimeout @updateTimer
@updateTimer = null
- isCustomSearch: ->
+ shouldActivateCustomSearchMode: ->
queryTerms = @input.value.ltrim().split /\s+/
- 1 < queryTerms.length and queryTerms[0] in @keywords
+ 1 < queryTerms.length and queryTerms[0] in @keywords and not @customSearchMode
update: (updateSynchronously = false, callback = null) =>
# If the query text becomes a custom search (the user enters a search keyword), then we need to force a
# synchronous update (so that the state is updated immediately).
- updateSynchronously ||= @isCustomSearch() and not @customSearchMode?
+ updateSynchronously ||= @shouldActivateCustomSearchMode()
if updateSynchronously
@clearUpdateTimer()
@updateCompletions callback
@@ -234,7 +234,7 @@ class VomnibarUI
@box = document.getElementById("vomnibar")
@input = @box.querySelector("input")
- @input.addEventListener "input", @updateOnInput
+ @input.addEventListener "input", @onInput
@input.addEventListener "keydown", @onKeydown
@completionList = @box.querySelector("ul")
@completionList.style.display = ""
--
cgit v1.2.3
From 0c7668d6cc46cf24081b6b64ece27faef6667dea Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 11:30:30 +0100
Subject: TabToOpen: tidy up pre-PR.
---
background_scripts/completion.coffee | 26 +++++++-------------------
lib/utils.coffee | 2 +-
pages/vomnibar.coffee | 14 +++++++-------
pages/vomnibar.css | 7 -------
4 files changed, 15 insertions(+), 34 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index d5c6c23a..0f8f24f5 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -45,17 +45,14 @@ class Suggestion
return @html if @html
relevancyHtml = if @showRelevancy then "#{@computeRelevancy()}" else ""
# NOTE(philc): We're using these vimium-specific class names so we don't collide with the page's CSS.
- insertTextClass = if @insertText then "vomnibarInsertText" else "vomnibarNoInsertText"
- insertTextIndicator = "﹢" # A small plus sign.
- insertTextIndicator = "﹥" # A small "greater than" sign.
@html =
"""
- #{insertTextIndicator}#{@type}
+ #{@type}
#{@highlightQueryTerms Utils.escapeHtml @title}
- #{insertTextIndicator}#{@highlightQueryTerms Utils.escapeHtml @shortenUrl()}
+ #{@highlightQueryTerms Utils.escapeHtml @shortenUrl()}
#{relevancyHtml}
"""
@@ -225,7 +222,7 @@ class BookmarkCompleter
RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
class HistoryCompleter
- filter: ({ queryTerms, tabToOpen }, onComplete) ->
+ filter: ({ queryTerms, seenTabToOpenCompletionList }, onComplete) ->
@currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }
results = []
HistoryCache.use (history) =>
@@ -233,7 +230,7 @@ class HistoryCompleter
results =
if queryTerms.length > 0
history.filter (entry) -> RankingUtils.matches(queryTerms, entry.url, entry.title)
- else if tabToOpen
+ else if seenTabToOpenCompletionList
# opens the completion list, even without a query.
history
else
@@ -253,14 +250,6 @@ class HistoryCompleter
# If there are no query terms, then relevancy is based on recency alone.
return recencyScore if suggestion.queryTerms.length == 0
wordRelevancy = RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
- if suggestion.insertText?
- # If this suggestion matches a previous search with the default search engine, then we also score the
- # previous query terms themselves (suggestion.insertText) and, if that score is higher, then we use it
- # in place of the wordRelevancy score. Because the query terms are shorter than the original URL, this
- # has the side effect of boosting the wordRelevancy score for previous searches with the default search
- # engine.
- wordRelevancy = Math.max wordRelevancy,
- RankingUtils.wordRelevancy suggestion.queryTerms, suggestion.insertText, suggestion.title
# Average out the word score and the recency. Recency has the ability to pull the score up, but not down.
(wordRelevancy + Math.max recencyScore, wordRelevancy) / 2
@@ -406,7 +395,7 @@ class SearchEngineCompleter
# This looks up the custom search engine and, if one is found, notes it and removes its keyword from the
# query terms.
- triageRequest: (request) ->
+ preprocessRequest: (request) ->
@searchEngines.use (engines) =>
{ queryTerms, query } = request
request.searchEngines = engines
@@ -559,7 +548,6 @@ class SearchEngineCompleter
console.log suggestion.insertText, engine unless engine.description
suggestion.type = engine.description ? "custom search"
break
- delete request.searchEngines
# A completer which calls filter() on many completers, aggregates the results, ranks them, and returns the top
# 10. All queries from the vomnibar come through a multi completer.
@@ -578,7 +566,7 @@ class MultiCompleter
# Provide each completer with an opportunity to see (and possibly alter) the request before it is
# launched.
- completer.triageRequest? request for completer in @completers
+ completer.preprocessRequest? request for completer in @completers
RegexpCache.clear()
{ queryTerms } = request
@@ -648,7 +636,7 @@ class MultiCompleter
break if count++ == @maxResults
seenUrls[url] = suggestion
- # Give each completer an opportunity to tweak the suggestions.
+ # Give each completer the opportunity to tweak the suggestions.
completer.postProcessSuggestions? request, suggestions for completer in @completers
# Generate HTML for the remaining suggestions and return them.
diff --git a/lib/utils.coffee b/lib/utils.coffee
index cd466b9b..724250e0 100644
--- a/lib/utils.coffee
+++ b/lib/utils.coffee
@@ -114,7 +114,7 @@ Utils =
searchUrl += "%s" unless 0 <= searchUrl.indexOf "%s"
searchUrl.replace /%s/g, @createSearchQuery query
- # Extract a query from url if it appears to be a URL created by createSearchQuery.
+ # Extract a query from url if it appears to be a URL created generated from the given search URL.
# For example, map "https://www.google.ie/search?q=star+wars&foo&bar" to "star wars".
extractQuery: do =>
queryTerminator = new RegExp "[?/]"
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index c4b22911..fd7fd3cc 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -71,7 +71,7 @@ class VomnibarUI
@customSearchMode = null
@selection = @initialSelectionValue
@keywords = []
- @tabToOpen = false
+ @seenTabToOpenCompletionList = false
updateSelection: ->
# For custom search engines, we suppress the leading term (e.g. the "w" of "w query terms") within the
@@ -126,8 +126,8 @@ class VomnibarUI
if (action == "dismiss")
@hide()
else if action in [ "tab", "down" ]
- if @input.value.trim().length == 0 and action == "tab" and not @tabToOpen
- @tabToOpen = true
+ if @input.value.trim().length == 0 and action == "tab" and not @seenTabToOpenCompletionList
+ @seenTabToOpenCompletionList = true
@update true
else
@selection += 1
@@ -162,8 +162,8 @@ class VomnibarUI
@input.value = @customSearchMode
@customSearchMode = null
@update true
- else if inputIsEmpty and @tabToOpen
- @tabToOpen = false
+ else if inputIsEmpty and @seenTabToOpenCompletionList
+ @seenTabToOpenCompletionList = false
@update true
else
return true # Do not suppress event.
@@ -181,7 +181,7 @@ class VomnibarUI
updateCompletions: (callback = null) ->
@completer.filter
query: @getInputValueAsQuery()
- tabToOpen: @tabToOpen
+ seenTabToOpenCompletionList: @seenTabToOpenCompletionList
callback: (@lastReponse) =>
{ results } = @lastReponse
@completions = results
@@ -194,7 +194,7 @@ class VomnibarUI
callback?()
onInput: =>
- @tabToOpen = false
+ @seenTabToOpenCompletionList = false
@completer.cancel()
if 0 <= @selection and @completions[@selection].customSearchMode and not @customSearchMode
@customSearchMode = @completions[@selection].customSearchMode
diff --git a/pages/vomnibar.css b/pages/vomnibar.css
index b1ed0252..9fdc43ba 100644
--- a/pages/vomnibar.css
+++ b/pages/vomnibar.css
@@ -145,10 +145,3 @@
* on the eye for this purpose. */
background-color: #E6EEFB;
}
-
-.vomnibarInsertText {
-}
-
-.vomnibarNoInsertText {
- visibility: hidden;
-}
--
cgit v1.2.3
From 222d3dd6491bca8f152382fb84e2d43c499b8951 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 11:34:37 +0100
Subject: TabToOpen: more tidy up pre-PR.
---
background_scripts/completion.coffee | 4 ----
lib/utils.coffee | 2 +-
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 0f8f24f5..cc1ada5b 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -25,9 +25,6 @@ class Suggestion
# If @autoSelect is truthy, then this suggestion is automatically pre-selected in the vomnibar. There may
# be at most one such suggestion.
@autoSelect = false
- # If truthy (and @autoSelect is truthy too), then this suggestion is always pre-selected when the query
- # changes. There may be at most one such suggestion.
- @forceAutoSelect = false
# If @highlightTerms is true, then we highlight matched terms in the title and URL.
@highlightTerms = true
# If @insertText is a string, then the indicated text is inserted into the vomnibar input when the
@@ -226,7 +223,6 @@ class HistoryCompleter
@currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }
results = []
HistoryCache.use (history) =>
- searchUrl = Settings.get "searchUrl"
results =
if queryTerms.length > 0
history.filter (entry) -> RankingUtils.matches(queryTerms, entry.url, entry.title)
diff --git a/lib/utils.coffee b/lib/utils.coffee
index 724250e0..63b8ba0e 100644
--- a/lib/utils.coffee
+++ b/lib/utils.coffee
@@ -114,7 +114,7 @@ Utils =
searchUrl += "%s" unless 0 <= searchUrl.indexOf "%s"
searchUrl.replace /%s/g, @createSearchQuery query
- # Extract a query from url if it appears to be a URL created generated from the given search URL.
+ # Extract a query from url if it appears to be a URL created from the given search URL.
# For example, map "https://www.google.ie/search?q=star+wars&foo&bar" to "star wars".
extractQuery: do =>
queryTerminator = new RegExp "[?/]"
--
cgit v1.2.3
From a730a3b4639a8eb5f909c7c4acda8e4d6e1ba0b9 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 11:40:34 +0100
Subject: TabToOpen: more tidy up pre-PR (additional comments).
---
background_scripts/completion.coffee | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index cc1ada5b..8a7d0a47 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -22,15 +22,18 @@ class Suggestion
@title = ""
# Extra data which will be available to the relevancy function.
@relevancyData = null
- # If @autoSelect is truthy, then this suggestion is automatically pre-selected in the vomnibar. There may
- # be at most one such suggestion.
+ # If @autoSelect is truthy, then this suggestion is automatically pre-selected in the vomnibar. This only
+ # affects the suggestion in slot 0 in the vomnibar.
@autoSelect = false
- # If @highlightTerms is true, then we highlight matched terms in the title and URL.
+ # If @highlightTerms is true, then we highlight matched terms in the title and URL. Otherwise we don't.
@highlightTerms = true
- # If @insertText is a string, then the indicated text is inserted into the vomnibar input when the
- # suggestion is selected.
+ # @insertText is text to insert into the vomnibar input when the suggestion is selected.
@insertText = null
+ # Other options set by individual completers include:
+ # - tabId (TabCompleter)
+ # - isSearchSuggestion, customSearchMode (SearchEngineCompleter)
+
extend this, @options
computeRelevancy: ->
@@ -539,6 +542,8 @@ class SearchEngineCompleter
unless suggestion.isSearchSuggestion or suggestion.insertText
for engine in engines
if suggestion.insertText = Utils.extractQuery engine.searchUrl, suggestion.url
+ # suggestion.customSearchMode informs the vomnibar that, if the users edits the text from this
+ # suggestion, then custom search-engine mode should be activated.
suggestion.customSearchMode = engine.keyword
suggestion.title = suggestion.insertText
console.log suggestion.insertText, engine unless engine.description
--
cgit v1.2.3
From 5f2b6fb55840ba55bb1ad1519b71fc02bb4823cf Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 12:46:43 +0100
Subject: TabToOpen: turn off relevancy debugging.
---
background_scripts/completion.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 8a7d0a47..e824486d 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -10,7 +10,7 @@
# - refresh(): (optional) refreshes the completer's data source (e.g. refetches the list of bookmarks).
# - cancel(): (optional) cancels any pending, cancelable action.
class Suggestion
- showRelevancy: true # Set this to true to render relevancy when debugging the ranking scores.
+ showRelevancy: false # Set this to true to render relevancy when debugging the ranking scores.
constructor: (@options) ->
# Required options.
--
cgit v1.2.3
From 6387f2e89774c1af7494f8507dfcc1fa245f2524 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 12:52:53 +0100
Subject: TabToOpen: remove console.log.
---
background_scripts/completion.coffee | 1 -
1 file changed, 1 deletion(-)
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index e824486d..77332967 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -546,7 +546,6 @@ class SearchEngineCompleter
# suggestion, then custom search-engine mode should be activated.
suggestion.customSearchMode = engine.keyword
suggestion.title = suggestion.insertText
- console.log suggestion.insertText, engine unless engine.description
suggestion.type = engine.description ? "custom search"
break
--
cgit v1.2.3
From 904398308debad22fedec227ec8e71adb2bc5720 Mon Sep 17 00:00:00 2001
From: Stephen Blott
Date: Sun, 17 May 2015 13:24:46 +0100
Subject: TabToOpen: respect trailing options when extracting query terms.
A custom search engine like this...
i: https://www.google.ie/search?q=%s&num=30&newwindow=1&biw=1918&bih=1015&tbm=isch Google image search
Should not match a URL like this...
https://www.google.ie/search?q=bbc+sport
---
lib/utils.coffee | 9 +++++++--
tests/unit_tests/utils_test.coffee | 10 ++++++++++
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/lib/utils.coffee b/lib/utils.coffee
index 63b8ba0e..03403644 100644
--- a/lib/utils.coffee
+++ b/lib/utils.coffee
@@ -121,10 +121,15 @@ Utils =
httpProtocolRegexp = new RegExp "^https?://"
(searchUrl, url) ->
url = url.replace httpProtocolRegexp
- searchUrl = searchUrl.split("%s")[0].replace httpProtocolRegexp
+ searchUrl = searchUrl.replace httpProtocolRegexp
+ [ searchUrl, suffixTerms... ] = searchUrl.split "%s"
+ # We require the URL to start with the search URL.
+ return null unless url.startsWith searchUrl
+ # We require any remaining terms in the search URL to also be present in the URL.
+ for suffix in suffixTerms
+ return null unless 0 <= url.indexOf suffix
# We use try/catch because decodeURIComponent can throw an exception.
try
- if url.startsWith searchUrl
url[searchUrl.length..].split(queryTerminator)[0].split("+").map(decodeURIComponent).join " "
catch
null
diff --git a/tests/unit_tests/utils_test.coffee b/tests/unit_tests/utils_test.coffee
index 829c7042..9d71cc49 100644
--- a/tests/unit_tests/utils_test.coffee
+++ b/tests/unit_tests/utils_test.coffee
@@ -49,6 +49,16 @@ context "convertToUrl",
assert.equal "https://www.google.com/search?q=go+ogle.com", Utils.convertToUrl("go ogle.com")
assert.equal "https://www.google.com/search?q=%40twitter", Utils.convertToUrl("@twitter")
+context "extractQuery",
+ should "extract queries from search URLs", ->
+ assert.equal "bbc sport 1", Utils.extractQuery "https://www.google.ie/search?q=%s", "https://www.google.ie/search?q=bbc+sport+1"
+ assert.equal "bbc sport 2", Utils.extractQuery "http://www.google.ie/search?q=%s", "https://www.google.ie/search?q=bbc+sport+2"
+ assert.equal "bbc sport 3", Utils.extractQuery "https://www.google.ie/search?q=%s", "http://www.google.ie/search?q=bbc+sport+3"
+ assert.equal "bbc sport 4", Utils.extractQuery "https://www.google.ie/search?q=%s", "http://www.google.ie/search?q=bbc+sport+4&blah"
+
+ should "extract not queries from incorrect search URLs", ->
+ assert.isFalse Utils.extractQuery "https://www.google.ie/search?q=%s&foo=bar", "https://www.google.ie/search?q=bbc+sport"
+
context "hasChromePrefix",
should "detect chrome prefixes of URLs", ->
assert.isTrue Utils.hasChromePrefix "about:foobar"
--
cgit v1.2.3