]> git.gir.st - VimFx.git/blob - extension/packages/events.coffee
Factor out normal mode into modes.coffee
[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 # Not suppressing Esc allows for stopping the loading of the page as well as closing many custom
11 # dialogs (and perhaps other things -- Esc is a very commonly used key). There are two reasons we
12 # might suppress it in other modes. If some custom dialog of a website is open, we should be able to
13 # cancel hint markers on it without closing it. Secondly, otherwise cancelling hint markers on
14 # google causes its search bar to be focused.
15
16 newFunc = (window) -> new Vim(window)
17 vimBucket = new utils.Bucket(utils.getWindowId, newFunc)
18
19 keyStrFromEvent = (event) ->
20 { ctrlKey: ctrl, metaKey: meta, altKey: alt, shiftKey: shift } = event
21
22 if !meta and !alt
23 return unless keyChar = keyUtils.keyCharFromCode(event.keyCode, shift)
24 keyStr = keyUtils.applyModifiers(keyChar, ctrl, alt, meta)
25 return keyStr
26
27 return null
28
29 # Passthrough mode is activated when VimFx should temporarily stop processing keyboard input, for
30 # example when a menu is shown.
31 passthrough = false
32 checkPassthrough = (event) ->
33 if event.target.nodeName in ['menupopup', 'panel']
34 passthrough = switch event.type
35 when 'popupshown' then true
36 when 'popuphidden' then false
37
38 suppress = false
39 keyListener = (event) ->
40 try
41 return if passthrough or getPref('disabled')
42 return unless window = utils.getEventCurrentTabWindow(event)
43 return unless vim = vimBucket.get(window)
44 return if vim.blacklisted
45
46 if event.type == 'keydown'
47 suppress = false
48
49 return unless keyStr = keyStrFromEvent(event)
50
51 # This check must be done before `vim.onInput()` below, since that call might change the mode.
52 # We are interested in the mode at the beginning of the events, not whatever it might be
53 # afterwards.
54 isEditable = utils.isElementEditable(event.originalTarget)
55
56 suppress = vim.onInput(keyStr, event, {autoInsertMode: isEditable})
57
58 if suppress
59 event.preventDefault()
60 event.stopPropagation()
61
62 catch error
63 console.log("#{ error } (in #{ event.type })\n#{ error.stack.replace(/@.+-> /g, '@') }")
64
65 removeVimFromTab = (tab, gBrowser) ->
66 return unless browser = gBrowser.getBrowserForTab(tab)
67 vimBucket.forget(browser.contentWindow)
68
69 updateButton = (vim) ->
70 return unless rootWindow = utils.getRootWindow(vim.window)
71 updateToolbarButton(rootWindow, {blacklisted: vim.blacklisted, insertMode: vim.mode == 'insert'})
72
73 # The following listeners are installed on every top level Chrome window
74 windowsListeners =
75 keydown: keyListener
76 keypress: keyListener
77 keyup: keyListener
78 popupshown: checkPassthrough
79 popuphidden: checkPassthrough
80
81 # When the top level window closes we should release all Vims that were
82 # associated with tabs in this window
83 DOMWindowClose: (event) ->
84 return unless { gBrowser } = event.originalTarget
85 for tab in gBrowser.tabs
86 removeVimFromTab(tab, gBrowser)
87
88 TabClose: (event) ->
89 return unless { gBrowser } = utils.getEventRootWindow(event) ? {}
90 tab = event.originalTarget
91 removeVimFromTab(tab, gBrowser)
92
93 # Update the toolbar button icon to reflect the blacklisted state
94 TabSelect: (event) ->
95 return unless window = event.originalTarget?.linkedBrowser?.contentDocument?.defaultView
96 return unless vim = vimBucket.get(window)
97 updateButton(vim)
98
99 # This listener works on individual tabs within Chrome Window
100 tabsListener =
101 # Listenfor location changes and disable the extension on blacklisted urls
102 onLocationChange: (browser, webProgress, request, location) ->
103 return unless vim = vimBucket.get(browser.contentWindow)
104
105 # If the location changes when in hints mode (for example because the reload button has been
106 # clicked), we're going to end up in hints mode without any markers. So switch back to normal
107 # mode in that case.
108 if vim.mode == 'hints'
109 vim.enterMode('normal')
110
111 vim.blacklisted = utils.isBlacklisted(location.spec)
112 updateButton(vim)
113
114 addEventListeners = (window) ->
115 for name, listener of windowsListeners
116 window.addEventListener(name, listener, true)
117
118 window.gBrowser.addTabsProgressListener(tabsListener)
119
120 unload ->
121 for name, listener of windowsListeners
122 window.removeEventListener(name, listener, true)
123
124 window.gBrowser.removeTabsProgressListener(tabsListener)
125
126 exports.addEventListeners = addEventListeners
Imprint / Impressum