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, |
