]> git.gir.st - VimFx.git/blob - extension/packages/events.coffee
Merge branch 'develop' into proper-modes + Refactor
[VimFx.git] / extension / packages / events.coffee
1 utils = require 'utils'
2 keyUtils = require 'key-utils'
3 { Vim } = require 'vim'
4 { getPref } = require 'prefs'
5 { setWindowBlacklisted } = require 'button'
6 { unload } = require 'unload'
7 { commands } = require 'commands'
8 { modes } = require 'modes'
9
10 { interfaces: Ci } = Components
11
12 newFunc = (window) -> new Vim({window, commands, modes, esc: 'Esc'})
13 vimBucket = new utils.Bucket(utils.getWindowId, newFunc)
14
15 suppressEvent = (event) ->
16 event.preventDefault()
17 event.stopPropagation()
18
19 # *************************
20 # NB! TODO! All this shit needs to be redone!!
21 # *************************
22
23 keyStrFromEvent = (event) ->
24
25 { ctrlKey: ctrl, metaKey: meta, altKey: alt, shiftKey: shift } = event
26
27 if !meta and !alt
28 if keyChar = keyUtils.keyCharFromCode(event.keyCode, shift)
29 keyStr = keyUtils.applyModifiers(keyChar, ctrl, alt, meta)
30
31 return keyStr
32
33 # Passthrough mode is activated when VimFx should temporarily stop processking
34 # keyboard input. For example when a context menu is whown
35 passthrough = false
36
37 logError = (err, eventName) ->
38 console.log("#{ err } (in #{ eventName })\n#{ err.stack.replace(/@.+-> /g, '@') }")
39
40 # The following listeners are installed on every top level Chrome window
41 windowsListener =
42 keydown: (event) ->
43 if passthrough or getPref('disabled')
44 return
45
46 try
47 isEditable = utils.isElementEditable(event.originalTarget)
48
49 keyStr = keyStrFromEvent(event)
50
51 # We only handle the key if it's recognized by `keyCharFromCode`
52 # and if there is no focused editable element or if it's the *Esc* key,
53 # which will remove the focus from the currently focused element
54 if keyStr and (not isEditable or keyStr == 'Esc')
55 if window = utils.getCurrentTabWindow(event)
56 if vim = vimBucket.get(window)
57 if vim.blacklisted
58 return
59
60 if vim.handleKeyDown(event, keyStr)
61 suppressEvent(event)
62
63 # Also blur active element if preferencess allow (for XUL controls)
64 if keyStr == 'Esc' and getPref('blur_on_esc')
65 cb = -> event.originalTarget?.ownerDocument?.activeElement?.blur()
66 window.setTimeout(cb, 0)
67
68 catch err
69 logError(err, 'keydown')
70
71 keypress: (event) ->
72 if passthrough or getPref('disabled')
73 return
74
75 try
76 isEditable = utils.isElementEditable(event.originalTarget)
77
78 # Try to execute keys that were accumulated so far.
79 # Suppress event if there is a matching command.
80 if window = utils.getCurrentTabWindow(event)
81 if vim = vimBucket.get(window)
82 if vim.blacklisted
83 return
84
85 if vim.handleKeyPress(event)
86 suppressEvent(event)
87
88 catch err
89 logError(err, 'keypress')
90
91 keyup: (event) ->
92 if passthrough or getPref('disabled')
93 return
94
95 if window = utils.getCurrentTabWindow event
96 if vim = vimBucket.get(window)
97 if vim.handleKeyUp(event)
98 suppressEvent(event)
99
100 popupshown: (event) ->
101 if event.target.tagName in [ 'menupopup', 'panel' ]
102 passthrough = true
103
104
105 popuphidden: (event) ->
106 if event.target.tagName in [ 'menupopup', 'panel' ]
107 passthrough = false
108
109 # When the top level window closes we should release all Vims that were
110 # associated with tabs in this window
111 DOMWindowClose: (event) ->
112 if gBrowser = event.originalTarget.gBrowser
113 for tab in gBrowser.tabs
114 if browser = gBrowser.getBrowserForTab(tab)
115 vimBucket.forget(browser.contentWindow)
116
117 TabClose: (event) ->
118 if gBrowser = utils.getEventTabBrowser(event)
119 if browser = gBrowser.getBrowserForTab(event.originalTarget)
120 vimBucket.forget(browser.contentWindow)
121
122 # Update the toolbar button icon to reflect the blacklisted state
123 TabSelect: (event) ->
124 if vim = vimBucket.get(event.originalTarget?.linkedBrowser?.contentDocument?.defaultView)
125 if rootWindow = utils.getRootWindow(vim.window)
126 setWindowBlacklisted(rootWindow, vim.blacklisted)
127
128 # This listener works on individual tabs within Chrome Window
129 # User for: listening for location changes and disabling the extension
130 # on black listed urls
131 tabsListener =
132 onLocationChange: (browser, webProgress, request, location) ->
133 blacklisted = utils.isBlacklisted(location.spec, getPref('black_list'))
134 if vim = vimBucket.get(browser.contentWindow)
135 vim.enterNormalMode()
136 vim.blacklisted = blacklisted
137 if rootWindow = utils.getRootWindow(vim.window)
138 setWindowBlacklisted(rootWindow, vim.blacklisted)
139
140 addEventListeners = (window) ->
141 for name, listener of windowsListener
142 window.addEventListener(name, listener, true)
143
144 # Install onLocationChange listener
145 window.gBrowser.addTabsProgressListener(tabsListener)
146
147 removeEventListeners = ->
148 for name, listener of windowsListener
149 window.removeEventListener(name, listener, true)
150
151 unload ->
152 removeEventListeners(window)
153 window.gBrowser.removeTabsProgressListener(tabsListener)
154
155 exports.addEventListeners = addEventListeners
Imprint / Impressum