diff options
Diffstat (limited to 'vimiumFrontend.js')
| -rw-r--r-- | vimiumFrontend.js | 444 |
1 files changed, 238 insertions, 206 deletions
diff --git a/vimiumFrontend.js b/vimiumFrontend.js index 0e8bdbb5..a9dc1d37 100644 --- a/vimiumFrontend.js +++ b/vimiumFrontend.js @@ -1,41 +1,69 @@ /* * This content script takes input from its webpage and executes commands locally on behalf of the background - * page. It must be run prior to domReady so that we perform some operations very early, like setting - * the page's zoom level. We tell the background page that we're in domReady and ready to accept normal - * commands by connectiong to a port named "domReady". + * page. It must be run prior to domReady so that we perform some operations very early. We tell the + * background page that we're in domReady and ready to accept normal commands by connectiong to a port named + * "domReady". */ -var settings = {}; -var settingsToLoad = ["scrollStepSize", "linkHintCharacters", "previousPatterns", "nextPatterns"]; - var getCurrentUrlHandlers = []; // function(url) -var insertMode = false; +var insertModeLock = null; var findMode = false; var findModeQuery = ""; var findModeQueryHasResults = false; var isShowingHelpDialog = false; +var handlerStack = []; var keyPort; var settingPort; -var saveZoomLevelPort; // Users can disable Vimium on URL patterns via the settings page. var isEnabledForUrl = true; // The user's operating system. var currentCompletionKeys; +var validFirstKeys; var linkHintCss; -// TODO(philc): This should be pulled from the extension's storage when the page loads. -var currentZoomLevel = 100; - // The types in <input type="..."> that we consider for focusInput command. Right now this is recalculated in // each content script. Alternatively we could calculate it once in the background page and use a request to // fetch it each time. // // Should we include the HTML5 date pickers here? -var textInputTypes = ["text", "search", "email", "url", "number"]; + // The corresponding XPath for such elements. -var textInputXPath = '//input[' + - textInputTypes.map(function (type) { return '@type="' + type + '"'; }).join(" or ") + - ' or not(@type)]'; +var textInputXPath = (function() { + var textInputTypes = ["text", "search", "email", "url", "number"]; + var inputElements = ["input[" + + textInputTypes.map(function (type) { return '@type="' + type + '"'; }).join(" or ") + "or not(@type)]", + "textarea"]; + return utils.makeXPath(inputElements); +})(); + +var settings = { + values: {}, + loadedValues: 0, + valuesToLoad: ["scrollStepSize", "linkHintCharacters", "filterLinkHints", "previousPatterns", "nextPatterns"], + + get: function (key) { return this.values[key]; }, + + load: function() { + for (var i in this.valuesToLoad) { this.sendMessage(this.valuesToLoad[i]); } + }, + + sendMessage: function (key) { + if (!settingPort) + settingPort = chrome.extension.connect({ name: "getSetting" }); + settingPort.postMessage({ key: key }); + }, + + receiveMessage: function (args) { + // not using 'this' due to issues with binding on callback + settings.values[args.key] = args.value; + if (++settings.loadedValues == settings.valuesToLoad.length) + settings.initializeOnReady(); + }, + + initializeOnReady: function () { + linkHints.init(); + } +}; /* * Give this frame a unique id. @@ -43,27 +71,16 @@ var textInputXPath = '//input[' + frameId = Math.floor(Math.random()*999999999) var hasModifiersRegex = /^<([amc]-)+.>/; - -function getSetting(key) { - if (!settingPort) - settingPort = chrome.extension.connect({ name: "getSetting" }); - settingPort.postMessage({ key: key }); -} - -function setSetting(args) { settings[args.key] = args.value; } +var googleRegex = /:\/\/[^/]*google[^/]+/; /* - * Complete initialization work that sould be done prior to DOMReady, like setting the page's zoom level. + * Complete initialization work that sould be done prior to DOMReady. */ function initializePreDomReady() { - for (var i in settingsToLoad) { getSetting(settingsToLoad[i]); } + settings.load(); checkIfEnabledForUrl(); - var getZoomLevelPort = chrome.extension.connect({ name: "getZoomLevel" }); - if (window.self == window.parent) - getZoomLevelPort.postMessage({ domain: window.location.host }); - chrome.extension.sendRequest({handler: "getLinkHintCss"}, function (response) { linkHintCss = response.linkHintCss; }); @@ -74,35 +91,36 @@ function initializePreDomReady() { keyPort = chrome.extension.connect({ name: "keyDown" }); chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { - if (request.name == "hideUpgradeNotification") + if (request.name == "hideUpgradeNotification") { HUD.hideUpgradeNotification(); - else if (request.name == "showUpgradeNotification" && isEnabledForUrl) + } else if (request.name == "showUpgradeNotification" && isEnabledForUrl) { HUD.showUpgradeNotification(request.version); - else if (request.name == "showHelpDialog") + } else if (request.name == "showHelpDialog") { if (isShowingHelpDialog) hideHelpDialog(); else showHelpDialog(request.dialogHtml, request.frameId); - else if (request.name == "focusFrame") - if(frameId == request.frameId) + } else if (request.name == "focusFrame") { + if (frameId == request.frameId) focusThisFrame(request.highlight); - else if (request.name == "refreshCompletionKeys") - refreshCompletionKeys(request.completionKeys); + } else if (request.name == "refreshCompletionKeys") { + refreshCompletionKeys(request); + } sendResponse({}); // Free up the resources used by this open connection. }); chrome.extension.onConnect.addListener(function(port, name) { if (port.name == "executePageCommand") { port.onMessage.addListener(function(args) { - if (this[args.command] && frameId == args.frameId) { + if (frameId == args.frameId) { if (args.passCountToFunction) { - this[args.command].call(null, args.count); + utils.invokeCommandString(args.command, [args.count]); } else { - for (var i = 0; i < args.count; i++) { this[args.command].call(); } + for (var i = 0; i < args.count; i++) { utils.invokeCommandString(args.command); } } } - refreshCompletionKeys(args.completionKeys); + refreshCompletionKeys(args); }); } else if (port.name == "getScrollPosition") { @@ -122,14 +140,8 @@ function initializePreDomReady() { port.onMessage.addListener(function(args) { if (getCurrentUrlHandlers.length > 0) { getCurrentUrlHandlers.pop()(args.url); } }); - } else if (port.name == "returnZoomLevel") { - port.onMessage.addListener(function(args) { - currentZoomLevel = args.zoomLevel; - if (isEnabledForUrl) - setPageZoomLevel(currentZoomLevel); - }); } else if (port.name == "returnSetting") { - port.onMessage.addListener(setSetting); + port.onMessage.addListener(settings.receiveMessage); } else if (port.name == "refreshCompletionKeys") { port.onMessage.addListener(function (args) { refreshCompletionKeys(args.completionKeys); @@ -144,6 +156,7 @@ function initializePreDomReady() { function initializeWhenEnabled() { document.addEventListener("keydown", onKeydown, true); document.addEventListener("keypress", onKeypress, true); + document.addEventListener("keyup", onKeyup, true); document.addEventListener("focus", onFocusCapturePhase, true); document.addEventListener("blur", onBlurCapturePhase, true); enterInsertModeIfElementIsFocused(); @@ -183,100 +196,59 @@ function initializeOnDomReady() { }; // This is a little hacky but sometimes the size wasn't available on domReady? -function registerFrameIfSizeAvailable (top) { +function registerFrameIfSizeAvailable (is_top) { if (innerWidth != undefined && innerWidth != 0 && innerHeight != undefined && innerHeight != 0) chrome.extension.sendRequest({ handler: "registerFrame", frameId: frameId, - area: innerWidth * innerHeight, top: top, total: frames.length + 1 }); + area: innerWidth * innerHeight, is_top: is_top, total: frames.length + 1 }); else - setTimeout(function () { registerFrameIfSizeAvailable(top); }, 100); + setTimeout(function () { registerFrameIfSizeAvailable(is_top); }, 100); } /* - * Checks the currently focused element of the document and will enter insert mode if that element is focusable. + * Enters insert mode if the currently focused element in the DOM is focusable. */ function enterInsertModeIfElementIsFocused() { - // Enter insert mode automatically if there's already a text box focused. if (document.activeElement && isEditable(document.activeElement)) - enterInsertMode(); -} - -/* - * Asks the background page to persist the zoom level for the given domain to localStorage. - */ -function saveZoomLevel(domain, zoomLevel) { - if (!saveZoomLevelPort) - saveZoomLevelPort = chrome.extension.connect({ name: "saveZoomLevel" }); - saveZoomLevelPort.postMessage({ domain: domain, zoomLevel: zoomLevel }); -} - -/* - * Zoom in increments of 20%; this matches chrome's CMD+ and CMD- keystrokes. - * Set the zoom style on documentElement because document.body does not exist pre-page load. - */ -function setPageZoomLevel(zoomLevel, showUINotification) { - document.documentElement.style.zoom = zoomLevel + "%"; - if (document.body) - HUD.updatePageZoomLevel(zoomLevel); - if (showUINotification) - HUD.showForDuration("Zoom: " + currentZoomLevel + "%", 1000); -} - -function zoomIn() { - currentZoomLevel += 20; - setAndSaveZoom(); -} - -function zoomOut() { - currentZoomLevel -= 20; - setAndSaveZoom(); -} - -function zoomReset() { - currentZoomLevel = 100; - setAndSaveZoom(); -} - -function setAndSaveZoom() { - setPageZoomLevel(currentZoomLevel, true); - saveZoomLevel(window.location.host, currentZoomLevel); + enterInsertModeWithoutShowingIndicator(document.activeElement); } function scrollToBottom() { window.scrollTo(window.pageXOffset, document.body.scrollHeight); } function scrollToTop() { window.scrollTo(window.pageXOffset, 0); } function scrollToLeft() { window.scrollTo(0, window.pageYOffset); } function scrollToRight() { window.scrollTo(document.body.scrollWidth, window.pageYOffset); } -function scrollUp() { window.scrollBy(0, -1 * settings["scrollStepSize"]); } -function scrollDown() { window.scrollBy(0, settings["scrollStepSize"]); } +function scrollUp() { window.scrollBy(0, -1 * settings.get("scrollStepSize")); } +function scrollDown() { window.scrollBy(0, settings.get("scrollStepSize")); } function scrollPageUp() { window.scrollBy(0, -1 * window.innerHeight / 2); } function scrollPageDown() { window.scrollBy(0, window.innerHeight / 2); } function scrollFullPageUp() { window.scrollBy(0, -window.innerHeight); } function scrollFullPageDown() { window.scrollBy(0, window.innerHeight); } -function scrollLeft() { window.scrollBy(-1 * settings["scrollStepSize"], 0); } -function scrollRight() { window.scrollBy(settings["scrollStepSize"], 0); } +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, - XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); + var results = utils.evaluateXPath(textInputXPath, XPathResult.ORDERED_NODE_ITERATOR_TYPE); var lastInputBox; var i = 0; while (i < count) { - i += 1; - var currentInputBox = results.iterateNext(); if (!currentInputBox) { break; } + if (linkHints.getVisibleClientRect(currentInputBox) === null) + continue; + lastInputBox = currentInputBox; + + i += 1; } if (lastInputBox) { lastInputBox.focus(); } } function reload() { window.location.reload(); } -function goBack() { history.back(); } -function goForward() { history.forward(); } +function goBack(count) { history.go(-count); } +function goForward(count) { history.go(count); } function goUp(count) { var url = window.location.href; @@ -308,6 +280,8 @@ function copyCurrentUrl() { // TODO(ilya): Convert to sendRequest. var getCurrentUrlPort = chrome.extension.connect({ name: "getCurrentTabUrl" }); getCurrentUrlPort.postMessage({}); + + HUD.showForDuration("Yanked URL", 1000); } function toggleViewSourceCallback(url) { @@ -327,18 +301,18 @@ function toggleViewSourceCallback(url) { * Note that some keys will only register keydown events and not keystroke events, e.g. ESC. */ function onKeypress(event) { - var keyChar = ""; - - if (linkHintsModeActivated) + if (!bubbleEvent('keypress', event)) return; + var keyChar = ""; + // Ignore modifier keys by themselves. if (event.keyCode > 31) { keyChar = String.fromCharCode(event.charCode); // Enter insert mode when the user enables the native find interface. if (keyChar == "f" && isPrimaryModifierKey(event)) { - enterInsertMode(); + enterInsertModeWithoutShowingIndicator(); return; } @@ -349,7 +323,7 @@ function onKeypress(event) { // Don't let the space scroll us if we're searching. if (event.keyCode == keyCodes.space) event.preventDefault(); - } else if (!insertMode && !findMode) { + } else if (!isInsertMode() && !findMode) { if (currentCompletionKeys.indexOf(keyChar) != -1) { event.preventDefault(); event.stopPropagation(); @@ -361,18 +335,32 @@ function onKeypress(event) { } } -function onKeydown(event) { - var keyChar = ""; +/** + * Called whenever we receive a key event. Each individual handler has the option to stop the event's + * propagation by returning a falsy value. + */ +function bubbleEvent(type, event) { + for (var i = handlerStack.length-1; i >= 0; i--) { + // We need to check for existence of handler because the last function call may have caused the release of + // more than one handler. + if (handlerStack[i] && handlerStack[i][type] && !handlerStack[i][type](event)) + return false; + } + return true; +} - if (linkHintsModeActivated) +function onKeydown(event) { + if (!bubbleEvent('keydown', event)) return; + var keyChar = ""; + // handle modifiers being pressed.don't handle shiftKey alone (to avoid / being interpreted as ? - if (event.metaKey && event.keyCode > 31 || event.ctrlKey && event.keyCode > 31 || event.altKey && event.keyCode > 31) { + if (event.metaKey && event.keyCode > 31 || event.ctrlKey && event.keyCode > 31 || + event.altKey && event.keyCode > 31) { keyChar = getKeyChar(event); - if (keyChar != "") // Again, ignore just modifiers. Maybe this should replace the keyCode > 31 condition. - { + if (keyChar != "") { // Again, ignore just modifiers. Maybe this should replace the keyCode>31 condition. var modifiers = []; if (event.shiftKey) @@ -392,44 +380,45 @@ function onKeydown(event) { } } - if (insertMode && isEscape(event)) - { + if (isInsertMode() && isEscape(event)) { // Note that we can't programmatically blur out of Flash embeds from Javascript. if (!isEmbed(event.srcElement)) { - // Remove focus so the user can't just get himself back into insert mode by typing in the same input box. - if (isEditable(event.srcElement)) { event.srcElement.blur(); } + // Remove focus so the user can't just get himself back into insert mode by typing in the same input + // box. + if (isEditable(event.srcElement)) + event.srcElement.blur(); exitInsertMode(); - // Added to prevent Google Instant from reclaiming the keystroke and putting us back into the search box. - // TOOD(ilya): Revisit this. Not sure it's the absolute best approach. - event.stopPropagation(); + // Added to prevent Google Instant from reclaiming the keystroke and putting us back into the search + // box. + if (isGoogleSearch()) + event.stopPropagation(); } } - else if (findMode) - { - if (isEscape(event)) + else if (findMode) { + if (isEscape(event)) { exitFindMode(); // Don't let backspace take us back in history. - else if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey) - { + } + else if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey) { handleDeleteForFindMode(); event.preventDefault(); } - else if (event.keyCode == keyCodes.enter) + else if (event.keyCode == keyCodes.enter) { handleEnterForFindMode(); + } } - else if (isShowingHelpDialog && isEscape(event)) - { + else if (isShowingHelpDialog && isEscape(event)) { hideHelpDialog(); } - else if (!insertMode && !findMode) { + else if (!isInsertMode() && !findMode) { if (keyChar) { - if (currentCompletionKeys.indexOf(keyChar) != -1) { - event.preventDefault(); - event.stopPropagation(); - } + if (currentCompletionKeys.indexOf(keyChar) != -1) { + event.preventDefault(); + event.stopPropagation(); + } - keyPort.postMessage({keyChar:keyChar, frameId:frameId}); + keyPort.postMessage({keyChar:keyChar, frameId:frameId}); } else if (isEscape(event)) { keyPort.postMessage({keyChar:"<ESC>", frameId:frameId}); @@ -443,40 +432,55 @@ function onKeydown(event) { // Subject to internationalization issues since we're using keyIdentifier instead of charCode (in keypress). // // TOOD(ilya): Revisit this. Not sure it's the absolute best approach. - if (keyChar == "" && !insertMode && currentCompletionKeys.indexOf(getKeyChar(event)) != -1) + if (keyChar == "" && !isInsertMode() && (currentCompletionKeys.indexOf(getKeyChar(event)) != -1 || + validFirstKeys[getKeyChar(event)])) event.stopPropagation(); } +function onKeyup() { + if (!bubbleEvent('keyup', event)) + return; +} + function checkIfEnabledForUrl() { - var url = window.location.toString(); - - chrome.extension.sendRequest({ handler: "isEnabledForUrl", url: url }, function (response) { - isEnabledForUrl = response.isEnabledForUrl; - if (isEnabledForUrl) - initializeWhenEnabled(); - else if (HUD.isReady()) - // Quickly hide any HUD we might already be showing, e.g. if we entered insertMode on page load. - HUD.hide(); - }); + var url = window.location.toString(); + + chrome.extension.sendRequest({ handler: "isEnabledForUrl", url: url }, function (response) { + isEnabledForUrl = response.isEnabledForUrl; + if (isEnabledForUrl) + initializeWhenEnabled(); + else if (HUD.isReady()) + // Quickly hide any HUD we might already be showing, e.g. if we entered insert mode on page load. + HUD.hide(); + }); } -function refreshCompletionKeys(completionKeys) { - if (completionKeys) - currentCompletionKeys = completionKeys; - else - chrome.extension.sendRequest({handler: "getCompletionKeys"}, function (response) { - currentCompletionKeys = response.completionKeys; - }); +// TODO(ilya): This just checks if "google" is in the domain name. Probably should be more targeted. +function isGoogleSearch() { + var url = window.location.toString(); + return !!url.match(googleRegex); +} + +function refreshCompletionKeys(response) { + if (response) { + currentCompletionKeys = response.completionKeys; + + if (response.validFirstKeys) + validFirstKeys = response.validFirstKeys; + } + else { + chrome.extension.sendRequest({ handler: "getCompletionKeys" }, refreshCompletionKeys); + } } function onFocusCapturePhase(event) { if (isFocusable(event.target)) - enterInsertMode(); + enterInsertModeWithoutShowingIndicator(event.target); } function onBlurCapturePhase(event) { if (isFocusable(event.target)) - exitInsertMode(); + exitInsertMode(event.target); } /* @@ -488,32 +492,52 @@ function isFocusable(element) { return isEditable(element) || isEmbed(element); * Embedded elements like Flash and quicktime players can obtain focus but cannot be programmatically * unfocused. */ -function isEmbed(element) { return ["EMBED", "OBJECT"].indexOf(element.tagName) > 0; } +function isEmbed(element) { return ["embed", "object"].indexOf(element.nodeName.toLowerCase()) > 0; } /* * Input or text elements are considered focusable and able to receieve their own keyboard events, * and will enter enter mode if focused. Also note that the "contentEditable" attribute can be set on * any element which makes it a rich text editor, like the notes on jjot.com. - * Note: we used to discriminate for text-only inputs, but this is not accurate since all input fields - * can be controlled via the keyboard, particuarlly SELECT combo boxes. */ function isEditable(target) { - if (target.getAttribute("contentEditable") == "true") + if (target.isContentEditable) + return true; + var nodeName = target.nodeName.toLowerCase(); + // use a blacklist instead of a whitelist because new form controls are still being implemented for html5 + var noFocus = ["radio", "checkbox"]; + if (nodeName == "input" && noFocus.indexOf(target.type) == -1) return true; - var focusableInputs = ["input", "textarea", "select", "button"]; - return focusableInputs.indexOf(target.tagName.toLowerCase()) >= 0; + var focusableElements = ["textarea", "select"]; + return focusableElements.indexOf(nodeName) >= 0; } -function enterInsertMode() { - insertMode = true; +/* + * Enters insert mode and show an "Insert mode" message. Showing the UI is only useful when entering insert + * mode manually by pressing "i". In most cases we do not show any UI (enterInsertModeWithoutShowingIndicator) + */ +function enterInsertMode(target) { + enterInsertModeWithoutShowingIndicator(target); HUD.show("Insert mode"); } -function exitInsertMode() { - insertMode = false; - HUD.hide(); +/* + * We cannot count on 'focus' and 'blur' events to happen sequentially. For example, if blurring element A + * causes element B to come into focus, we may get "B focus" before "A blur". Thus we only leave insert mode + * when the last editable element that came into focus -- which insertModeLock points to -- has been blurred. + * If insert mode is entered manually (via pressing 'i'), then we set insertModeLock to 'undefined', and only + * leave insert mode when the user presses <ESC>. + */ +function enterInsertModeWithoutShowingIndicator(target) { insertModeLock = target; } + +function exitInsertMode(target) { + if (target === undefined || insertModeLock === target) { + insertModeLock = null; + HUD.hide(); + } } +function isInsertMode() { return insertModeLock !== null; } + function handleKeyCharForFindMode(keyChar) { findModeQuery = findModeQuery + keyChar; performFindInPlace(); @@ -521,13 +545,11 @@ function handleKeyCharForFindMode(keyChar) { } function handleDeleteForFindMode() { - if (findModeQuery.length == 0) - { + if (findModeQuery.length == 0) { exitFindMode(); performFindInPlace(); } - else - { + else { findModeQuery = findModeQuery.substring(0, findModeQuery.length - 1); performFindInPlace(); showFindModeHUDForQuery(); @@ -551,31 +573,51 @@ function performFindInPlace() { // backwards. window.scrollTo(cachedScrollX, cachedScrollY); - performFind(); + executeFind(); } -function performFind() { - findModeQueryHasResults = window.find(findModeQuery, false, false, true, false, true, false); +function executeFind(backwards) { + findModeQueryHasResults = window.find(findModeQuery, false, backwards, true, false, true, false); } -function performBackwardsFind() { - findModeQueryHasResults = window.find(findModeQuery, false, true, true, false, true, false); +function focusFoundLink() { + if (findModeQueryHasResults) { + var link = getLinkFromSelection(); + if (link) + link.focus(); + } +} + +function findAndFocus(backwards) { + executeFind(backwards); + focusFoundLink(); +} + +function performFind() { findAndFocus(); } + +function performBackwardsFind() { findAndFocus(true); } + +function getLinkFromSelection() { + var node = window.getSelection().anchorNode; + while (node.nodeName.toLowerCase() !== 'body') { + if (node.nodeName.toLowerCase() === 'a') return node; + node = node.parentNode; + } + return null; } function findAndFollowLink(linkStrings) { for (i = 0; i < linkStrings.length; i++) { - var findModeQueryHasResults = window.find(linkStrings[i], false, true, true, false, true, false); - if (findModeQueryHasResults) { - var node = window.getSelection().anchorNode; - while (node.nodeName != 'BODY') { - if (node.nodeName == 'A') { - window.location = node.href; - return true; - } - node = node.parentNode; + var hasResults = window.find(linkStrings[i], false, true, true, false, true, false); + if (hasResults) { + var link = getLinkFromSelection(); + if (link) { + window.location = link.href; + return true; } } } + return false; } function findAndFollowRel(value) { @@ -592,13 +634,13 @@ function findAndFollowRel(value) { } function goPrevious() { - var previousPatterns = settings["previousPatterns"] || ""; + var previousPatterns = settings.get("previousPatterns") || ""; var previousStrings = previousPatterns.split(","); findAndFollowRel('prev') || findAndFollowLink(previousStrings); } function goNext() { - var nextPatterns = settings["nextPatterns"] || ""; + var nextPatterns = settings.get("nextPatterns") || ""; var nextStrings = nextPatterns.split(","); findAndFollowRel('next') || findAndFollowLink(nextStrings); } @@ -616,12 +658,11 @@ function showFindModeHUDForQuery() { function insertSpaces(query) { var newQuery = ""; - for (var i = 0; i < query.length; i++) - { + for (var i = 0; i < query.length; i++) { if (query[i] == " " || (i + 1 < query.length && query[i + 1] == " ")) newQuery = newQuery + query[i]; - else - newQuery = newQuery + query[i] + "<span style=\"font-size: 0px;\"> </span>"; + else // ​ is a zero-width space + newQuery = newQuery + query[i] + "<span>​</span>"; } return newQuery; @@ -635,6 +676,7 @@ function enterFindMode() { function exitFindMode() { findMode = false; + focusFoundLink(); HUD.hide(); } @@ -648,13 +690,14 @@ function showHelpDialog(html, fid) { document.body.appendChild(container); container.innerHTML = html; + container.getElementsByClassName("closeButton")[0].addEventListener("click", hideHelpDialog, false); + container.getElementsByClassName("optionsPage")[0].addEventListener("click", + function() { chrome.extension.sendRequest({ handler: "openOptionsPageInNewTab" }); }, false); + // This is necessary because innerHTML does not evaluate javascript embedded in <script> tags. var scripts = Array.prototype.slice.call(container.getElementsByTagName("script")); scripts.forEach(function(script) { eval(script.text); }); - container.getElementsByClassName("closeButton")[0].addEventListener("click", hideHelpDialog, false); - container.getElementsByClassName("optionsPage")[0].addEventListener("click", - function() { chrome.extension.sendRequest({ handler: "openOptionsPageInNewTab" }); }, false); } function hideHelpDialog(clickEvent) { @@ -763,15 +806,6 @@ HUD = { function() { HUD.upgradeNotificationElement().style.display = "none"; }); }, - updatePageZoomLevel: function(pageZoomLevel) { - // Since the chrome HUD does not scale with the page's zoom level, neither will this HUD. - var inverseZoomLevel = (100.0 / pageZoomLevel) * 100; - if (HUD._displayElement) - HUD.displayElement().style.zoom = inverseZoomLevel + "%"; - if (HUD._upgradeNotificationElement) - HUD.upgradeNotificationElement().style.zoom = inverseZoomLevel + "%"; - }, - /* * Retrieves the HUD HTML element. */ @@ -780,7 +814,6 @@ HUD = { HUD._displayElement = HUD.createHudElement(); // Keep this far enough to the right so that it doesn't collide with the "popups blocked" chrome HUD. HUD._displayElement.style.right = "150px"; - HUD.updatePageZoomLevel(currentZoomLevel); } return HUD._displayElement; }, @@ -790,7 +823,6 @@ HUD = { HUD._upgradeNotificationElement = HUD.createHudElement(); // Position this just to the left of our normal HUD. HUD._upgradeNotificationElement.style.right = "315px"; - HUD.updatePageZoomLevel(currentZoomLevel); } return HUD._upgradeNotificationElement; }, |
