diff options
| -rw-r--r-- | content_scripts/link_hints.coffee | 2 | ||||
| -rw-r--r-- | content_scripts/mode.coffee | 7 | ||||
| -rw-r--r-- | content_scripts/mode_find.coffee | 5 | ||||
| -rw-r--r-- | content_scripts/mode_insert.coffee | 105 | ||||
| -rw-r--r-- | content_scripts/mode_visual.coffee | 2 | ||||
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 19 | 
6 files changed, 29 insertions, 111 deletions
diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 0668e3ae..b0feea8c 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -66,7 +66,7 @@ LinkHints =        { id: "vimiumHintMarkerContainer", className: "vimiumReset" })      @handlerMode = -      new class HintMode extends InsertModeBlocker +      new class HintMode extends Mode          constructor: ->            super              name: "hint/#{mode.name}" diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index 84b76301..98d3df80 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -191,13 +191,6 @@ class Mode            handler: "setBadge"            badge: badge.badge -  # Temporarily install a mode to protect a function call, then exit the mode.  For example, temporarily -  # install an InsertModeBlocker, so that focus events don't unintentionally drop us into insert mode. -  @runIn: (mode, func) -> -    mode = new mode() -    func() -    mode.exit() -    registerSingleton: do ->      singletons = {} # Static.      (key) -> diff --git a/content_scripts/mode_find.coffee b/content_scripts/mode_find.coffee index 519e99ad..bf6e7f5b 100644 --- a/content_scripts/mode_find.coffee +++ b/content_scripts/mode_find.coffee @@ -2,14 +2,13 @@  # When we use find mode, the selection/focus can end up in a focusable/editable element.  In this situation,  # special considerations apply.  We implement three special cases: -#   1. Prevent keyboard events from dropping us unintentionally into insert mode. This is achieved by -#      inheriting from InsertModeBlocker. +#   1. Prevent keyboard events from dropping us unintentionally into insert mode. This is achieved by...  #   2. Prevent all printable keypress events on the active element from propagating.  This is achieved by setting the  #      suppressPrintableEvents 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.  #   3. If the very-next keystroke is Escape, then drop immediately into insert mode.  # -class PostFindMode extends InsertModeBlocker +class PostFindMode extends Mode    constructor: (findModeAnchorNode) ->      element = document.activeElement      initialSelection = window.getSelection().toString() diff --git a/content_scripts/mode_insert.coffee b/content_scripts/mode_insert.coffee index dd0c8d16..678e35cc 100644 --- a/content_scripts/mode_insert.coffee +++ b/content_scripts/mode_insert.coffee @@ -1,105 +1,34 @@ -# This mode is installed only when insert mode is active.  It is a singleton, so a newly-activated instance -# displaces any active instance.  class InsertMode extends Mode    constructor: (options = {}) ->      defaults =        name: "insert" -      badge: "I" -      singleton: InsertMode -      keydown: (event) => @stopBubblingAndTrue -      keypress: (event) => @stopBubblingAndTrue -      keyup: (event) => @stopBubblingAndTrue        exitOnEscape: true -      blurOnExit: true -      targetElement: null +      keydown: (event) => @handler event +      keypress: (event) => @handler event +      keyup: (event) => @handler event -    # If options.targetElement blurs, we exit. -    options.exitOnBlur ||= options.targetElement      super extend defaults, options -    triggerSuppressor.suppress() - -  exit: (event = null) -> -    triggerSuppressor.unsuppress() -    super() -    if @options.blurOnExit -      element = event?.srcElement -      if element and DomUtils.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() - -# Automatically trigger insert mode: -#   - On a keydown event in a contentEditable element. -#   - When a focusable element receives the focus. -# -# The trigger can be suppressed via triggerSuppressor; see InsertModeBlocker, below.  This mode is permanently -# installed (just above normal mode and passkeys mode) on the handler stack. -class InsertModeTrigger extends Mode -  constructor: -> -    super -      name: "insert-trigger" -      keydown: (event) => -        triggerSuppressor.unlessSuppressed => -          # 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 (on every keydown) whether the active element is contentEditable. -          return @continueBubbling unless document.activeElement?.isContentEditable -          new InsertMode -            targetElement: document.activeElement -          @stopBubblingAndTrue      @push -      _name: "mode-#{@id}/activate-on-focus" -      focus: (event) => -        triggerSuppressor.unlessSuppressed => -          @alwaysContinueBubbling => -            if DomUtils.isFocusable event.target -              new InsertMode -                targetElement: event.target +      "blur": => @exit() -    # We may have already focussed an input element, so check. -    if document.activeElement and DomUtils.isEditable document.activeElement -      new InsertMode -        targetElement: document.activeElement +  active: -> +    document.activeElement and DomUtils.isFocusable document.activeElement -# Used by InsertModeBlocker to suppress InsertModeTrigger; see below. -triggerSuppressor = new Utils.Suppressor true # Note: true == @continueBubbling +  handler: (event) -> +    if @active() then @stopBubblingAndTrue else @continueBubbling -# Suppresses InsertModeTrigger.  This is used by various modes (usually via inheritance) to prevent -# unintentionally dropping into insert mode on focusable elements. -class InsertModeBlocker extends Mode -  constructor: (options = {}) -> -    defaults = -      name: "insert-blocker" -      # The user knows best; so, if the user clicks on something, the insert-mode blocker gets out of the way. -      exitOnClick: true -      onClickMode: InsertMode -    super extend defaults, options -    triggerSuppressor.suppress() - -    @push -      _name: "mode-#{@id}/bail-on-click" -      "click": (event) => -        @alwaysContinueBubbling => -          # The user knows best; so, if the user clicks on something, the insert-mode blocker gets out of the -          # way. +  exit: () -> +    document.activeElement.blur() if @active() +    if @options.permanentInsertMode +      # We don't really exit if we're permanently installed. +      Mode.updateBadge() +    else +      super() -  exit: -> -    super() -    # If the element associated with the event is focusable, then, had we not been blocking the trigger, we -    # would already have been in insert mode.  Now, a click on that element will not generate a new focus -    # event, so the insert-mode trigger will not fire.  We have to handle this case specially. -    # @options.onClickMode specifies the mode to use (by default, insert mode). -    if @clickEvent?.target? and DomUtils.isFocusable @clickEvent.target -      new @options.onClickMode -        targetElement: event.target -    triggerSuppressor.unsuppress() +  chooseBadge: (badge) -> +    badge.badge ||= "I" if @active()  root = exports ? window  root.InsertMode = InsertMode -root.InsertModeTrigger = InsertModeTrigger -root.InsertModeBlocker = InsertModeBlocker diff --git a/content_scripts/mode_visual.coffee b/content_scripts/mode_visual.coffee index 7b5cc0f6..2580106d 100644 --- a/content_scripts/mode_visual.coffee +++ b/content_scripts/mode_visual.coffee @@ -1,5 +1,5 @@ -class VisualMode extends InsertModeBlocker +class VisualMode extends Mode    constructor: (element=null) ->      super        name: "visual" diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 09e19486..f2e0cb2a 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -123,17 +123,12 @@ initializePreDomReady = ->    settings.addEventListener("load", LinkHints.init.bind(LinkHints))    settings.load() -  # Install normal mode. This is near the bottom of the handler stack, and is never deactivated. +  # Install permanent modes and handlers.    new NormalMode() - -  # Initialize the scroller. The scroller installs a key handler, and this is next on the handler stack, -  # immediately above normal mode.    Scroller.init settings - -  # Install passKeys mode and the insert-mode trigger.  These too are permanently on the stack.    passKeysMode = new PassKeysMode() -  new InsertModeTrigger() -  Mode.updateBadge() +  new InsertMode +    permanentInsertMode: true    checkIfEnabledForUrl() @@ -375,7 +370,7 @@ extend window,        id: "vimiumInputMarkerContainer"        className: "vimiumReset" -    new class FocusSelector extends InsertModeBlocker +    new class FocusSelector extends Mode        constructor: ->          super            name: "focus-selector" @@ -767,7 +762,7 @@ handleEnterForFindMode = ->    document.body.classList.add("vimiumFindMode")    settings.set("findModeRawQuery", findModeQuery.rawQuery) -class FindMode extends InsertModeBlocker +class FindMode extends Mode    constructor: ->      super        name: "find" @@ -828,8 +823,10 @@ executeFind = (query, options) ->    HUD.hide(true)    # ignore the selectionchange event generated by find()    document.removeEventListener("selectionchange",restoreDefaultSelectionHighlight, true) -  Mode.runIn InsertModeBlocker, -> +  handlerId = handlerStack.push +    focus: -> handlerStack.stopBubblingAndTrue      result = window.find(query, options.caseSensitive, options.backwards, true, false, true, false) +  handlerStack.remove    setTimeout(      -> document.addEventListener("selectionchange", restoreDefaultSelectionHighlight, true)      0)  | 
