diff options
| author | Stephen Blott | 2015-01-08 07:44:53 +0000 |
|---|---|---|
| committer | Stephen Blott | 2015-01-08 09:33:40 +0000 |
| commit | 5d199e6c786bb2874f7ecb700d505e7b2d70d982 (patch) | |
| tree | d8160473402140c7045e16bc45499af03f4f3ee8 | |
| parent | 7c886d32cca6c0540a9ec6247eb1617b8f1db86a (diff) | |
| download | vimium-5d199e6c786bb2874f7ecb700d505e7b2d70d982.tar.bz2 | |
Modes; refactor and simplify.
- Insert mode trigger and blocker.
- Better comments for PostFindMode.
- Better comments for FocusSelector.
- Make insert mode consistent with master.
| -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 |
