aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content_scripts/mode.coffee18
-rw-r--r--content_scripts/mode_find.coffee22
-rw-r--r--content_scripts/vimium_frontend.coffee12
-rw-r--r--lib/handler_stack.coffee12
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