]> git.gir.st - VimFx.git/blob - extension/lib/events-frame.coffee
Re-work autofocus prevention
[VimFx.git] / extension / lib / events-frame.coffee
1 ###
2 # Copyright Simon Lydell 2015.
3 #
4 # This file is part of VimFx.
5 #
6 # VimFx is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # VimFx is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
18 ###
19
20 # This file is the equivalent to events.coffee, but for frame scripts.
21
22 messageManager = require('./message-manager')
23 utils = require('./utils')
24
25 class FrameEventManager
26 constructor: (@vim) ->
27
28 listen: utils.listen.bind(null, FRAME_SCRIPT_ENVIRONMENT)
29 listenOnce: utils.listenOnce.bind(null, FRAME_SCRIPT_ENVIRONMENT)
30
31 addListeners: ->
32 @listen('DOMWindowCreated', @vim.resetState.bind(@vim))
33
34 @listen('keydown', (event) =>
35 suppress = @vim.onInput(event)
36 # If the event wasn’t suppressed, it’s on obvious interaction with the
37 # page. If it _was_ suppressed, though, it’s an interaction depending on
38 # the command triggered; if it calls `vim.markPageInteraction()` or not.
39 @vim.markPageInteraction() unless suppress
40 )
41
42 @listen('overflow', (event) =>
43 return unless computedStyle = @vim.content.getComputedStyle(event.target)
44 return if computedStyle.getPropertyValue('overflow') == 'hidden'
45 @vim.state.scrollableElements.add(event.target)
46 )
47
48 @listen('underflow', (event) =>
49 @vim.state.scrollableElements.delete(event.target)
50 )
51
52 @listen('focus', (event) =>
53 target = event.originalTarget
54
55 options = @vim.options(['prevent_autofocus', 'prevent_autofocus_modes'])
56
57 if utils.isTextInputElement(target)
58 @vim.state.lastFocusedTextInput = target
59
60 # Autofocus prevention. Strictly speaking, autofocus may only happen
61 # during page load, which means that we should only prevent focus events
62 # during page load. However, it is very difficult to reliably determine
63 # when the page load ends. Moreover, a page may load very slowly. Then it
64 # is likely that the user tries to focus something before the page has
65 # loaded fully. Therefore any and all focus events that fire before the
66 # user has interacted with the page (clicked or pressed a key) are blurred
67 # (regardless of whether the page is loaded or not).
68 focusManager = Cc['@mozilla.org/focus-manager;1']
69 .getService(Ci.nsIFocusManager)
70 if options.prevent_autofocus and not @vim.state.hasInteraction and
71 @vim.mode in options.prevent_autofocus_modes and
72 # Only blur programmatic events (not caused by clicks or keypresses).
73 focusManager.getLastFocusMethod(null) == 0 and
74 # Only blur elements that may steal most keystrokes.
75 (utils.isTextInputElement(target) or utils.isContentEditable(target))
76 # Some sites (such as icloud.com) re-focuses inputs if they are blurred,
77 # causing an infinite loop of autofocus prevention and re-focusing.
78 # Therefore we suppress blur events that happen just after an autofocus
79 # prevention.
80 @listenOnce('blur', utils.suppressEvent)
81 target.blur()
82 )
83
84 @listen('mousedown', (event) => @vim.markPageInteraction())
85
86 @listen('click', (event) =>
87 if @vim.mode == 'hints' and event.isTrusted
88 messageManager.send('enterMode', {mode: 'normal'})
89 )
90
91 module.exports = FrameEventManager
Imprint / Impressum