diff options
| author | Stephen Blott | 2015-01-20 06:38:02 +0000 |
|---|---|---|
| committer | Stephen Blott | 2015-01-20 06:38:02 +0000 |
| commit | 9fa664167b5aaf99069ba9298646a39853eeb067 (patch) | |
| tree | c84864502656862d4c0bd41bd5da8c6bdf06c5de | |
| parent | e8bc7c66521ac83b1396fadee32252f71b3375db (diff) | |
| parent | 7450e1cfc57231457c894d372774c391bf13ac68 (diff) | |
| download | vimium-9fa664167b5aaf99069ba9298646a39853eeb067.tar.bz2 | |
Merge pull request #1438 from smblott-github/focus-input-with-memory
Give focusInput (gi) a memory
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 131 | ||||
| -rw-r--r-- | tests/dom_tests/dom_tests.coffee | 6 |
2 files changed, 79 insertions, 58 deletions
diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index fdd36ab9..725d8a53 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -331,65 +331,80 @@ extend window, enterVisualMode: => new VisualMode() - focusInput: (count) -> - # Focus the first input element on the page, and create overlays to highlight all the input elements, with - # the currently-focused element highlighted specially. Tabbing will shift focus to the next input element. - # Pressing any other key will remove the overlays and the special tab behavior. - resultSet = DomUtils.evaluateXPath(textInputXPath, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE) - visibleInputs = - for i in [0...resultSet.snapshotLength] by 1 - element = resultSet.snapshotItem(i) - rect = DomUtils.getVisibleClientRect(element) - continue if rect == null - { element: element, rect: rect } - - return if visibleInputs.length == 0 - - selectedInputIndex = Math.min(count - 1, visibleInputs.length - 1) - - hints = for tuple in visibleInputs - hint = document.createElement("div") - hint.className = "vimiumReset internalVimiumInputHint vimiumInputHint" - - # minus 1 for the border - hint.style.left = (tuple.rect.left - 1) + window.scrollX + "px" - hint.style.top = (tuple.rect.top - 1) + window.scrollY + "px" - hint.style.width = tuple.rect.width + "px" - hint.style.height = tuple.rect.height + "px" - - hint - - new class FocusSelector extends Mode - constructor: -> - super - name: "focus-selector" - badge: "?" - # We share a singleton with PostFindMode. That way, a new FocusSelector displaces any existing - # PostFindMode. - singleton: PostFindMode - exitOnClick: true - keydown: (event) => - if event.keyCode == KeyboardUtils.keyCodes.tab - hints[selectedInputIndex].classList.remove 'internalVimiumSelectedInputHint' - selectedInputIndex += hints.length + (if event.shiftKey then -1 else 1) - selectedInputIndex %= hints.length - hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint' - visibleInputs[selectedInputIndex].element.focus() - @suppressEvent - else unless event.keyCode == KeyboardUtils.keyCodes.shiftKey - @exit() - @continueBubbling - - @onExit -> DomUtils.removeElement hintContainingDiv - hintContainingDiv = DomUtils.addElementList hints, - id: "vimiumInputMarkerContainer" - className: "vimiumReset" - - visibleInputs[selectedInputIndex].element.focus() - if visibleInputs.length == 1 - @exit() + focusInput: do -> + # Track the most recently focused input element. + recentlyFocusedElement = null + handlerStack.push + _name: "focus-input-tracker" + focus: (event) -> + recentlyFocusedElement = event.target if DomUtils.isEditable event.target + true + + (count) -> + # Focus the first input element on the page, and create overlays to highlight all the input elements, with + # the currently-focused element highlighted specially. Tabbing will shift focus to the next input element. + # Pressing any other key will remove the overlays and the special tab behavior. + resultSet = DomUtils.evaluateXPath textInputXPath, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE + visibleInputs = + for i in [0...resultSet.snapshotLength] by 1 + element = resultSet.snapshotItem i + rect = DomUtils.getVisibleClientRect element + continue if rect == null + { element: element, rect: rect } + + return if visibleInputs.length == 0 + + selectedInputIndex = + if count == 1 + # As the starting index, we pick that of the most recently focused input element (or 0). + elements = visibleInputs.map (visibleInput) -> visibleInput.element + Math.max 0, elements.indexOf recentlyFocusedElement else - hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint' + Math.min(count, visibleInputs.length) - 1 + + hints = for tuple in visibleInputs + hint = document.createElement "div" + hint.className = "vimiumReset internalVimiumInputHint vimiumInputHint" + + # minus 1 for the border + hint.style.left = (tuple.rect.left - 1) + window.scrollX + "px" + hint.style.top = (tuple.rect.top - 1) + window.scrollY + "px" + hint.style.width = tuple.rect.width + "px" + hint.style.height = tuple.rect.height + "px" + + hint + + new class FocusSelector extends Mode + constructor: -> + super + name: "focus-selector" + badge: "?" + # We share a singleton with PostFindMode. That way, a new FocusSelector displaces any existing + # PostFindMode. + singleton: PostFindMode + exitOnClick: true + keydown: (event) => + if event.keyCode == KeyboardUtils.keyCodes.tab + hints[selectedInputIndex].classList.remove 'internalVimiumSelectedInputHint' + selectedInputIndex += hints.length + (if event.shiftKey then -1 else 1) + selectedInputIndex %= hints.length + hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint' + visibleInputs[selectedInputIndex].element.focus() + @suppressEvent + else unless event.keyCode == KeyboardUtils.keyCodes.shiftKey + @exit() + @continueBubbling + + @onExit -> DomUtils.removeElement hintContainingDiv + hintContainingDiv = DomUtils.addElementList hints, + id: "vimiumInputMarkerContainer" + className: "vimiumReset" + + visibleInputs[selectedInputIndex].element.focus() + if visibleInputs.length == 1 + @exit() + else + hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint' # Decide whether this keyChar should be passed to the underlying page. # Keystrokes are *never* considered passKeys if the keyQueue is not empty. So, for example, if 't' is a diff --git a/tests/dom_tests/dom_tests.coffee b/tests/dom_tests/dom_tests.coffee index 33177c59..a4713a72 100644 --- a/tests/dom_tests/dom_tests.coffee +++ b/tests/dom_tests/dom_tests.coffee @@ -207,6 +207,12 @@ context "Input focus", handlerStack.bubbleEvent 'focus', target: document. activeElement assert.isTrue InsertMode.permanentInstance.isActive() + should "select the previously-focused input when count is 1", -> + focusInput 100 + handlerStack.bubbleEvent 'focus', target: document. activeElement + focusInput 1 + assert.equal "third", document.activeElement.id + # TODO: these find prev/next link tests could be refactored into unit tests which invoke a function which has # a tighter contract than goNext(), since they test minor aspects of goNext()'s link matching behavior, and we # don't need to construct external state many times over just to test that. |
