aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Blott2015-01-08 07:44:53 +0000
committerStephen Blott2015-01-08 09:33:40 +0000
commit5d199e6c786bb2874f7ecb700d505e7b2d70d982 (patch)
treed8160473402140c7045e16bc45499af03f4f3ee8
parent7c886d32cca6c0540a9ec6247eb1617b8f1db86a (diff)
downloadvimium-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.coffee7
-rw-r--r--content_scripts/mode_insert.coffee82
-rw-r--r--content_scripts/vimium_frontend.coffee2
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