diff options
| -rw-r--r-- | content_scripts/link_hints.coffee | 105 | ||||
| -rw-r--r-- | content_scripts/mode.coffee | 12 | ||||
| -rw-r--r-- | content_scripts/mode_insert.coffee | 2 | ||||
| -rw-r--r-- | content_scripts/mode_visual_edit.coffee | 4 | ||||
| -rw-r--r-- | lib/dom_utils.coffee | 5 | ||||
| -rw-r--r-- | lib/handler_stack.coffee | 2 | ||||
| -rw-r--r-- | pages/options.coffee | 2 | ||||
| -rw-r--r-- | tests/unit_tests/handler_stack_test.coffee | 2 |
8 files changed, 51 insertions, 83 deletions
diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index c8f9b6f9..57fec611 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -43,8 +43,6 @@ class LinkHintsMode mode: undefined # Function that does the appropriate action on the selected link. linkActivator: undefined - # Lock to ensure only one instance runs at a time. - isActive: false # The link-hints "mode" (in the key-handler, indicator sense). hintMode: null # Call this function on exit (if defined). @@ -55,7 +53,6 @@ class LinkHintsMode constructor: (mode = OPEN_IN_CURRENT_TAB, onExit = (->)) -> # we need documentElement to be ready in order to append links return unless document.documentElement - @isActive = true elements = @getVisibleClickableElements() # For these modes, we filter out those elements which don't have an HREF (since there's nothing we can do @@ -88,7 +85,7 @@ class LinkHintsMode keypress: @onKeyPressInMode.bind this, hintMarkers @hintMode.onExit => - @deactivateMode() if @isActive + @deactivateMode() @hintMode.onExit onExit @setOpenLinkMode mode @@ -322,7 +319,7 @@ class LinkHintsMode keyup: (event) => if event.keyCode == keyCode handlerStack.remove() - @setOpenLinkMode previousMode if @isActive + @setOpenLinkMode previousMode true # Continue bubbling the event. # For some (unknown) reason, we don't always receive the keyup event needed to remove this handler. @@ -364,12 +361,11 @@ class LinkHintsMode DomUtils.suppressEvent event updateVisibleMarkers: (hintMarkers, tabCount = 0) -> - keyResult = @markerMatcher.getMatchingHints hintMarkers, tabCount - linksMatched = keyResult.linksMatched + {linksMatched, userMightOverType} = @markerMatcher.getMatchingHints hintMarkers, tabCount if linksMatched.length == 0 @deactivateMode() else if linksMatched.length == 1 - @activateLink linksMatched[0], keyResult.delay ? 0, keyResult.waitForEnter and Settings.get "waitForEnterForFilteredHints" + @activateLink linksMatched[0], userMightOverType ? false else @hideMarker marker for marker in hintMarkers @showMarker matched, @markerMatcher.hintKeystrokeQueue.length for matched in linksMatched @@ -377,26 +373,30 @@ class LinkHintsMode # # When only one link hint remains, this function activates it in the appropriate way. # - activateLink: (@matchedLink, delay = 0, waitForEnter = false) -> - clickEl = @matchedLink.clickableItem - if (DomUtils.isSelectable(clickEl)) - DomUtils.simulateSelect(clickEl) - @deactivateMode delay - else - # TODO figure out which other input elements should not receive focus - if (clickEl.nodeName.toLowerCase() == "input" and clickEl.type not in ["button", "submit"]) - clickEl.focus() + activateLink: (linkMatched, userMightOverType=false) -> + @removeHintMarkers() + clickEl = linkMatched.clickableItem - linkActivator = => - @linkActivator(clickEl) + linkActivator = => + @deactivateMode() + if DomUtils.isSelectable clickEl + DomUtils.simulateSelect clickEl + else + # TODO: Are there any other input elements which should not receive focus? + if clickEl.nodeName.toLowerCase() == "input" and clickEl.type not in ["button", "submit"] + clickEl.focus() + @linkActivator clickEl LinkHints.activateModeWithQueue() if @mode is OPEN_WITH_QUEUE - if waitForEnter - new WaitForEnter @matchedLink.rect, => @deactivateMode 0, linkActivator - else - @deactivateMode delay, => - DomUtils.flashRect @matchedLink.rect - linkActivator() + if userMightOverType and Settings.get "waitForEnterForFilteredHints" + new WaitForEnter linkMatched.rect, linkActivator + else if userMightOverType + # Block keyboard events while the user is still typing. The intention is to prevent the user from + # inadvertently launching Vimium commands when (over-)typing the link text. + new TypingProtector 200, linkMatched.rect, linkActivator + else + DomUtils.flashRect linkMatched.rect + linkActivator() # # Shows the marker, highlighting matchingCharCount characters. @@ -411,27 +411,14 @@ class LinkHintsMode hideMarker: (linkMarker) -> linkMarker.style.display = "none" - deactivateMode: (delay = 0, callback = null) -> - deactivate = => - DomUtils.removeElement @hintMarkerContainingDiv if @hintMarkerContainingDiv - @hintMarkerContainingDiv = null - @markerMatcher = null - @isActive = false - @hintMode?.exit() - @hintMode = null - @onExit?() - @onExit = null - @tabCount = 0 - callback?() - - if delay - # Install a mode to block keyboard events if the user is still typing. The intention is to prevent the - # user from inadvertently launching Vimium commands when typing the link text. - new TypingProtector delay, @matchedLink?.rect, deactivate - else - # We invoke deactivate() directly (instead of setting a timeout of 0) so that deactivateMode() can be - # tested synchronously. - deactivate() + deactivateMode: -> + @removeHintMarkers() + @hintMode?.exit() + @onExit?() + + removeHintMarkers: -> + DomUtils.removeElement @hintMarkerContainingDiv if @hintMarkerContainingDiv + @hintMarkerContainingDiv = null # Use characters for hints, and do not filter links by their text. class AlphabetHints @@ -556,19 +543,12 @@ class FilterHints @filterLinkHints hintMarkers getMatchingHints: (hintMarkers, tabCount = 0) -> - delay = 0 - # At this point, linkTextKeystrokeQueue and hintKeystrokeQueue have been updated to reflect the latest # input. use them to filter the link hints accordingly. matchString = @hintKeystrokeQueue.join "" linksMatched = @filterLinkHints hintMarkers linksMatched = linksMatched.filter (linkMarker) -> linkMarker.hintString.startsWith matchString - if linksMatched.length == 1 && @hintKeystrokeQueue.length == 0 and 0 < @linkTextKeystrokeQueue.length - # In filter mode, people tend to type out words past the point needed for a unique match. Hence we - # should avoid passing control back to command mode immediately after a match is found. - delay = 200 - # Visually highlight of the active hint (that is, the one that will be activated if the user # types <Enter>). tabCount = ((linksMatched.length * Math.abs tabCount) + tabCount) % linksMatched.length @@ -576,7 +556,8 @@ class FilterHints @activeHintMarker = linksMatched[tabCount] @activeHintMarker?.classList.add "vimiumActiveHintMarker" - { linksMatched: linksMatched, delay: delay, waitForEnter: 0 < delay } + linksMatched: linksMatched + userMightOverType: @hintKeystrokeQueue.length == 0 and 0 < @linkTextKeystrokeQueue.length pushKeyChar: (keyChar, keydownKeyChar) -> # For filtered hints, we *always* use the keyChar value from keypress, because there is no obvious and @@ -652,24 +633,22 @@ class TypingProtector extends Mode constructor: (delay, rect, callback) -> @timer = Utils.setTimeout delay, => @exit() - handler = (event) => + resetExitTimer = (event) => clearTimeout @timer @timer = Utils.setTimeout delay, => @exit() super name: "hint/typing-protector" suppressAllKeyboardEvents: true - keydown: handler - keypress: handler - - if rect - # We keep a "flash" overlay active while the user is typing; this provides visual feeback that something - # has been selected. - flashEl = DomUtils.addFlashRect rect - @onExit -> DomUtils.removeElement flashEl + keydown: resetExitTimer + keypress: resetExitTimer @onExit callback + # We keep a "flash" overlay active while the user is typing; this provides visual feeback that something + # has been selected. + flashEl = DomUtils.addFlashRect rect + @onExit -> DomUtils.removeElement flashEl class WaitForEnter extends Mode constructor: (rect, callback) -> diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index 5cc8800e..454a6ed9 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -117,7 +117,7 @@ class Mode key = Utils.getIdentity @options.singleton @onExit -> delete singletons[key] @deactivateSingleton @options.singleton - singletons[key] = @ + singletons[key] = this # If @options.trackState is truthy, then the mode mainatins the current state in @enabled and @passKeys, # and calls @registerStateChange() (if defined) whenever the state changes. The mode also tracks the @@ -164,7 +164,7 @@ class Mode keypress: handler keyup: -> handlerStack.stopBubblingAndFalse - Mode.modes.push @ + Mode.modes.push this @setIndicator() @logModes() # End of Mode constructor. @@ -194,7 +194,7 @@ class Mode @modeIsExiting = true handler args... for handler in @exitHandlers handlerStack.remove handlerId for handlerId in @handlers - Mode.modes = Mode.modes.filter (mode) => mode != @ + Mode.modes = Mode.modes.filter (mode) => mode != this @modeIsActive = false @setIndicator() @@ -213,12 +213,6 @@ class Mode DomUtils.suppressPropagation event @stopBubblingAndFalse - # Activate a new instance of this mode, together with all of its original options (except its main - # keybaord-event handlers; these will be recreated). - cloneMode: -> - delete @options[key] for key in [ "keydown", "keypress", "keyup" ] - new @constructor @options - # Debugging routines. logModes: -> if @debug diff --git a/content_scripts/mode_insert.coffee b/content_scripts/mode_insert.coffee index 9037b05a..f86038d6 100644 --- a/content_scripts/mode_insert.coffee +++ b/content_scripts/mode_insert.coffee @@ -77,7 +77,7 @@ class InsertMode extends Mode shadowRoot.removeEventListener type, listener, true # Only for tests. This gives us a hook to test the status of the permanently-installed instance. - InsertMode.permanentInstance = @ if @permanent + InsertMode.permanentInstance = this if @permanent isActive: (event) -> return false if event == InsertMode.suppressedEvent diff --git a/content_scripts/mode_visual_edit.coffee b/content_scripts/mode_visual_edit.coffee index ae8897ca..cca305f8 100644 --- a/content_scripts/mode_visual_edit.coffee +++ b/content_scripts/mode_visual_edit.coffee @@ -274,7 +274,7 @@ class Movement extends CountPrefix handleMovementKeyChar: (keyChar, count = 1) -> switch typeof @movements[keyChar] when "string" then @runMovement @movements[keyChar] for [0...count] - when "function" then @movements[keyChar].call @, count + when "function" then @movements[keyChar].call this, count @scrollIntoView() constructor: (options) -> @@ -307,7 +307,7 @@ class Movement extends CountPrefix return @continueBubbling if command == "0" and 0 < @countPrefix.length if @commands[command] - @commands[command].call @, @getCountPrefix() + @commands[command].call this, @getCountPrefix() @scrollIntoView() return @suppressEvent diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 553287af..aab0a4df 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -290,11 +290,6 @@ DomUtils = @remove() false - simulateTextEntry: (element, text) -> - event = document.createEvent "TextEvent" - event.initTextEvent "textInput", true, true, null, text - element.dispatchEvent event - # Adapted from: http://roysharon.com/blog/37. # This finds the element containing the selection focus. getElementWithFocus: (selection, backwards) -> diff --git a/lib/handler_stack.coffee b/lib/handler_stack.coffee index c07d028b..bb0f19a6 100644 --- a/lib/handler_stack.coffee +++ b/lib/handler_stack.coffee @@ -45,7 +45,7 @@ class HandlerStack # A handler may have been removed (handler.id == null), so check. if handler?.id and handler[type] @currentId = handler.id - result = handler[type].call @, event + result = handler[type].call this, event @logResult eventNumber, type, event, handler, result if @debug if not result DomUtils.suppressEvent event if @isChromeEvent event diff --git a/pages/options.coffee b/pages/options.coffee index 51400740..a82c3807 100644 --- a/pages/options.coffee +++ b/pages/options.coffee @@ -21,7 +21,7 @@ class Option @element = $(@field) @element.addEventListener "change", @onUpdated @fetch() - Option.all.push @ + Option.all.push this # Fetch a setting from localStorage, remember the @previous value and populate the DOM element. # Return the fetched value. diff --git a/tests/unit_tests/handler_stack_test.coffee b/tests/unit_tests/handler_stack_test.coffee index 0ed85e63..629fc3ed 100644 --- a/tests/unit_tests/handler_stack_test.coffee +++ b/tests/unit_tests/handler_stack_test.coffee @@ -63,7 +63,7 @@ context "handlerStack", assert.isFalse @handler1Called should "handle self-removing handlers correctly", -> - ctx = @ + ctx = this @handlerStack.push { keydown: => @handler1Called = true } @handlerStack.push { keydown: -> ctx.handler2Called = true |
