diff options
| author | Jez Ng | 2012-01-12 20:55:28 +0800 |
|---|---|---|
| committer | Jez Ng | 2012-01-13 19:21:51 +0800 |
| commit | febd41a8a044c7c0968e41882490bd1ff6c968b9 (patch) | |
| tree | d5af0fa8961d90445587dbf978cac817c63eee45 /vimiumFrontend.js | |
| parent | 9e14b51f7761fa35acdbf7e5abbb7bc59928a6e2 (diff) | |
| download | vimium-febd41a8a044c7c0968e41882490bd1ff6c968b9.tar.bz2 | |
Enable scrolling for <div> elements.
Partial fix for issue #425.
Diffstat (limited to 'vimiumFrontend.js')
| -rw-r--r-- | vimiumFrontend.js | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/vimiumFrontend.js b/vimiumFrontend.js index 736f14b0..3ae6e6cc 100644 --- a/vimiumFrontend.js +++ b/vimiumFrontend.js @@ -20,6 +20,7 @@ var isEnabledForUrl = true; var currentCompletionKeys; var validFirstKeys; var linkHintCss; +var activatedElement; // 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 @@ -159,6 +160,7 @@ function initializeWhenEnabled() { document.addEventListener("keyup", onKeyup, true); document.addEventListener("focus", onFocusCapturePhase, true); window.addEventListener("blur", onBlurCapturePhase, true); + document.addEventListener("DOMActivate", onDOMActivate, true); enterInsertModeIfElementIsFocused(); } @@ -212,18 +214,67 @@ function enterInsertModeIfElementIsFocused() { enterInsertModeWithoutShowingIndicator(document.activeElement); } +function onDOMActivate(event) { + activatedElement = event.target; +} + +/** + * activatedElement is different from document.activeElement -- the latter seems to be reserved mostly for + * input elements. This mechanism allows us to decide whether to scroll a div or to scroll the whole document. + */ +function scrollActivatedElementBy(x, y) { + if (!activatedElement) { + // if this is called before domReady, just use the window scroll function + if (document.body) + activatedElement = document.body; + else + window.scrollBy(x, y); + } + + // Chrome does not report scrollHeight accurately for nodes with pseudo-elements of height 0 (bug 110149). + // Therefore we just try to increase scrollTop blindly -- if it fails we know we have reached the end of the + // content. + if (y !== 0) { + var element = activatedElement; + do { + var oldScrollTop = element.scrollTop; + element.scrollTop += y; + var lastElement = element; + element = element.parentElement; + } while(lastElement.scrollTop == oldScrollTop && lastElement.nodeName.toLowerCase() != 'body'); + } + + if (x !== 0) { + element = lastElement; + do { + var oldScrollLeft = element.scrollLeft; + element.scrollLeft += x; + var lastElement = element; + element = element.parentElement; + } while(lastElement.scrollLeft == oldScrollLeft && lastElement.nodeName.toLowerCase() != 'body'); + } + + // if the activated element has been scrolled completely offscreen, subsequent changes in its scroll + // position will not provide any more visual feedback to the user. therefore we deactivate it so that + // subsequent scrolls only move the parent element. + var rect = activatedElement.getBoundingClientRect(); + if (rect.top < 0 || rect.top > window.innerHeight || + rect.left < 0 || rect.left > window.innerWidth) + activatedElement = lastElement; +} + 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.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.get("scrollStepSize"), 0); } -function scrollRight() { window.scrollBy(settings.get("scrollStepSize"), 0); } +function scrollUp() { scrollActivatedElementBy(0, -1 * settings.get("scrollStepSize")); } +function scrollDown() { scrollActivatedElementBy(0, settings.get("scrollStepSize")); } +function scrollPageUp() { scrollActivatedElementBy(0, -1 * window.innerHeight / 2); } +function scrollPageDown() { scrollActivatedElementBy(0, window.innerHeight / 2); } +function scrollFullPageUp() { scrollActivatedElementBy(0, -window.innerHeight); } +function scrollFullPageDown() { scrollActivatedElementBy(0, window.innerHeight); } +function scrollLeft() { scrollActivatedElementBy(-1 * settings.get("scrollStepSize"), 0); } +function scrollRight() { scrollActivatedElementBy(settings.get("scrollStepSize"), 0); } function focusInput(count) { var results = utils.evaluateXPath(textInputXPath, XPathResult.ORDERED_NODE_ITERATOR_TYPE); |
