diff options
Diffstat (limited to 'content_scripts')
| -rw-r--r-- | content_scripts/mode_find.coffee | 7 | ||||
| -rw-r--r-- | content_scripts/mode_insert.coffee | 82 | ||||
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 2 | 
3 files changed, 47 insertions, 44 deletions
diff --git a/content_scripts/mode_find.coffee b/content_scripts/mode_find.coffee index 837606f3..2ef74a89 100644 --- a/content_scripts/mode_find.coffee +++ b/content_scripts/mode_find.coffee @@ -1,7 +1,7 @@  # 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 three special cases: +# special considerations apply.  We implement 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. Prevent all keyboard events on the active element from propagating.  This is achieved by setting the @@ -16,12 +16,15 @@ class PostFindMode extends InsertModeBlocker      super        name: "post-find" +      # Be a singleton.  That way, we don't have to keep track of any currently-active instance.  Such  an +      # instance is automatically deactivated when a new instance is created.        singleton: PostFindMode        trapAllKeyboardEvents: element      return @exit() unless element and findModeAnchorNode -    # Special cases only arise if the active element can take input.  So, exit immediately if it cannot. +    # Special considerations 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 diff --git a/content_scripts/mode_insert.coffee b/content_scripts/mode_insert.coffee index b80a78ee..41d82add 100644 --- a/content_scripts/mode_insert.coffee +++ b/content_scripts/mode_insert.coffee @@ -17,34 +17,7 @@ isEmbed =(element) ->  isFocusable =(element) ->    isEditable(element) or isEmbed element -# This mode is installed when insert mode is active. -class InsertMode extends Mode -  constructor: (@insertModeLock = null) -> -    super -      name: "insert" -      badge: "I" -      keydown: (event) => @stopBubblingAndTrue -      keypress: (event) => @stopBubblingAndTrue -      keyup: (event) => @stopBubblingAndTrue -      singleton: InsertMode -      exitOnEscape: true -      exitOnBlur: @insertModeLock - -  exit: (event = null) -> -    super() -    if @insertModeLock and event?.srcElement == @insertModeLock -      if isFocusable @insertModeLock -        # Remove the focus so the user can't just get himself back into insert mode by typing in the same -        # input box. -        # NOTE(smblott, 2014/12/22) Including embeds for .blur() here is experimental.  It appears to be the -        # right thing to do for most common use cases.  However, it could also cripple flash-based sites and -        # games.  See discussion in #1211 and #1194. -        @insertModeLock.blur() - -  # Static method. Check whether insert mode is currently active. -  @isActive: (extra) -> extra?.insertModeIsActive - -# Trigger insert mode: +# Automatically trigger insert mode:  #   - On a keydown event in a contentEditable element.  #   - When a focusable element receives the focus.  # @@ -53,8 +26,8 @@ class InsertModeTrigger extends Mode    constructor: ->      super        name: "insert-trigger" -      keydown: (event, extra) => -        return @continueBubbling if InsertModeTrigger.isDisabled extra +      keydown: (event) => +        return @continueBubbling if InsertModeTrigger.isSuppressed()          # Some sites (e.g. inbox.google.com) change the contentEditable attribute on the fly (see #1245);          # and unfortunately, the focus event happens *before* the change is made.  Therefore, we need to          # check again whether the active element is contentEditable. @@ -63,31 +36,56 @@ class InsertModeTrigger extends Mode          @stopBubblingAndTrue      @push -      focus: (event, extra) => +      focus: (event) =>          @alwaysContinueBubbling => -          return @continueBubbling if InsertModeTrigger.isDisabled extra +          return @continueBubbling if InsertModeTrigger.isSuppressed()            return if not isFocusable event.target            new InsertMode event.target      # We may already have focussed an input, so check.      new InsertMode document.activeElement if document.activeElement and isEditable document.activeElement -  # Allow other modes to disable this trigger. Static. -  @disable: (extra) -> extra.disableInsertModeTrigger = true -  @isDisabled: (extra) -> extra?.disableInsertModeTrigger +  # Allow other modes (notably InsertModeBlocker, below) to suppress this trigger. All static. +  @suppressors: 0 +  @isSuppressed: -> 0 < @suppressors +  @suppress: -> @suppressors += 1 +  @unsuppress: -> @suppressors -= 1 -# Disables InsertModeTrigger.  This is used by find mode and by findFocus to prevent unintentionally dropping -# into insert mode on focusable elements. +# Suppresses InsertModeTrigger.  This is used by various modes (usually by inheritance) to prevent +# unintentionally dropping into insert mode on focusable elements.  class InsertModeBlocker extends Mode    constructor: (options = {}) -> +    InsertModeTrigger.suppress()      options.name ||= "insert-blocker"      super options -    @push -      "focus": (event, extra) => @alwaysContinueBubbling -> InsertModeTrigger.disable extra -      "keydown": (event, extra) => @alwaysContinueBubbling -> InsertModeTrigger.disable extra -      "keypress": (event, extra) => @alwaysContinueBubbling -> InsertModeTrigger.disable extra -      "keyup": (event, extra) => @alwaysContinueBubbling -> InsertModeTrigger.disable extra +  exit: -> +    super() +    InsertModeTrigger.unsuppress() + +# This mode is installed when insert mode is active. +class InsertMode extends Mode +  constructor: (@insertModeLock = null) -> +    super +      name: "insert" +      badge: "I" +      singleton: InsertMode +      keydown: (event) => @stopBubblingAndTrue +      keypress: (event) => @stopBubblingAndTrue +      keyup: (event) => @stopBubblingAndTrue +      exitOnEscape: true +      exitOnBlur: @insertModeLock + +  exit: (event = null) -> +    super() +    element = event?.srcElement +    if element and isFocusable element +      # Remove the focus so the user can't just get himself back into insert mode by typing in the same +      # input box. +      # NOTE(smblott, 2014/12/22) Including embeds for .blur() here is experimental.  It appears to be the +      # right thing to do for most common use cases.  However, it could also cripple flash-based sites and +      # games.  See discussion in #1211 and #1194. +      element.blur()  root = exports ? window  root.InsertMode = InsertMode diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 07b4fe4b..e8248c0a 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -380,6 +380,8 @@ extend window,          super            name: "focus-selector"            badge: "?" +          # Be a singleton.  It doesn't make any sense to have two instances active at the same time; and that +          # shouldn't happen anyway.  However, it does no harm to enforce it.            singleton: FocusSelector            keydown: (event) =>              if event.keyCode == KeyboardUtils.keyCodes.tab  | 
