diff options
| author | Niklas Baumstark | 2012-01-25 01:53:41 +0100 |
|---|---|---|
| committer | Niklas Baumstark | 2012-04-10 23:58:07 +0200 |
| commit | 386c08403503ffad5e08e4f554529c248fdaa8bc (patch) | |
| tree | 4587cefc3ba6523406b9b289915a8cb949da8538 /lib | |
| parent | d761e429f7c6b8583d32f7849fdbeb9aa2b50faf (diff) | |
| download | vimium-386c08403503ffad5e08e4f554529c248fdaa8bc.tar.bz2 | |
code cleanup + small bugfixes
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/completion.js | 123 |
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 }; }); }); } |
