diff options
| author | Stephen Blott | 2015-01-18 21:39:00 +0000 | 
|---|---|---|
| committer | Stephen Blott | 2015-01-18 21:39:00 +0000 | 
| commit | 9d7185b78b366abafe52faeb18ec039b242e02b9 (patch) | |
| tree | 374318338309ee4de62e3e0ce1e49f5f4eabcc4a | |
| parent | 7ed25b7a757a0b3d8d8cf14c60fd8e0e0d237835 (diff) | |
| download | vimium-9d7185b78b366abafe52faeb18ec039b242e02b9.tar.bz2 | |
Give focusInput a memory (fix typo).
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 145 | ||||
| -rw-r--r-- | tests/dom_tests/dom_tests.coffee | 13 | 
2 files changed, 70 insertions, 88 deletions
diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 27e813c9..6cc686d2 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -331,84 +331,77 @@ extend window,    enterVisualMode: =>      new VisualMode() -# Track the most-recently focused input element. This is used by focusInput to decide which input to initially -# highlight. -getFocusedElementIndexByRecency = do -> -  focusedElement = null -  installListener window, "focus", (event) -> -    focusedElement = event.target if DomUtils.isEditable event.target - -  # Only for tests. -  window.resetFocusInputFocusedElement = -> +  focusInput: do -> +    # Track the most-recently focused input element.      focusedElement = null - -  (elements) -> -    Math.max 0, elements.indexOf focusedElement - -extend window, -  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 = -      if count == 1 -        getFocusedElementIndexByRecency visibleInputs.map (visibleInput) -> visibleInput.element -      else -        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() +    handlerStack.push +      focus: (event) -> +        focusedElement = event.target if DomUtils.isEditable event.target + +    (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 +          elements = visibleInputs.map (visibleInput) -> visibleInput.element +          Math.max 0, elements.indexOf focusedElement          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 f67ebc88..a4713a72 100644 --- a/tests/dom_tests/dom_tests.coffee +++ b/tests/dom_tests/dom_tests.coffee @@ -184,12 +184,10 @@ context "Input focus",        <input type='password' id='third' value='some value'/>"      document.getElementById("test-div").innerHTML = testContent      backupStackState() -    resetFocusInputFocusedElement()    tearDown ->      document.getElementById("test-div").innerHTML = ""      restoreStackState() -    resetFocusInputFocusedElement()    should "focus the right element", ->      focusInput 1 @@ -204,25 +202,16 @@ context "Input focus",      focusInput 1      handlerStack.bubbleEvent 'focus', target: document.activeElement      assert.isTrue InsertMode.permanentInstance.isActive() -    # deactivate the tabbing mode and its overlays -    handlerStack.bubbleEvent 'keydown', mockKeyboardEvent("A")      focusInput 100      handlerStack.bubbleEvent 'focus', target: document. activeElement      assert.isTrue InsertMode.permanentInstance.isActive() -    # deactivate the tabbing mode and its overlays -    handlerStack.bubbleEvent 'keydown', mockKeyboardEvent("A")    should "select the previously-focused input when count is 1", ->      focusInput 100 -    assert.equal "third", document.activeElement.id -    # deactivate the tabbing mode and its overlays -    handlerStack.bubbleEvent 'keydown', mockKeyboardEvent("A") - +    handlerStack.bubbleEvent 'focus', target: document. activeElement      focusInput 1      assert.equal "third", document.activeElement.id -    # deactivate the tabbing mode and its overlays -    handlerStack.bubbleEvent 'keydown', mockKeyboardEvent("A")  # 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  | 
