From 98b3d851a74034db8cec07488f7c3ab8c33a9d5f Mon Sep 17 00:00:00 2001 From: Phil Crosby Date: Sat, 5 May 2012 17:27:54 -0700 Subject: Add overview documentation to explain the completion workflow. --- fuzzyMode.js | 1 + lib/completion.js | 57 ++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/fuzzyMode.js b/fuzzyMode.js index fe5b542a..2a38fa6f 100644 --- a/fuzzyMode.js +++ b/fuzzyMode.js @@ -183,6 +183,7 @@ var fuzzyMode = (function() { this.filterPort.onMessage.addListener(function(msg) { if (msg.id != id) return; callback(msg.results.map(function(result) { + // functionName will be either "navigateToUrl" or "switchToTab". args will be a URL or a tab ID. var functionToCall = eval(result.action.functionName); result.performAction = functionToCall.curry(result.action.args); return result; diff --git a/lib/completion.js b/lib/completion.js index de69dc90..0e6b1b8d 100644 --- a/lib/completion.js +++ b/lib/completion.js @@ -1,5 +1,47 @@ +/* + * This contains the definition of the completers used for the Vomnibar's suggestion UI. A complter will take + * a query (whatever the user typed into the Vomnibar) and return a list of matches, e.g. bookmarks, domains, + * URLs from history. + * + * The Vomnibar frontend script makes a "filterCompleter" request to the background page, which in turn calls + * filter() on each these completers. + * + * A completer is a class which has two functions: + * - refresh(): refreshes the completer's data source (e.g. refetches the list of bookmarks from Chrome). + * - filter(query, callback): "query" will be whatever the user typed into the Vomnibar. "callback" is a + * function which will be invoked with a list of LazyCompletionResults as its first argument. + * + * A completer's filter() function returns a list of LazyCompletionResults. This contains a relevancy score + * for the result, as well as a function to build the full result (e.g. the HTML representing this result). + * + * The MultiCompleter collects a big list of LazyCompletionResults from many completers by calling each of + * their filter functions in turn, sorts the results by relevancy, and then calls build() on the top N + * results. This allows us to avoid generating HTML for all of the results we're not going to use. + * The objects returned from build() are sent to the Vomnibox frontend script to be shown in the UI. + */ var completion = (function() { + /* + * An object which contains a relevancy score for the given completion, and a function which can be + * invoked to build its HTML. + * Calling build() should return an object of the form: + * { html: "", action: { functionName: "", args: [] } } + * This object is eventually sent back to the Vomnibox frontend script. "action" contains the action to + * be performed by the frontend script if this result is chosen (user selects it and hits enter). + * "action" includes the function the frontendScript should execute (e.g. "navigateToUrl") along with any + * arguments (like the URL). + * "html" is the HTML representation of this result, with some characters emphasized to higlight the query. + * + * This is called "lazy" because it takes in a function to lazily compute a result's html. That operation + * can be kind of expensive, so you only want to do it to the top completion results, after you've sorted + * them by relevancy. + */ + var LazyCompletionResult = function(relevancy, buildFunction) { + this.relevancy = relevancy; + this.build = buildFunction; + } + + /** Helper class to construct fuzzy completers for asynchronous data sources like history or bookmark * matchers. */ var AsyncCompleter = Class.extend({ @@ -24,7 +66,7 @@ var completion = (function() { action = action || { functionName: "navigateToUrl", args: [url] }; function createLazyCompletion(query) { - return new LazyCompletion(url.length / fuzzyMatcher.calculateRelevancy(query, str), function() { + return new LazyCompletionResult(url.length / fuzzyMatcher.calculateRelevancy(query, str), function() { return { html: renderFuzzy(query, createCompletionHtml.apply(null, parts)), action: action, @@ -84,7 +126,7 @@ var completion = (function() { var url = (typeof pattern == "function") ? pattern(term) : pattern.replace(/%s/g, term); // this will appear even before the URL/search suggestion - return new LazyCompletion(-2, function() { + return new LazyCompletionResult(-2, function() { return { html: createCompletionHtml(desc, term), action: { functionName: "navigateToUrl", args: [utils.createFullUrl(url)] }, @@ -98,7 +140,7 @@ var completion = (function() { // trim query query = query.replace(/^\s+|\s+$/g, ''); var isUrl = utils.isUrl(query); - return new LazyCompletion(-1, function() { + return new LazyCompletionResult(-1, function() { return { html: createCompletionHtml(isUrl ? "goto" : "search", query), action: { functionName: "navigateToUrl", @@ -242,7 +284,7 @@ var completion = (function() { // found a new optimum bestOffset = offset; - best = new LazyCompletion(-1.5, function() { + best = new LazyCompletionResult(-1.5, function() { return { html: createCompletionHtml("site", domain), action: { functionName: "navigateToUrl", args: [protocol + "://" + domain] }, @@ -529,13 +571,6 @@ var completion = (function() { return html.join(''); } - /** A completion class that only holds a relevancy value and a function to get HTML and action - * properties */ - var LazyCompletion = function(relevancy, builder) { - this.relevancy = relevancy; - this.build = builder; - } - /** Singleton object that provides fast access to the Chrome history */ var historyCache = (function() { var size = 20000; -- cgit v1.2.3