]> git.gir.st - VimFx.git/blob - extension/lib/events-frame.coffee
Merge pull request #512 from akhodakivskiy/multi-process
[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 HTMLInputElement = Ci.nsIDOMHTMLInputElement
26
27 class FrameEventManager
28 constructor: (@vim) ->
29
30 listen: utils.listen.bind(null, FRAME_SCRIPT_ENVIRONMENT)
31
32 addListeners: ->
33 @listen('DOMWindowCreated', @vim.resetState.bind(@vim))
34
35 @listen('keydown', (event) =>
36 @vim.onInput(event)
37 )
38
39 @listen('overflow', (event) =>
40 return unless computedStyle = @vim.content.getComputedStyle(event.target)
41 return if computedStyle.getPropertyValue('overflow') == 'hidden'
42 @vim.state.scrollableElements.add(event.target)
43 )
44
45 @listen('underflow', (event) =>
46 @vim.state.scrollableElements.delete(event.target)
47 )
48
49 @listen('focus', (event) =>
50 target = event.originalTarget
51
52 options = @vim.options(['prevent_autofocus', 'prevent_autofocus_modes',
53 'autofocus_limit'])
54
55 if utils.isTextInputElement(target)
56 @vim.state.lastFocusedTextInput = target
57
58 # If the user has interacted with the page and the `window` of the page
59 # gets focus, it means that the user just switched back to the page from
60 # another window or tab. If a text input was focused when the user focused
61 # _away_ from the page Firefox blurs it and then re-focuses it when the
62 # user switches back. Therefore we count this case as an interaction, so
63 # the re-focus event isn’t caught as autofocus.
64 if @vim.state.lastInteraction != null and target == @vim.content
65 @vim.state.lastInteraction = Date.now()
66
67 # Autofocus prevention. Strictly speaking, autofocus may only happen
68 # during page load, which means that we should only prevent focus events
69 # during page load. However, it is very difficult to reliably determine
70 # when the page load ends. Moreover, a page may load very slowly. Then it
71 # is likely that the user tries to focus something before the page has
72 # loaded fully. Therefore focus events that aren’t reasonably close to a
73 # user interaction (click or key press) are blurred (regardless of whether
74 # the page is loaded or not -- but that isn’t so bad: if the user doesn’t
75 # like autofocus, he doesn’t like any automatic focusing, right? This is
76 # actually useful on devdocs.io). There is a slight risk that the user
77 # presses a key just before an autofocus, causing it not to be blurred,
78 # but that’s not likely. Autofocus prevention is also restricted to
79 # `<input>` elements, since only such elements are commonly autofocused.
80 # Many sites have buttons which inserts a `<textarea>` when clicked (which
81 # might take up to a second) and then focuses the `<textarea>`. Such focus
82 # events should _not_ be blurred. There are also many buttons that do the
83 # same thing but insert an `<input>` element. There is sadly always a risk
84 # that those events are blurred.
85 focusManager = Cc['@mozilla.org/focus-manager;1']
86 .getService(Ci.nsIFocusManager)
87 if options.prevent_autofocus and
88 @vim.mode in options.prevent_autofocus_modes and
89 target instanceof HTMLInputElement and
90 # Only blur programmatic events (not caused by clicks or keypresses).
91 focusManager.getLastFocusMethod(null) == 0 and
92 (@vim.state.lastInteraction == null or
93 Date.now() - @vim.state.lastInteraction > options.autofocus_limit)
94 @vim.state.lastAutofocusPrevention = Date.now()
95 target.blur()
96 )
97
98 # Save the time of the last user interaction. This is used to determine
99 # whether a focus event was automatic or voluntarily dispatched.
100 markLastInteraction = (event) =>
101 @vim.state.lastInteraction = Date.now()
102
103 @listen('mousedown', markLastInteraction)
104 @listen('mouseup', markLastInteraction)
105 messageManager.listen('keydown', markLastInteraction)
106
107 @listen('blur', (event) =>
108 # Some sites (such as icloud.com) re-focuses inputs if they are blurred,
109 # causing an infinite loop autofocus prevention and re-focusing. Therefore
110 # we suppress blur events that happen just after an autofocus prevention.
111 if @vim.state.lastAutofocusPrevention != null and
112 Date.now() - @vim.state.lastAutofocusPrevention < 1
113 @vim.state.lastAutofocusPrevention = null
114 utils.suppressEvent(event)
115 )
116
117 @listen('click', (event) =>
118 if @vim.mode == 'hints' and event.isTrusted
119 messageManager.send('enterMode', {mode: 'normal'})
120 )
121
122 module.exports = FrameEventManager
Imprint / Impressum