diff options
| -rw-r--r-- | content_scripts/mode.coffee | 18 | ||||
| -rw-r--r-- | content_scripts/mode_find.coffee | 22 | ||||
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 12 | ||||
| -rw-r--r-- | lib/handler_stack.coffee | 12 |
4 files changed, 41 insertions, 23 deletions
diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index 92285b8c..160debc4 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -102,12 +102,27 @@ class Mode @passKeys = passKeys @registerStateChange?() + # If options.trapAllKeyboardEvents is truthy, then it should be an element. All keyboard events on that + # element are suppressed *after* bubbling the event down the handler stack. This prevents such events + # from propagating to other extensions or the host page. + if options.trapAllKeyboardEvents + @unshift + keydown: (event) => @alwaysContinueBubbling -> + DomUtils.suppressPropagation event if event.srcElement == options.trapAllKeyboardEvents + keypress: (event) => @alwaysContinueBubbling -> + DomUtils.suppressEvent event if event.srcElement == options.trapAllKeyboardEvents + keyup: (event) => @alwaysContinueBubbling -> + DomUtils.suppressPropagation event if event.srcElement == options.trapAllKeyboardEvents + Mode.updateBadge() if @badge # End of Mode.constructor(). push: (handlers) -> @handlers.push handlerStack.push handlers + unshift: (handlers) -> + @handlers.unshift handlerStack.push handlers + onExit: (handler) -> @exitHandlers.push handler @@ -124,7 +139,8 @@ class Mode chooseBadge: (badge) -> badge.badge ||= @badge - # Shorthand for a long name. + # Shorthand for an otherwise long name. This allow us to write handlers which always yield the same value, + # without having to be concerned with the result of the handler itself. alwaysContinueBubbling: (func) -> handlerStack.alwaysContinueBubbling func # Static method. Used externally and internally to initiate bubbling of an updateBadge event and to send diff --git a/content_scripts/mode_find.coffee b/content_scripts/mode_find.coffee index f9766e3a..837606f3 100644 --- a/content_scripts/mode_find.coffee +++ b/content_scripts/mode_find.coffee @@ -1,26 +1,33 @@ # NOTE(smblott). Ultimately, all of the FindMode-related code should be moved to this file. # When we use find mode, the selection/focus can end up in a focusable/editable element. In this situation, -# PostFindMode handles two special cases: -# 1. Be an InsertModeBlocker. This prevents keyboard events from dropping us unintentionaly into insert +# PostFindMode handles three special cases: +# 1. Be an InsertModeBlocker. This prevents keyboard events from dropping us unintentionally into insert # mode. This is achieved by inheriting from InsertModeBlocker. -# 2. If the very-next keystroke is Escape, then drop immediately into insert mode. +# 2. Prevent all keyboard events on the active element from propagating. This is achieved by setting the +# trapAllKeyboardEvents option. There's some controversy as to whether this is the right thing to do. +# See discussion in #1415. This implements option 2 from there, although option 3 would be a reasonable +# alternative. +# 3. If the very-next keystroke is Escape, then drop immediately into insert mode. # class PostFindMode extends InsertModeBlocker constructor: (findModeAnchorNode) -> + element = document.activeElement + super name: "post-find" singleton: PostFindMode + trapAllKeyboardEvents: element - element = document.activeElement return @exit() unless element and findModeAnchorNode - # Special cases only arise if the active element can take input. So, exit immediately if it cannot not. + # Special cases only arise if the active element can take input. So, exit immediately if it cannot. canTakeInput = DomUtils.isSelectable(element) and DomUtils.isDOMDescendant findModeAnchorNode, element canTakeInput ||= element.isContentEditable canTakeInput ||= findModeAnchorNode.parentElement?.isContentEditable return @exit() unless canTakeInput + self = @ @push keydown: (event) -> if element == document.activeElement and KeyboardUtils.isEscape event @@ -38,10 +45,11 @@ class PostFindMode extends InsertModeBlocker keydown: (event) => @alwaysContinueBubbling => @exit() if document.activeElement != element # If element is selectable, then it's already focused. If the user clicks on it, then there's no new - # focus event, so InsertModeTrigger doesn't fire and we don't drop automatically into insert mode. + # focus event, so InsertModeTrigger doesn't fire and we don't drop automatically into insert mode. So + # we have to handle this case separately. click: (event) => @alwaysContinueBubbling => - new InsertMode event.target if DomUtils.isDOMDescendant element, event.target + new InsertMode element if DomUtils.isDOMDescendant element, event.target @exit() root = exports ? window diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 3f36a5cd..07b4fe4b 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -465,12 +465,6 @@ onKeypress = (event, extra) -> keyPort.postMessage({ keyChar:keyChar, frameId:frameId }) - if InsertModeTrigger.isDisabled extra - # If PostFindMode is active, then we're blocking vimium's keystrokes from going into an input - # element. So we should also block other keystrokes (otherwise, it's weird). There's some controversy as - # to whether this is the right thing to do. See discussion in #1415. - DomUtils.suppressEvent(event) - return true onKeydown = (event, extra) -> @@ -564,12 +558,6 @@ onKeydown = (event, extra) -> isValidFirstKey(KeyboardUtils.getKeyChar(event)))) DomUtils.suppressPropagation(event) KeydownEvents.push event - else if InsertModeTrigger.isDisabled extra - # If PostFindMode is active, then we're blocking vimium's keystrokes from going into an input - # element. So we should also block other keystrokes (otherwise, it's weird). There's some controversy as - # to whether this is the right thing to do. See discussion in #1415. - DomUtils.suppressPropagation(event) - KeydownEvents.push event return true diff --git a/lib/handler_stack.coffee b/lib/handler_stack.coffee index 4d186341..718bee9d 100644 --- a/lib/handler_stack.coffee +++ b/lib/handler_stack.coffee @@ -14,11 +14,17 @@ class HandlerStack # processing should take place. @stopBubblingAndFalse = new Object() - # Adds a handler to the stack. Returns a unique ID for that handler that can be used to remove it later. + # Adds a handler to the top of the stack. Returns a unique ID for that handler that can be used to remove it + # later. push: (handler) -> - handler.id = ++@counter @stack.push handler - handler.id + handler.id = ++@counter + + # Adds a handler to the bottom of the stack. Returns a unique ID for that handler that can be used to remove + # it later. + unshift: (handler) -> + @stack.unshift handler + handler.id = ++@counter # Called whenever we receive a key or other event. Each individual handler has the option to stop the # event's propagation by returning a falsy value, or stop bubbling by returning @stopBubblingAndFalse or |
