diff options
| author | Niklas Baumstark | 2012-01-27 23:02:57 +0100 | 
|---|---|---|
| committer | Niklas Baumstark | 2012-04-10 23:59:54 +0200 | 
| commit | 5ee53fc3ef8d4b3a2a616843accb77c30849a26f (patch) | |
| tree | c134c70d9642b40b9b8cd6f8f55479c0c77f1bc1 /lib | |
| parent | f28edd6bcb2a84e7c36700af102006c95468a265 (diff) | |
| download | vimium-5ee53fc3ef8d4b3a2a616843accb77c30849a26f.tar.bz2 | |
add domain completion a la Chrome omnibox
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/completion.js | 117 | 
1 files changed, 88 insertions, 29 deletions
diff --git a/lib/completion.js b/lib/completion.js index 58f140f9..935773a5 100644 --- a/lib/completion.js +++ b/lib/completion.js @@ -84,7 +84,6 @@ var completion = (function() {      /** Trims the size of the caches to the configured size using a FIFO algorithm. */      self.cleanCache = function() { -      console.log("cleaning cache");        // remove old cached regexes        Object.keys(self.matcherCache).slice(self.cacheSize).forEach(function(query) {          delete self.matcherCache[query]; @@ -178,7 +177,9 @@ var completion = (function() {      if (!positions)        return str.replace(htmlRegex, ''); -    var match = str.match(htmlRegex).reverse(); +    var match = str.match(htmlRegex); +    if (!match) return; +    match.reverse();      var split = str.split(htmlRegex);      var offset = 0;      var i = 0; @@ -278,6 +279,34 @@ var completion = (function() {      this.build = builder;    } +  /** Singleton object that provides fast access to the Chrome history */ +  var historyCache = (function() { +    var size = 20000; +    var cachedHistory = null; + +    function use(callback) { +      if (cachedHistory !== null) +        return callback(cachedHistory); + +      chrome.history.search({ text: '', maxResults: size, startTime: 0 }, function(history) { +        // sorting in ascending order, so we can push new items to the end later +        history.sort(function(a, b) { +          return (a.lastVisitTime|| 0) - (b.lastVisitTime || 0); +        }); +        cachedHistory = history; +        callback(history); +      }); + +      chrome.history.onVisited.addListener(function(item) { +        // only cache newly visited sites +        if (item.visitCount === 1) +          cachedHistory.push(item); +      }); +    } + +    return { use: use }; +  })() +    /** Helper class to construct fuzzy completers for asynchronous data sources like history or bookmark     * matchers. */    var AsyncCompletionSource = function() { @@ -429,41 +458,15 @@ var completion = (function() {    /** A fuzzy history completer */    var FuzzyHistoryCompletionSource = function(maxResults) {      AsyncCompletionSource.call(this); -    this.cachedHistory = null;      this.maxResults = maxResults;    }    utils.extend(AsyncCompletionSource, FuzzyHistoryCompletionSource); -  FuzzyHistoryCompletionSource.prototype.useHistory = function(callback) { -    var self = this; -    if (self.cachedHistory !== null) -      return callback(self.cachedHistory); - -    chrome.history.search({ -        text: '', -        maxResults: 20000, -        startTime: 0, -    }, function(history) { -      // sorting in ascending order, so we can push new items to the end later -      history.sort(function(a, b) { -        return (a.lastVisitTime|| 0) - (b.lastVisitTime || 0); -      }); -      self.cachedHistory = history; -      callback(history); -    }); - -    chrome.history.onVisited.addListener(function(item) { -      // only cache newly visited sites -      if (item.visitCount === 1) -        self.cachedHistory.push(item); -    }); -  } -    FuzzyHistoryCompletionSource.prototype.refresh = function() {      var self = this;      self.reset(); -    self.useHistory(function(history) { +    historyCache.use(function(history) {        self.resultsReady(history.slice(-self.maxResults).map(function(item) {          return self.createInternalMatch('history', item);        })) @@ -489,6 +492,61 @@ var completion = (function() {      });    } +  /** A domain completer as it is provided by Chrome's omnibox */ +  var DomainCompletionSource = function() { +    this.domains = null; +  } + +  DomainCompletionSource.prototype.withDomains = function(callback) { +    var self = this; +    if (self.domains !== null) +      return callback(Object.keys(self.domains)); + +    self.domains = {}; + +    function processDomain(domain) { +      self.domains[domain] = true; +      delete self.domains['www.' + domain]; +    } +    function extractDomain(url) { return url.split('/')[2]; } + +    historyCache.use(function(history) { +      history.forEach(function(item) { +        processDomain(extractDomain(item.url)); +      }); +    }); +    // delete redundant www. domains +    Object.keys(self.domains).forEach(function(domain) { processDomain(domain); }); + +    chrome.history.onVisited.addListener(function(item) { +      processDomain(extractDomain(item.url)); +    }); +    callback(Object.keys(self.domains)); +  } + +  DomainCompletionSource.prototype.refresh = function() { } +  DomainCompletionSource.prototype.filter = function(query, callback) { +    var best = null; +    this.withDomains(function(domains) { +      var bestOffset = 1000; +      domains.forEach(function(domain) { +        var offset = domain.indexOf(query); +        if (offset < 0 || offset >= bestOffset) +          return; + +        // found a new optimum +        bestOffset = offset; +        best = new LazyCompletion(-1.5, function() { +          return { +            html:   createCompletionHtml('site', domain), +            action: {func: 'completion.createActionOpenUrl', args: [utils.createFullUrl(domain)]}, +          }}); +      }); +    }); +    callback(best ? [best] : []); +  } + +  /** Get completion results from the background page */    var BackgroundCompleter = function(name) {      this.name = name;      this.filterPort = chrome.extension.connect({ name: 'filterCompleter' }); @@ -560,6 +618,7 @@ var completion = (function() {      FuzzyHistoryCompletionSource: FuzzyHistoryCompletionSource,      FuzzyTabCompletionSource: FuzzyTabCompletionSource,      SmartCompletionSource: SmartCompletionSource, +    DomainCompletionSource: DomainCompletionSource,      MultiCompleter: MultiCompleter,      BackgroundCompleter: BackgroundCompleter,      createActionOpenUrl: createActionOpenUrl,  | 
