aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormike-work2014-05-07 23:57:56 +0100
committermike-work2014-05-29 02:42:51 +0100
commita18ad484f2fdc0019c15d94405c915f8bfe6d76f (patch)
tree3a8667096504d09b85ac0cd1cf4135763c95e375
parent1aa7ba3a5810742d14edfb738120b70f4a0f7619 (diff)
downloadvimium-a18ad484f2fdc0019c15d94405c915f8bfe6d76f.tar.bz2
Adding in search engines feature to fix #1009
-rw-r--r--background_scripts/completion.coffee22
-rw-r--r--background_scripts/main.coffee2
-rw-r--r--background_scripts/settings.coffee21
-rw-r--r--pages/options.coffee4
-rw-r--r--pages/options.html27
-rw-r--r--tests/unit_tests/completion_test.coffee14
-rw-r--r--tests/unit_tests/settings_test.coffee9
7 files changed, 96 insertions, 3 deletions
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index beb7003a..2868308a 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -248,6 +248,27 @@ class TabCompleter
computeRelevancy: (suggestion) ->
RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
+# A completer which will return your search engines
+class SearchEngineCompleter
+ searchEngines: {}
+
+ filter: (queryTerms, onComplete) ->
+ searchEngineMatch = this.getSearchEngineMatches(queryTerms[0])
+ suggestions = []
+ if searchEngineMatch
+ searchEngineMatch = searchEngineMatch.replace(/%s/g, queryTerms[1..].join(" "))
+ suggestion = new Suggestion(queryTerms, "search", searchEngineMatch, queryTerms[0] + ": " + queryTerms[1..].join(" "), @computeRelevancy)
+ suggestions.push(suggestion)
+ onComplete(suggestions)
+
+ computeRelevancy: -> 1
+
+ refresh: ->
+ this.searchEngines = root.Settings.getSearchEngines()
+
+ getSearchEngineMatches: (queryTerm) ->
+ this.searchEngines[queryTerm]
+
# A completer which calls filter() on many completers, aggregates the results, ranks them, and returns the top
# 10. Queries from the vomnibar frontend script come through a multi completer.
class MultiCompleter
@@ -436,6 +457,7 @@ root.MultiCompleter = MultiCompleter
root.HistoryCompleter = HistoryCompleter
root.DomainCompleter = DomainCompleter
root.TabCompleter = TabCompleter
+root.SearchEngineCompleter = SearchEngineCompleter
root.HistoryCache = HistoryCache
root.RankingUtils = RankingUtils
root.RegexpCache = RegexpCache
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee
index b2b4669c..00b96643 100644
--- a/background_scripts/main.coffee
+++ b/background_scripts/main.coffee
@@ -24,9 +24,11 @@ completionSources =
history: new HistoryCompleter()
domains: new DomainCompleter()
tabs: new TabCompleter()
+ seachEngines: new SearchEngineCompleter()
completers =
omni: new MultiCompleter([
+ completionSources.seachEngines,
completionSources.bookmarks,
completionSources.history,
completionSources.domains])
diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee
index c26da5a4..175f3262 100644
--- a/background_scripts/settings.coffee
+++ b/background_scripts/settings.coffee
@@ -32,10 +32,28 @@ root.Settings = Settings =
root.Commands.parseCustomKeyMappings value
root.refreshCompletionKeysAfterMappingSave()
+ searchEngines: (value) ->
+ root.Settings.parseSearchEngines value
+
# postUpdateHooks convenience wrapper
performPostUpdateHook: (key, value) ->
@postUpdateHooks[key] value if @postUpdateHooks[key]
+ # Here we have our functions that parse the search engines
+ # this is a map that we use to store our search engines for use.
+ searchEnginesMap: {}
+
+ # this parses the search engines settings and clears the old searchEngines and sets the new one
+ parseSearchEngines: (searchEnginesText) ->
+ @searchEnginesMap = {}
+ # find the split pairs by first splitting by line then splitting on the first `: `
+ split_pairs = ( pair.split( /: (.+)/, 2) for pair in searchEnginesText.split( /\n/ ) when pair[0] != "#" )
+ @searchEnginesMap[a[0]] = a[1] for a in split_pairs
+ @searchEnginesMap
+ getSearchEngines: ->
+ this.parseSearchEngines(@get("searchEngines") || "") if Object.keys(@searchEnginesMap).length == 0
+ @searchEnginesMap
+
# options.coffee and options.html only handle booleans and strings; therefore all defaults must be booleans
# or strings
defaults:
@@ -78,9 +96,12 @@ root.Settings = Settings =
nextPatterns: "next,more,>,\u2192,\xbb,\u226b,>>"
# default/fall back search engine
searchUrl: "http://www.google.com/search?q="
+ # put in an example search engine
+ searchEngines: "w: http://www.wikipedia.org/w/index.php?title=Special:Search&search=%s"
settingsVersion: Utils.getCurrentVersion()
+
# We use settingsVersion to coordinate any necessary schema changes.
if Utils.compareVersions("1.42", Settings.get("settingsVersion")) != -1
Settings.set("scrollStepSize", parseFloat Settings.get("scrollStepSize"))
diff --git a/pages/options.coffee b/pages/options.coffee
index 34696f68..d73d8f15 100644
--- a/pages/options.coffee
+++ b/pages/options.coffee
@@ -4,9 +4,9 @@ bgSettings = chrome.extension.getBackgroundPage().Settings
editableFields = [ "scrollStepSize", "excludedUrls", "linkHintCharacters", "linkHintNumbers",
"userDefinedLinkHintCss", "keyMappings", "filterLinkHints", "previousPatterns",
- "nextPatterns", "hideHud", "regexFindMode", "searchUrl"]
+ "nextPatterns", "hideHud", "regexFindMode", "searchUrl", "searchEngines"]
-canBeEmptyFields = ["excludedUrls", "keyMappings", "userDefinedLinkHintCss"]
+canBeEmptyFields = ["excludedUrls", "keyMappings", "userDefinedLinkHintCss", "searchEngines"]
document.addEventListener "DOMContentLoaded", ->
populateOptions()
diff --git a/pages/options.html b/pages/options.html
index 8c7c007a..5450a774 100644
--- a/pages/options.html
+++ b/pages/options.html
@@ -122,6 +122,10 @@
width: 100%;
min-height: 135px;
}
+ textarea#searchEngines {
+ width: 100%;
+ min-height: 135px;
+ }
input#previousPatterns, input#nextPatterns {
width: 100%;
}
@@ -330,12 +334,33 @@ unmapAll
<td verticalAlign="top">
<div class="help">
<div class="example">
- Set which search engine is used when searching from the Vomnibar (examples: "http://duckduckgo.com/?q=", "http://www.google.com/search?q=").
+ Set which search engine is used when searching from the Vomnibar (examples: "http://duckduckgo.com/?q=").
</div>
</div>
<input id="searchUrl" type="text" />
</td>
</tr>
+ <tr>
+ <td class="caption">Search Engines</td>
+ <td verticalAlign="top">
+ <div class="help">
+ <div class="example">
+ Allow customised search engines the format is `token: http://address.com/q?=%s`
+ <br/>
+ token must not contain a colon.
+ <br/>
+ comments are allowed and start with '#'
+ <br/>
+ all `%s` will be replaced with the query string
+ <br/>
+ for a list of default and extra search engines please see <a href="https://gist.github.com/mhauserr/1918ecd63393a9cb23c4">here</a>
+ <br/>
+ to subsequently search for something just type token follewed by your search terms
+ </div>
+ </div>
+ <textarea id="searchEngines"></textarea>
+ </td>
+ </tr>
</tbody>
</table>
diff --git a/tests/unit_tests/completion_test.coffee b/tests/unit_tests/completion_test.coffee
index fb267f63..43ecb49d 100644
--- a/tests/unit_tests/completion_test.coffee
+++ b/tests/unit_tests/completion_test.coffee
@@ -209,6 +209,20 @@ context "tab completer",
assert.arrayEqual ["tab2.com"], results.map (tab) -> tab.url
assert.arrayEqual [2], results.map (tab) -> tab.tabId
+context "search engines",
+ setup ->
+ searchEngines = "foo: bar?q=%s\n# comment\nbaz: qux?q=%s"
+ Settings.set 'searchEngines', searchEngines
+ @completer = new SearchEngineCompleter()
+ # note, I couldn't just call @completer.refresh() here as I couldn't set root.Settings without errors
+ # workaround is below, would be good for someone that understands the testing system better than me to improve
+ @completer.searchEngines = Settings.getSearchEngines()
+
+ should "return search engine suggestion", ->
+ results = filterCompleter(@completer, ["foo", "hello"])
+ assert.arrayEqual ["bar?q=hello"], results.map (result) -> result.url
+ assert.arrayEqual ["foo: hello"], results.map (result) -> result.title
+
context "suggestions",
should "escape html in page titles", ->
suggestion = new Suggestion(["queryterm"], "tab", "url", "title <span>", returns(1))
diff --git a/tests/unit_tests/settings_test.coffee b/tests/unit_tests/settings_test.coffee
index 25bb3628..1283497c 100644
--- a/tests/unit_tests/settings_test.coffee
+++ b/tests/unit_tests/settings_test.coffee
@@ -70,5 +70,14 @@ context "settings",
chrome.storage.sync.set { scrollStepSize: JSON.stringify(message) }
assert.equal message, Sync.message
+ should "set search engines, retrieve them correctly and check that it has been parsed correctly", ->
+ searchEngines = "foo: bar?q=%s\n# comment\nbaz: qux?q=%s"
+ parsedSearchEngines = {"foo": "bar?q=%s", "baz": "qux?q=%s"}
+ Settings.set 'searchEngines', searchEngines
+ assert.equal(searchEngines, Settings.get('searchEngines'))
+ result = Settings.getSearchEngines()
+ assert.isTrue(parsedSearchEngines["foo"] == result["foo"] &&
+ parsedSearchEngines["baz"] == result["baz"] && Object.keys(result).length == 2)
+
should "sync a key which is not a known setting (without crashing)", ->
chrome.storage.sync.set { notASetting: JSON.stringify("notAUsefullValue") }