aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorNiklas Baumstark2012-01-25 01:53:41 +0100
committerNiklas Baumstark2012-04-10 23:58:07 +0200
commit386c08403503ffad5e08e4f554529c248fdaa8bc (patch)
tree4587cefc3ba6523406b9b289915a8cb949da8538 /lib
parentd761e429f7c6b8583d32f7849fdbeb9aa2b50faf (diff)
downloadvimium-386c08403503ffad5e08e4f554529c248fdaa8bc.tar.bz2
code cleanup + small bugfixes
Diffstat (limited to 'lib')
-rw-r--r--lib/completion.js123
1 files changed, 44 insertions, 79 deletions
diff --git a/lib/completion.js b/lib/completion.js
index 3c43f28b..a2f97c2c 100644
--- a/lib/completion.js
+++ b/lib/completion.js
@@ -153,10 +153,10 @@ var completion = (function() {
return self;
})();
- /** Strips HTML tags using a naive regex replacement. Optionally, saves the stripped HTML tags in a
- * dictionary indexed by the position where the tag should be reinserted. */
+ /** Strips HTML tags and escape sequences using a naive regex replacement. Optionally, saves the stripped
+ * HTML tags in a dictionary indexed by the position where the tag should be reinserted. */
function stripHtmlTags(str, positions) {
- var result = str.replace(/<[^>]*>/g, '');
+ var result = str.replace(/<[^>]*>|&[a-z]+;/gi, '');
if (!positions)
return result;
@@ -240,6 +240,14 @@ var completion = (function() {
}
}
+ /** Creates an file-internal representation of a URL match with the given paramters */
+ function createCompletionHtml(type, url, title) {
+ title = title || '';
+ // sanitize input, it could come from a malicious web site
+ title = title.length > 0 ? ' <span class="title">' + utils.escapeHtml(title) + '</span>' : '';
+ return '<em>' + type + '</em> ' + utils.escapeHtml(url) + title;
+ }
+
/** Creates a function that returns a constant value */
function createConstantFunction(x) {
return function() { return x; }
@@ -323,88 +331,43 @@ var completion = (function() {
this.refresh = function() { };
- // TODO make this shorter and use a more functional way to do it
-
- /** Checks if the input is a special command and if yes, add according suggestions to the given array */
- this.addCommandSuggestions = function(query, suggestions) {
- // check if the input is a special command
- for (var i = 0; i < commandKeys.length; ++i) {
- var key = commandKeys[i];
- if (query.indexOf(key) != 0)
- continue;
-
- var term = query.slice(key.length, query.length);
- var command = commands[key];
- var desc = command[0];
- var pattern = command[1];
- var url;
+ /** Returns the suggestions matching the user-defined commands */
+ this.getCommandSuggestions = function(query, suggestions) {
+ return commandKeys.filter(function(cmd) { return query.indexOf(cmd) == 0 }).map(function(cmd) {
+ var term = query.slice(cmd.length);
+ var desc = commands[cmd][0];
+ var pattern = commands[cmd][1];
+ var url = typeof pattern == 'function' ? pattern(term) : pattern.replace(/%s/g, term);
- if (typeof pattern === 'function')
- url = pattern(term);
- else
- url = pattern.replace(/%s/g, term);
-
- suggestions.push({
- render: createConstantFunction('<em>' + desc + '</em> ' + term),
+ return {
+ render: function() { return createCompletionHtml(desc, term) },
action: createActionOpenUrl(utils.createFullUrl(url)),
- relevancy: -2, // this will appear even before the URL/search suggestion
- });
- }
+ relevancy: -2 // this will appear even before the URL/search suggestion
+ };
+ });
}
- /** Checks if the input is a URL. If yes, add the URL to the list of suggestions. If no, add a search
- * query to the list of suggestions. */
- this.addUrlOrSearchSuggestion = function(query, suggestions) {
- var url, str;
-
+ /** Checks if the input is a URL. If yes, returns a suggestion to visit it. If no, returns a suggestion
+ * to start a web search. */
+ this.getUrlOrSearchSuggestions = function(query, suggestions) {
// trim query
query = query.replace(/^\s+|\s+$/g, '');
- // TODO fix HTML injection
- if (utils.isUrl(query)) {
- url = utils.createFullUrl(query);
- str = '<em>goto</em> ' + query;
- } else {
- url = utils.createSearchUrl(query);
- str = '<em>search</em> ' + query;
- }
- suggestions.push({
- render: function() { return str; },
- action: createActionOpenUrl(url),
- // relevancy will always be the lowest one, so the suggestion is at the top
- relevancy: -1,
- });
+ var isUrl = utils.isUrl(query);
+
+ return [{
+ render: function() { return createCompletionHtml(isUrl ? 'goto' : 'search', query); },
+ action: createActionOpenUrl(isUrl ? utils.createFullUrl(query)
+ : utils.createSearchUrl(query)),
+ relevancy: -1, // low relevancy so this should appear at the top
+ }];
}
this.filter = function(query, callback) {
- var suggestions = [];
- this.addCommandSuggestions(query, suggestions);
- this.addUrlOrSearchSuggestion(query, suggestions);
- callback(suggestions);
- };
- }
-
- // TODO fix HTML injection
- function createUrlSuggestion(type, url, title) {
- title = title.length > 0 ? ' <span class="title">' + title + '</span>' : '';
- return { str: '<em>' + type + '</em> ' + url + title,
- url: url };
+ callback(this.getCommandSuggestions(query).concat(
+ this.getUrlOrSearchSuggestions(query)));
+ }
}
- /** Convenience function to remove shared code in the completers. Clear the completion cache, sends
- * a message to an extension port and pipes the returned message through a callback before storing it into
- * the instance's completion cache.
- */
- function fetchFromPort(self, name, query, callback) {
- self.completions = null; // reset completions
-
- // asynchronously fetch from a port
- var port = chrome.extension.connect({ name: name }) ;
- port.onMessage.addListener(function(msg) {
- self.readyCallback(callback(msg));
- });
- port.postMessage(query);
- };
-
/** A fuzzy history completer */
var FuzzyHistoryCompleter = function(maxResults) {
AsyncFuzzyUrlCompleter.call(this);
@@ -415,7 +378,8 @@ var completion = (function() {
this.resetCache();
this.fetchFromPort('getHistory', { maxResults: this.maxResults }, function(msg) {
return msg.history.map(function(historyItem) {
- return createUrlSuggestion('history', historyItem.url, historyItem.title);
+ return { str: createCompletionHtml('history', historyItem.url, historyItem.title),
+ url: historyItem.url };
});
});
}
@@ -430,7 +394,8 @@ var completion = (function() {
this.fetchFromPort('getAllBookmarks', {}, function(msg) {
return msg.bookmarks.filter(function(bookmark) { return bookmark.url !== undefined })
.map(function(bookmark) {
- return createUrlSuggestion('bookmark', bookmark.url, bookmark.title);
+ return { str: createCompletionHtml('bookmark', bookmark.url, bookmark.title),
+ url: bookmark.url };
})
});
}
@@ -450,9 +415,9 @@ var completion = (function() {
this.resetCache();
this.fetchFromPort('getTabsInCurrentWindow', {}, function(msg) {
return msg.tabs.map(function(tab) {
- suggestion = createUrlSuggestion('tab', tab.url, tab.title);
- suggestion.tab = tab;
- return suggestion;
+ return { str: createCompletionHtml('tab', tab.url, tab.title),
+ url: tab.url,
+ tab: tab };
});
});
}