]> git.gir.st - VimFx.git/blob - extension/packages/events.coffee
Re-implement popup passthrough more robustly
[VimFx.git] / extension / packages / events.coffee
1 utils = require 'utils'
2 keyUtils = require 'key-utils'
3 { Vim } = require 'vim'
4 { getPref } = require 'prefs'
5 { updateToolbarButton } = require 'button'
6 { unload } = require 'unload'
7
8 { interfaces: Ci } = Components
9
10 vimBucket = new utils.Bucket(utils.getWindowId, (w) -> new Vim(w))
11
12 keyStrFromEvent = (event) ->
13 { ctrlKey: ctrl, metaKey: meta, altKey: alt, shiftKey: shift } = event
14
15 if !meta and !alt
16 return unless keyChar = keyUtils.keyCharFromCode(event.keyCode, shift)
17 keyStr = keyUtils.applyModifiers(keyChar, ctrl, alt, meta)
18 return keyStr
19
20 return null
21
22 suppress = false
23 suppressEvent = (event) ->
24 if suppress
25 event.preventDefault()
26 event.stopPropagation()
27
28 removeVimFromTab = (tab, gBrowser) ->
29 return unless browser = gBrowser.getBrowserForTab(tab)
30 vimBucket.forget(browser.contentWindow)
31
32 updateButton = (vim) ->
33 return unless rootWindow = utils.getRootWindow(vim.window)
34 updateToolbarButton(rootWindow, {blacklisted: vim.blacklisted, insertMode: vim.mode == 'insert'})
35
36 # The following listeners are installed on every top level Chrome window
37 windowsListeners =
38 keydown: (event) ->
39 try
40 # No matter what, always reset the `suppress` flag, so we don't suppress more than intended.
41 suppress = false
42
43 return if getPref('disabled')
44
45 return unless rootWindow = utils.getEventRootWindow(event)
46 popups = rootWindow.document.querySelectorAll('menupopup, panel')
47 for popup in popups
48 return if popup.state == 'open'
49
50 return unless window = utils.getEventCurrentTabWindow(event)
51 return unless vim = vimBucket.get(window)
52
53 return if vim.blacklisted
54
55 return unless keyStr = keyStrFromEvent(event)
56 suppress = vim.onInput(keyStr, event)
57
58 suppressEvent(event)
59
60 catch error
61 console.error("#{ error }\n#{ error.stack.replace(/@.+-> /g, '@') }")
62
63 # Note that the below event listeners can suppress the event even in blacklisted sites. That's
64 # intentional. For example, if you press 'x' to close the current tab, it will close before keyup
65 # fires. So keyup (and perhaps keypress) will fire in another tab. Even if that particular tab is
66 # blacklisted, we must suppress the event, so that 'x' isn't sent to the page. The rule is simple:
67 # If the `suppress` flag is `true`, the event should be suppressed, no matter what. It has the
68 # highest priority.
69 keypress: suppressEvent
70 keyup: suppressEvent
71
72 # When the top level window closes we should release all Vims that were
73 # associated with tabs in this window
74 DOMWindowClose: (event) ->
75 return unless { gBrowser } = event.originalTarget
76 for tab in gBrowser.tabs
77 removeVimFromTab(tab, gBrowser)
78
79 TabClose: (event) ->
80 return unless { gBrowser } = utils.getEventRootWindow(event) ? {}
81 tab = event.originalTarget
82 removeVimFromTab(tab, gBrowser)
83
84 # Update the toolbar button icon to reflect the blacklisted state
85 TabSelect: (event) ->
86 return unless window = event.originalTarget?.linkedBrowser?.contentDocument?.defaultView
87 return unless vim = vimBucket.get(window)
88 updateButton(vim)
89
90 # This listener works on individual tabs within Chrome Window
91 tabsListener =
92 # Listenfor location changes and disable the extension on blacklisted urls
93 onLocationChange: (browser, webProgress, request, location) ->
94 return unless vim = vimBucket.get(browser.contentWindow)
95
96 # If the location changes when in hints mode (for example because the reload button has been
97 # clicked), we're going to end up in hints mode without any markers. So switch back to normal
98 # mode in that case.
99 if vim.mode == 'hints'
100 vim.enterMode('normal')
101
102 vim.blacklisted = utils.isBlacklisted(location.spec)
103 updateButton(vim)
104
105 addEventListeners = (window) ->
106 for name, listener of windowsListeners
107 window.addEventListener(name, listener, true)
108
109 window.gBrowser.addTabsProgressListener(tabsListener)
110
111 unload ->
112 for name, listener of windowsListeners
113 window.removeEventListener(name, listener, true)
114
115 window.gBrowser.removeTabsProgressListener(tabsListener)
116
117 exports.addEventListeners = addEventListeners
118 exports.vimBucket = vimBucket
Imprint / Impressum