aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorNiklas Baumstark2012-01-27 23:02:57 +0100
committerNiklas Baumstark2012-04-10 23:59:54 +0200
commit5ee53fc3ef8d4b3a2a616843accb77c30849a26f (patch)
treec134c70d9642b40b9b8cd6f8f55479c0c77f1bc1 /lib
parentf28edd6bcb2a84e7c36700af102006c95468a265 (diff)
downloadvimium-5ee53fc3ef8d4b3a2a616843accb77c30849a26f.tar.bz2
add domain completion a la Chrome omnibox
Diffstat (limited to 'lib')
-rw-r--r--lib/completion.js117
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,