diff options
| author | Stephen Blott | 2015-01-09 18:12:58 +0000 |
|---|---|---|
| committer | Stephen Blott | 2015-01-09 18:12:58 +0000 |
| commit | e2380ff9417834900649173750edf17a26a8b703 (patch) | |
| tree | 639d28c4074f539c3cb1af0ba25e3d22bb7ad683 | |
| parent | 8e65f74eea14850794ded12a0039a80e825ffa8d (diff) | |
| download | vimium-e2380ff9417834900649173750edf17a26a8b703.tar.bz2 | |
Modes; block unmapped keys with contentEditable.
| -rw-r--r-- | content_scripts/mode_insert.coffee | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/content_scripts/mode_insert.coffee b/content_scripts/mode_insert.coffee index 5375bcdc..cbeea48f 100644 --- a/content_scripts/mode_insert.coffee +++ b/content_scripts/mode_insert.coffee @@ -15,8 +15,10 @@ class InsertMode extends Mode options = extend defaults, options options.exitOnBlur = options.targetElement || null super options + triggerSuppressor.suppress() exit: (event = null) -> + triggerSuppressor.unsuppress() super() if @options.blurOnExit element = event?.srcElement @@ -44,7 +46,6 @@ class InsertModeTrigger extends Mode # and unfortunately, the focus event happens *before* the change is made. Therefore, we need to # check again whether the active element is contentEditable. return @continueBubbling unless document.activeElement?.isContentEditable - console.log @count, @name, "fired (by keydown)" new InsertMode targetElement: document.activeElement @stopBubblingAndTrue @@ -53,7 +54,6 @@ class InsertModeTrigger extends Mode focus: (event) => triggerSuppressor.unlessSuppressed => return unless DomUtils.isFocusable event.target - console.log @count, @name, "fired (by focus)" new InsertMode targetElement: event.target @@ -89,6 +89,36 @@ class InsertModeBlocker extends Mode new @options.onClickMode targetElement: document.activeElement +# There's some unfortunate feature interaction with chrome's content editable handling. If the selection is +# content editable and a descendant of the active element, then chrome focuses it on any unsuppressed keyboard +# events. This has the unfortunate effect of dropping us unintentally into insert mode. See #1415. +# This mode sits near the bottom of the handler stack and suppresses keyboard events if: +# - they haven't been handled by any other mode (so not by normal mode, passkeys mode, insert mode, and so +# on), and +# - the selection is content editable, and +# - the selection is a descendant of the active element. +# This should rarely fire, typically only on fudged keypresses in normal mode. And, even then, only in the +# circumstances outlined above. So it shouldn't normally block other extensions or the page itself from +# handling keyboard events. +new class ContentEditableTrap extends Mode + constructor: -> + super + name: "content-editable-trap" + keydown: (event) => @handle => DomUtils.suppressPropagation event + keypress: (event) => @handle => @suppressEvent + keyup: (event) => @handle => @suppressEvent + + # True if the selection is content editable and a descendant of the active element. In this situation, + # chrome unilaterally focuses the element containing the anchor, dropping us into insert mode. + isContentEditableFocused: -> + element = document.getSelection()?.anchorNode?.parentElement + return element?.isContentEditable? and + document.activeElement? and + DomUtils.isDOMDescendant document.activeElement, element + + handle: (func) -> + if @isContentEditableFocused() then func() else @continueBubbling + root = exports ? window root.InsertMode = InsertMode root.InsertModeTrigger = InsertModeTrigger |
