diff options
Diffstat (limited to 'background_scripts/completion.coffee')
| -rw-r--r-- | background_scripts/completion.coffee | 57 | 
1 files changed, 41 insertions, 16 deletions
| diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 91fb85e1..5fc98b88 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -22,18 +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 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. +    # 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: -> @@ -230,13 +230,16 @@ class BookmarkCompleter      RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)  class HistoryCompleter -  filter: ({ queryTerms }, onComplete) -> +  filter: ({ queryTerms, seenTabToOpenCompletionList }, onComplete) ->      @currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }      results = []      HistoryCache.use (history) =>        results =          if queryTerms.length > 0            history.filter (entry) -> RankingUtils.matches(queryTerms, entry.url, entry.title) +        else if seenTabToOpenCompletionList +          # <Tab> opens the completion list, even without a query. +          history          else            []        onComplete results.map (entry) => @@ -251,6 +254,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)      # 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 @@ -397,9 +402,10 @@ 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        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) @@ -468,7 +474,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. @@ -483,8 +489,8 @@ class SearchEngineCompleter        title: queryTerms.join " "        relevancy: 1        autoSelect: custom -      forceAutoSelect: custom        highlightTerms: not haveCompletionEngine +      isSearchSuggestion: true      mkSuggestion = (suggestion) =>        new Suggestion @@ -542,6 +548,22 @@ class SearchEngineCompleter      Suggestion.boostRelevancyScore 0.5,        relevancyData * RankingUtils.wordRelevancy queryTerms, title, title +  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 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.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 +            suggestion.type = engine.description ? "custom search" +            break +  # 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 @@ -559,7 +581,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 @@ -585,7 +607,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 @@ -602,7 +624,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 @@ -614,7 +636,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 @@ -629,6 +651,9 @@ class MultiCompleter          break if count++ == @maxResults          seenUrls[url] = suggestion +    # 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.      suggestion.generateHtml() for suggestion in suggestions      suggestions | 
