]> git.gir.st - VimFx.git/blob - extension/packages/events.coffee
Merge remote-tracking branch 'upstream/develop' into zh-CN
[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, (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 if passthrough or getPref('disabled')
41 return
42
43 try
44 isEditable = utils.isElementEditable(event.originalTarget)
45
46 keyStr = keyStrFromEvent(event)
47
48 # We only handle the key if it's recognized by `keyCharFromCode`
49 # and if there is no focused editable element or if it's the *Esc* key,
50 # which will remove the focus from the currently focused element
51 if keyStr and (not isEditable or keyStr == 'Esc')
52 if window = utils.getEventCurrentTabWindow(event)
53 if vim = vimBucket.get(window)
54 if vim.blacklisted
55 return
56
57 if vim.handleKeyDown(event, keyStr)
58 suppressEvent(event)
59
60 # Also blur active element if preferencess allow (for XUL controls)
61 if keyStr == 'Esc' and getPref('blur_on_esc')
62 cb = -> event.originalTarget?.ownerDocument?.activeElement?.blur()
63 window.setTimeout(cb, 0)
64
65 catch err
66 logError(err, 'keydown')
67
68 keypress: (event) ->
69 if passthrough or getPref('disabled')
70 return
71
72 try
73 isEditable = utils.isElementEditable(event.originalTarget)
74
75 # Try to execute keys that were accumulated so far.
76 # Suppress event if there is a matching command.
77 if window = utils.getEventCurrentTabWindow(event)
78 if vim = vimBucket.get(window)
79 if vim.blacklisted
80 return
81
82 if vim.handleKeyPress(event)
83 suppressEvent(event)
84
85 catch err
86 logError(err, 'keypress')
87
88 keyup: (event) ->
89 if passthrough or getPref('disabled')
90 return
91
92 if window = utils.getEventCurrentTabWindow(event)
93 if vim = vimBucket.get(window)
94 if vim.handleKeyUp(event)
95 suppressEvent(event)
96
97 popupshown: (event) ->
98 if event.target.tagName in [ 'menupopup', 'panel' ]
99 passthrough = true
100
101
102 popuphidden: (event) ->
103 if event.target.tagName in [ 'menupopup', 'panel' ]
104 passthrough = false
105
106 # When the top level window closes we should release all Vims that were
107 # associated with tabs in this window
108 DOMWindowClose: (event) ->
109 return unless { gBrowser } = event.originalTarget
110 for tab in gBrowser.tabs
111 if browser = gBrowser.getBrowserForTab(tab)
112 vimBucket.forget(browser.contentWindow)
113
114 TabClose: (event) ->
115 return unless { gBrowser } = utils.getEventRootWindow(event) ? {}
116 return unless browser = gBrowser.getBrowserForTab(event.originalTarget)
117 vimBucket.forget(browser.contentWindow)
118
119 # Update the toolbar button icon to reflect the blacklisted state
120 TabSelect: (event) ->
121 return unless vim = vimBucket.get(event.originalTarget?.linkedBrowser?.contentDocument?.defaultView)
122 return unless rootWindow = utils.getRootWindow(vim.window)
123 updateToolbarButton(rootWindow, {blacklisted: vim.blacklisted})
124
125 # This listener works on individual tabs within Chrome Window
126 # User for: listening for location changes and disabling the extension
127 # on black listed urls
128 tabsListener =
129 onLocationChange: (browser, webProgress, request, location) ->
130 return unless vim = vimBucket.get(browser.contentWindow)
131
132 vim.enterNormalMode()
133
134 return unless rootWindow = utils.getRootWindow(vim.window)
135 vim.blacklisted = utils.isBlacklisted(location.spec)
136 updateToolbarButton(rootWindow, {blacklisted: vim.blacklisted})
137
138 addEventListeners = (window) ->
139 for name, listener of windowsListener
140 window.addEventListener(name, listener, true)
141
142 # Install onLocationChange listener
143 window.gBrowser.addTabsProgressListener(tabsListener)
144
145 removeEventListeners = ->
146 for name, listener of windowsListener
147 window.removeEventListener(name, listener, true)
148
149 unload ->
150 removeEventListeners(window)
151 window.gBrowser.removeTabsProgressListener(tabsListener)
152
153 exports.addEventListeners = addEventListeners
Imprint / Impressum