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