diff options
| author | Stephen Blott | 2015-05-08 16:47:24 +0100 | 
|---|---|---|
| committer | Stephen Blott | 2015-05-08 16:47:24 +0100 | 
| commit | 82d25b5df76c8526d4ccb5352c0905cc28371199 (patch) | |
| tree | b6f695701b4f0801e2022a3699454d5e60e73711 | |
| parent | 5e6fa4ccfc103750b84df02a35f42a6acef78fa1 (diff) | |
| download | vimium-82d25b5df76c8526d4ccb5352c0905cc28371199.tar.bz2 | |
Search completion; search keyword on SPACE.
| -rw-r--r-- | background_scripts/completion.coffee | 22 | ||||
| -rw-r--r-- | lib/utils.coffee | 1 | ||||
| -rw-r--r-- | pages/vomnibar.coffee | 64 | 
3 files changed, 53 insertions, 34 deletions
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 9d249198..ba19970f 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -131,7 +131,8 @@ class BookmarkCompleter    # These bookmarks are loaded asynchronously when refresh() is called.    bookmarks: null -  filter: (@queryTerms, @onComplete) -> +  filter: (queryTerms, @onComplete) -> +    @queryTerms = queryTerms.filter (t) -> 0 < t.length      @currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }      @performSearch() if @bookmarks @@ -193,6 +194,7 @@ class BookmarkCompleter  class HistoryCompleter    filter: (queryTerms, onComplete) -> +    queryTerms = queryTerms.filter (t) -> 0 < t.length      @currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }      results = []      HistoryCache.use (history) => @@ -227,6 +229,7 @@ class DomainCompleter    domains: null    filter: (queryTerms, onComplete) -> +    queryTerms = queryTerms.filter (t) -> 0 < t.length      return onComplete([]) unless queryTerms.length == 1      if @domains        @performSearch(queryTerms, onComplete) @@ -329,6 +332,7 @@ tabRecency = new TabRecency()  # Searches through all open tabs, matching on title and URL.  class TabCompleter    filter: (queryTerms, onComplete) -> +    queryTerms = queryTerms.filter (t) -> 0 < t.length      # NOTE(philc): We search all tabs, not just those in the current window. I'm not sure if this is the      # correct UX.      chrome.tabs.query {}, (tabs) => @@ -366,9 +370,7 @@ class SearchEngineCompleter      queryTerms = queryTerms[1..] if custom      query = queryTerms.join " " - -    if queryTerms.length == 0 -      return onComplete [] +    return onComplete [] if queryTerms.length == 0      # For custom search engines, we add an auto-selected suggestion.      if custom @@ -385,6 +387,10 @@ class SearchEngineCompleter          # Suppress the "w" from "w query terms" in the vomnibar input.          suppressLeadingQueryTerm: true +    # We filter out the empty strings late so that we can distinguish between, for example, "w" and "w ". +    queryTerms = queryTerms.filter (t) -> 0 < t.length +    return onComplete suggestions if queryTerms.length == 0 +      onComplete suggestions,        exclusive: if custom and CompletionEngines.haveCompletionEngine searchUrl then description else null        continuation: (existingSuggestions, onComplete) => @@ -404,6 +410,7 @@ class SearchEngineCompleter          characterCount = query.length - queryTerms.length + 1          relavancy = 0.6 * (Math.min(characterCount, 10.0)/10.0) +        queryTerms = queryTerms.filter (t) -> 0 < t.length          if 0 < existingSuggestions.length            existingSuggestionsMinScore = existingSuggestions[existingSuggestions.length-1].relevancy            if relavancy < existingSuggestionsMinScore and MultiCompleter.maxResults <= existingSuggestions.length @@ -477,10 +484,11 @@ class MultiCompleter        # At most one of the completers (SearchEngineCompleter) may pass a continuation function, which will be        # called after the results of all of the other completers have been posted.  Any additional results        # from this continuation will be added to the existing results and posted later.  We don't call the -      # continuation if another query is already waiting. +      # continuation if another query is already waiting.  This is for slow tasks which should be done +      # asynchronously (e.g. HTTP GET).        continuation: null -      # If truthy, completions from other completers should be discarded.  The truthy value should be the type -      # of the completer (e.g. "custom search"). +      # If truthy, completions from other completers should be suppressed.  The truthy value should be the +      # type of the completer (e.g. "custom search").  All other completion types are suppressed.        exclusive: false      (queryTerms, onComplete) -> diff --git a/lib/utils.coffee b/lib/utils.coffee index 1c24a40f..033fdd2b 100644 --- a/lib/utils.coffee +++ b/lib/utils.coffee @@ -201,6 +201,7 @@ Function::curry = ->  Array.copy = (array) -> Array.prototype.slice.call(array, 0)  String::startsWith = (str) -> @indexOf(str) == 0 +String::ltrim = () -> @replace /^\s+/, ""  globalRoot = window ? global  globalRoot.extend = (hash1, hash2) -> diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee index 1188c411..b228a59b 100644 --- a/pages/vomnibar.coffee +++ b/pages/vomnibar.coffee @@ -61,11 +61,10 @@ class VomnibarUI      @postHideCallback = null    reset: -> +    @clearUpdateTimer()      @completionList.style.display = ""      @input.value = ""      @completions = [] -    window.clearTimeout @updateTimer if @updateTimer? -    @updateTimer = null      @previousAutoSelect = null      @previousInputValue = null      @suppressedLeadingQueryTerm = null @@ -84,10 +83,7 @@ class VomnibarUI      # For custom search engines, we suppress the leading term (e.g. the "w" of "w query terms") within the      # vomnibar input.      if @suppressedLeadingQueryTerm? -      # If we have a suppressed term and the input is empty, then reinstate it. -      if @input.value.trim().split(/\s+/).join("").length == 0 -        @input.value = @getInputValue() -        @suppressedLeadingQueryTerm = null +      @restoreSuppressedQueryTerm()      else if @completions[0]?.suppressLeadingQueryTerm        # We've been asked to suppress the leading query term, and it's not already suppressed.  So suppress it.        queryTerms = @input.value.trim().split /\s+/ @@ -107,8 +103,15 @@ class VomnibarUI      for i in [0...@completionList.children.length]        @completionList.children[i].className = (if i == @selection then "vomnibarSelected" else "") +  restoreSuppressedQueryTerm: -> +    if @suppressedLeadingQueryTerm? +      # If we have a suppressed term and the input is empty, then reinstate it. +      if @input.value.length == 0 +        @input.value = @suppressedLeadingQueryTerm +        @suppressedLeadingQueryTerm = null +    # -  # Returns the user's action ("up", "down", "enter", "dismiss" or null) based on their keypress. +  # Returns the user's action ("up", "down", "enter", "dismiss", "delete" or null) based on their keypress.    # We support the arrow keys and other shortcuts for moving, so this method hides that complexity.    #    actionFromKeyEvent: (event) -> @@ -125,6 +128,9 @@ class VomnibarUI        return "down"      else if (event.keyCode == keyCodes.enter)        return "enter" +    else if event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey +      return "delete" +    null    onKeydown: (event) =>      action = @actionFromKeyEvent(event) @@ -157,6 +163,13 @@ class VomnibarUI        else          completion = @completions[@selection]          @hide -> completion.performAction openInNewTab +    else if action == "delete" +      if @input.value.length == 0 +        @restoreSuppressedQueryTerm() +        @updateCompletions() +      else +        # Don't suppress the Delete.  We want it to happen. +        return true      # It seems like we have to manually suppress the event here and still return true.      event.stopImmediatePropagation() @@ -167,6 +180,7 @@ class VomnibarUI      (if @suppressedLeadingQueryTerm? then @suppressedLeadingQueryTerm + " " else "") + @input.value    updateCompletions: (callback = null) -> +    @clearUpdateTimer()      @completer.filter @getInputValue(), (@completions) =>        @populateUiWithCompletions @completions        callback?() @@ -188,19 +202,18 @@ class VomnibarUI        @selection = -1      @update false +  clearUpdateTimer: -> +    if @updateTimer? +      window.clearTimeout @updateTimer +      @updateTimer = null +    update: (updateSynchronously = false, callback = null) =>      if updateSynchronously -      # Cancel any scheduled update. -      if @updateTimer? -        window.clearTimeout @updateTimer -        @updateTimer = null        @updateCompletions callback      else if not @updateTimer?        # Update asynchronously for better user experience and to take some load off the CPU (not every        # keystroke will cause a dedicated update) -      @updateTimer = Utils.setTimeout @refreshInterval, => -        @updateTimer = null -        @updateCompletions callback +      @updateTimer = Utils.setTimeout @refreshInterval, => @updateCompletions callback      @input.focus() @@ -257,23 +270,21 @@ class BackgroundCompleter          @mostRecentCallback msg.results    filter: (query, @mostRecentCallback) -> -    queryTerms = query.trim().split(/\s+/).filter (term) -> 0 < term.length +    # We retain trailing whitespace so that we can tell the difference between "w" and "w " (for custom search +    # engines). +    queryTerms = query.ltrim().split(/\s+/)      query = queryTerms.join " "      if @cache.has query        console.log "cache hit:", query if @debug        @mostRecentCallback @cache.get query      else -      # Silently drop identical consecutive queries.  This can happen, for example, if the user adds -      # whitespace to the query. -      unless @mostRecentQuery? and query == @mostRecentQuery -        @mostRecentQuery = query -        @messageId = Utils.createUniqueId() -        @port.postMessage -          name: @name -          handler: "filter" -          id: @messageId -          query: query -          queryTerms: queryTerms +      @messageId = Utils.createUniqueId() +      @port.postMessage +        name: @name +        handler: "filter" +        id: @messageId +        query: query +        queryTerms: queryTerms    refresh: ->      @reset() @@ -283,7 +294,6 @@ class BackgroundCompleter    reset: ->      # We only cache results for the duration of a single vomnibar activation, so clear the cache now.      @cache.clear() -    @mostRecentQuery = null    cancel: ->      # Inform the background completer that it may (should it choose to do so) abandon any pending query  | 
