diff options
| -rw-r--r-- | background_page.html | 9 | ||||
| -rw-r--r-- | bookmarks.js | 137 | ||||
| -rw-r--r-- | completionDialog.js | 178 | ||||
| -rw-r--r-- | lib/keyboardUtils.js | 22 | ||||
| -rw-r--r-- | manifest.json | 5 | ||||
| -rw-r--r-- | vimiumFrontend.js | 1 |
6 files changed, 350 insertions, 2 deletions
diff --git a/background_page.html b/background_page.html index abb91677..8a6ade8a 100644 --- a/background_page.html +++ b/background_page.html @@ -65,7 +65,8 @@ getCurrentTabUrl: getCurrentTabUrl, getZoomLevel: getZoomLevel, saveZoomLevel: saveZoomLevel, - getSetting: getSetting + getSetting: getSetting, + getBookmarks: getBookmarks }; var sendRequestHandlers = { @@ -282,6 +283,12 @@ returnPort.postMessage({ key: args.key, value: value }); } + function getBookmarks(args, port) { + chrome.bookmarks.search(args.query, function(bookmarks) { + port.postMessage({bookmarks:bookmarks}) + }) + } + /* * Persists the current zoom level for a given domain */ diff --git a/bookmarks.js b/bookmarks.js new file mode 100644 index 00000000..1ec0c3d1 --- /dev/null +++ b/bookmarks.js @@ -0,0 +1,137 @@ + +function activateBookmarkFindModeToOpenInNewTab() { + BookmarkMode.openInNewTab(true) + BookmarkMode.enable() +} + +function activateBookmarkFindMode() { + BookmarkMode.openInNewTab(false) + BookmarkMode.enable() +} + +(function() { + // so when they let go of shift after hitting capital "B" it won't + // untoggle it + var shiftWasPressedWhileToggled = false; + + var BookmarkMode = { + isEnabled: function() { + return this.enabled + }, + openInNewTab: function(newTab) { + this.newTab = newTab + }, + invertNewTabSetting: function() { + this.newTab = !this.newTab; + if(this.isEnabled()) { + this.renderHUD() + } + }, + enable: function() { + this.enabled = true; + + if(!this.initialized) { + initialize.call(this) + } + + this.renderHUD(); + this.completionDialog.show(); + + this.keyPressListener.enable(); + }, + disable: function() { + this.enabled = false; + this.keyPressListener.disable(); + this.completionDialog.hide() + HUD.hide(); + }, + renderHUD: function() { + if (this.newTab) + HUD.show("Open bookmark in new tab"); + else + HUD.show("Open bookmark in current tab"); + } + + } + + // private method + var initialize = function() { + var self = this; + self.initialized = true; + + self.completionDialog = new CompletionDialog({ + source: findBookmarks, + onSelect: function(selection) { + var url = selection.url + var isABookmarklet = function(url) { + return url.indexOf("javascript:")===0 + } + + if(!self.newTab || isABookmarklet(url)) { + window.location=url + } + else { + window.open(url) + } + + self.disable(); + }, + renderOption: function(searchString, selection) { + + var displaytext = selection.title + " (" + selection.url + ")" + + if(displaytext.length>70) { + displaytext = displaytext.substr(0, 70)+"..." + } + + return displaytext.split(new RegExp(searchString, "i")).join("<strong>"+searchString+"</strong>") + }, + initialSearchText: "Type a bookmark name or URL" + }) + + this.keyPressListener = new KeyPressListener({ + keyDown: function(event) { + // shift key will toggle between new tab/same tab + if (event.keyCode == keyCodes.shiftKey) { + self.invertNewTabSetting(); + shiftWasPressedWhileToggled = true + return + } + + var keyChar = getKeyChar(event); + if (!keyChar) + return; + + // TODO(philc): Ignore keys that have modifiers. + if (isEscape(event)) { + self.disable(); + } + + event.stopPropagation(); + event.preventDefault(); + }, + keyUp: function(event) { + // shift key will toggle between new tab/same tab + if (event.keyCode == keyCodes.shiftKey && shiftWasPressedWhileToggled) { + self.invertNewTabSetting(); + shiftWasPressedWhileToggled = false + } + event.stopPropagation(); + event.preventDefault(); + } + }) + } + + var findBookmarks = function(searchString, callback) { + var port = chrome.extension.connect({ name: "getBookmarks" }) + port.onMessage.addListener(function(msg) { + callback(msg.bookmarks) + port = null + }) + port.postMessage({query:searchString}) + }; + + //export global + window.BookmarkMode = BookmarkMode; + +}()) diff --git a/completionDialog.js b/completionDialog.js new file mode 100644 index 00000000..c96ce92c --- /dev/null +++ b/completionDialog.js @@ -0,0 +1,178 @@ +(function(window, document) { + + var CompletionDialog = function(options) { + this.options = options + } + + CompletionDialog.prototype = { + show: function() { + if(!this.isShown) { + this.isShown=true; + this.query = []; + if(!this.initialized) { + initialize.call(this); + this.initialized=true; + } + this.keyPressListener.enable(); + render.call(this) + clearInterval(this._tweenId); + this._tweenId = Tween.fade(this.container, 1.0, 150); + } + }, + hide: function() { + if(this.isShown) { + this.keyPressListener.disable(); + this.isShown=false; + this.currentSelection=0; + clearInterval(this._tweenId); + this._tweenId = Tween.fade(this.container, 0, 150); + } + }, + getDisplayElement: function() { + if(!this.container) { + this.container = createDivInside(document.body) + } + return this.container + }, + getQueryString: function() { + return this.query.join("") + } + } + + var initialize = function() { + var self = this + addCssToPage(completionCSS) + + self.currentSelection=0; + + self.keyPressListener = new KeyPressListener({ + keyDown: function(event) { + var keyChar = getKeyChar(event); + if(keyChar==="up") { + if(self.currentSelection>0) { + self.currentSelection-=1; + } + render.call(self,self.getQueryString(), self.completions) + } + else if(keyChar==="down") { + if(self.currentSelection<self.completions.length-1) { + self.currentSelection+=1; + } + render.call(self,self.getQueryString(), self.completions) + } + else if(event.keyCode == keyCodes.enter) { + self.options.onSelect(self.completions[self.currentSelection]) + } + else if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey) { + if (self.query.length > 0) { + self.query.pop(); + self.options.source(self.getQueryString(), function(completions) { + render.call(self, self.getQueryString(), completions) + }) + } + } + else if(keyChar!=="left" && keyChar!="right") { + self.query.push(keyChar); + self.options.source(self.getQueryString(), function(completions) { + render.call(self, self.getQueryString(), completions) + }) + } + + event.stopPropagation(); + event.preventDefault(); + } + }) + } + + var render = function(searchString, completions) { + if(this.isShown) { + this.searchString = searchString; + this.completions = completions; + var container = this.getDisplayElement() + clearChildren(container); + + if(searchString===undefined) { + this.container.className = "vimium-dialog"; + createDivInside(container).innerHTML=this.options.initialSearchText || "Begin typing" + } + else { + this.container.className = "vimium-dialog vimium-completions"; + var searchBar = createDivInside(container) + searchBar.innerHTML=searchString + searchBar.className="vimium-searchBar" + + searchResults = createDivInside(container) + searchResults.className="vimium-searchResults" + if(completions.length<=0) { + var resultDiv = createDivInside(searchResults) + resultDiv.className="vimium-noResults" + resultDiv.innerHTML="No results found" + } + else { + for(var i=0;i<completions.length;i++) { + var resultDiv = createDivInside(searchResults) + if(i===this.currentSelection) { + resultDiv.className="vimium-selected" + } + resultDiv.innerHTML=this.options.renderOption(searchString, completions[i]) + } + } + } + + container.style.top=(window.innerHeight/2-container.clientHeight/2) + "px"; + container.style.left=(window.innerWidth/2-container.clientWidth/2) + "px"; + } + }; + var createDivInside = function(parent) { + var element = document.createElement("div"); + parent.appendChild(element); + return element + } + + var clearChildren = function(elem) { + if (elem.hasChildNodes()) { + while (elem.childNodes.length >= 1) { + elem.removeChild(elem.firstChild); + } + } + } + + var completionCSS = ".vimium-dialog {"+ + "position:fixed;"+ + "background-color: #ebebeb;" + + "z-index: 99999998;" + + "border: 1px solid #b3b3b3;" + + "font-size: 12px;" + + "text-align:left;"+ + "color: black;" + + "padding:10px;"+ + "border-radius: 4px;" + + "font-family: Lucida Grande, Arial, Sans;" + + "}"+ + ".vimium-completions {"+ + "width:400px;"+ + "}"+ + ".vimium-completions .vimium-searchBar {"+ + "height: 15px;"+ + "border-bottom: 1px solid #b3b3b3;"+ + "}"+ + ".vimium-completions .vimium-searchResults {"+ + "}"+ + ".vimium-completions .vimium-searchResults .vimium-selected{"+ + "background-color:#aaa;"+ + "border-radius: 4px;" + + "}"+ + ".vimium-completions div{"+ + "padding:4px;"+ + "}"+ + ".vimium-completions div strong{"+ + "color: black;" + + "font-weight:bold;"+ + "}"+ + ".vimium-completions .vimium-noResults{"+ + "color:#555;"+ + "}"; + + window.CompletionDialog = CompletionDialog; + +}(window, document)) diff --git a/lib/keyboardUtils.js b/lib/keyboardUtils.js index fe3dcd59..5b8b4c84 100644 --- a/lib/keyboardUtils.js +++ b/lib/keyboardUtils.js @@ -61,3 +61,25 @@ function isEscape(event) { return event.keyCode == keyCodes.ESC || (event.ctrlKey && getKeyChar(event) == '['); // c-[ is mapped to ESC in Vim by default. } + +var KeyPressListener = function(handlers) { + this.handlers = handlers; +} + +KeyPressListener.prototype = { + enable: function() { + var handlers = this.handlers; + var wrapper = function(callback){ + return function(event) { + callback(event) + } + } + (handlers.keyDown && document.addEventListener("keydown", handlers.keyDown, true)); + (handlers.keyUp && document.addEventListener("keyup", handlers.keyUp, true)); + }, + disable: function() { + var handlers = this.handlers; + (handlers.keyDown && document.removeEventListener("keydown", handlers.keyDown, true)); + (handlers.keyUp && document.removeEventListener("keyup", handlers.keyUp, true)); + } +} diff --git a/manifest.json b/manifest.json index 181c8739..e100f42d 100644 --- a/manifest.json +++ b/manifest.json @@ -9,6 +9,7 @@ "options_page": "options.html", "permissions": [ "tabs", + "bookmarks", "http://*/*", "https://*/*" ], @@ -19,7 +20,9 @@ "lib/keyboardUtils.js", "lib/clipboard.js", "linkHints.js", - "vimiumFrontend.js" + "vimiumFrontend.js", + "completionDialog.js", + "bookmarks.js" ], "run_at": "document_start", "all_frames": true diff --git a/vimiumFrontend.js b/vimiumFrontend.js index e0b6eb6a..6877be5f 100644 --- a/vimiumFrontend.js +++ b/vimiumFrontend.js @@ -266,6 +266,7 @@ function scrollFullPageDown() { window.scrollBy(0, window.innerHeight); } function scrollLeft() { window.scrollBy(-1 * settings.get("scrollStepSize"), 0); } function scrollRight() { window.scrollBy(settings.get("scrollStepSize"), 0); } + function focusInput(count) { var results = document.evaluate(textInputXPath, document.documentElement, null, |
