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