aboutsummaryrefslogtreecommitdiffstats
path: root/content_scripts/mode_insert.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'content_scripts/mode_insert.coffee')
-rw-r--r--content_scripts/mode_insert.coffee69
1 files changed, 52 insertions, 17 deletions
diff --git a/content_scripts/mode_insert.coffee b/content_scripts/mode_insert.coffee
index 678e35cc..4be9c589 100644
--- a/content_scripts/mode_insert.coffee
+++ b/content_scripts/mode_insert.coffee
@@ -3,32 +3,67 @@ class InsertMode extends Mode
constructor: (options = {}) ->
defaults =
name: "insert"
- exitOnEscape: true
- keydown: (event) => @handler event
- keypress: (event) => @handler event
- keyup: (event) => @handler event
+ keydown: (event) => @handleKeydownEvent event
+ keypress: (event) => @handleKeyEvent event
+ keyup: (event) => @handleKeyEvent event
super extend defaults, options
+ @insertModeLock = if options.targetElement? then options.targetElement else null
@push
- "blur": => @exit()
+ "blur": => @alwaysContinueBubbling =>
+ if DomUtils.isFocusable event.target
+ @exit event.target
+ Mode.updateBadge()
+ "focus": (event) => @alwaysContinueBubbling =>
+ @insertModeLock = event.target if DomUtils.isFocusable event.target
- active: ->
- document.activeElement and DomUtils.isFocusable document.activeElement
+ if @insertModeLock == null
+ # We may already have focused an input element, so check.
+ @insertModeLock = event.target if document.activeElement and DomUtils.isFocusable document.activeElement
- handler: (event) ->
- if @active() then @stopBubblingAndTrue else @continueBubbling
+ isActive: ->
+ return true if @insertModeLock != null
+ # Some sites (e.g. inbox.google.com) change the contentEditable property on the fly (see #1245); and
+ # unfortunately, the focus event fires *before* the change. Therefore, we need to re-check whether the
+ # active element is contentEditable.
+ @insertModeLock = document.activeElement if document.activeElement?.isContentEditable
+ @insertModeLock != null
- exit: () ->
- document.activeElement.blur() if @active()
- if @options.permanentInsertMode
- # We don't really exit if we're permanently installed.
- Mode.updateBadge()
- else
- super()
+ handleKeydownEvent: (event) ->
+ return @continueBubbling if event == InsertMode.suppressedEvent or not @isActive()
+ return @stopBubblingAndTrue unless KeyboardUtils.isEscape event
+ DomUtils.suppressKeyupAfterEscape handlerStack
+ if DomUtils.isFocusable event.srcElement
+ # Remove 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() etc. 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.
+ event.srcElement.blur()
+ @exit()
+ Mode.updateBadge()
+ @suppressEvent
+
+ # Handles keypress and keyup events.
+ handleKeyEvent: (event) ->
+ if @isActive() and event != InsertMode.suppressedEvent then @stopBubblingAndTrue else @continueBubbling
+
+ exit: (target) ->
+ if target == undefined or target == @insertModeLock
+ if @options.targetElement?
+ super()
+ else
+ # If @options.targetElement isn't set, then this is the permanently-installed instance from the front
+ # end. So, we don't actually exit; instead, we just reset ourselves.
+ @insertModeLock = null
chooseBadge: (badge) ->
- badge.badge ||= "I" if @active()
+ badge.badge ||= "I" if @isActive()
+
+ # Static stuff to allow PostFindMode to suppress insert mode.
+ @suppressedEvent: null
+ @suppressEvent: (event) -> @suppressedEvent = event
root = exports ? window
root.InsertMode = InsertMode