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 | 
