aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Blott2015-01-20 06:38:02 +0000
committerStephen Blott2015-01-20 06:38:02 +0000
commit9fa664167b5aaf99069ba9298646a39853eeb067 (patch)
treec84864502656862d4c0bd41bd5da8c6bdf06c5de
parente8bc7c66521ac83b1396fadee32252f71b3375db (diff)
parent7450e1cfc57231457c894d372774c391bf13ac68 (diff)
downloadvimium-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.coffee131
-rw-r--r--tests/dom_tests/dom_tests.coffee6
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.