Bind keydown on root view to catch events that aren't handled by ace

Also fixed a bug where the GlobalKeymap wasn't returning true when it
matched a binding, which caused key events to be processed twice when
they bubbled out of the editor and hit the root view.
This commit is contained in:
Nathan Sobo
2012-01-10 23:54:14 -08:00
committed by Corey Johnson & Nathan Sobo
parent 7f4120ce36
commit 2a80a72d64
6 changed files with 28 additions and 23 deletions

View File

@@ -161,12 +161,6 @@ describe "Editor", ->
describe "when onTextInput is called on the aceEditor (triggered by an input event)", ->
it "does not call handleKeyEvent on the key event handler, because there is no event", ->
editor.keyEventHandler = handler
editor.aceEditor.onTextInput("x", false)
expect(handler.handleKeyEvent).not.toHaveBeenCalled()

View File

@@ -30,8 +30,9 @@ describe "GlobalKeymap", ->
fragment.on 'insertChar', insertCharHandler
describe "when the event's target node matches a selector with a matching binding", ->
it "triggers the command event associated with that binding on the target node", ->
keymap.handleKeyEvent(keypressEvent('x', target: fragment[0]))
it "triggers the command event associated with that binding on the target node and returns true", ->
result = keymap.handleKeyEvent(keypressEvent('x', target: fragment[0]))
expect(result).toBeTruthy()
expect(deleteCharHandler).toHaveBeenCalled()
expect(insertCharHandler).not.toHaveBeenCalled()
@@ -47,9 +48,10 @@ describe "GlobalKeymap", ->
expect(keymap.handleKeyEvent(keypressEvent('0', target: fragment[0]))).toBe(false)
describe "when the event's target node *descends* from a selector with a matching binding", ->
it "triggers the command event associated with that binding on the target node", ->
it "triggers the command event associated with that binding on the target node and returns true", ->
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keypressEvent('x', target: target))
result = keymap.handleKeyEvent(keypressEvent('x', target: target))
expect(result).toBeTruthy()
expect(deleteCharHandler).toHaveBeenCalled()
expect(insertCharHandler).not.toHaveBeenCalled()

View File

@@ -81,15 +81,24 @@ describe "RootView", ->
rootView.fileFinder.select()
expect(rootView.editor.buffer.url).toBe(project.url + firstLi.text())
describe "when a key is typed in the editor that has a binding in the keymap", ->
it "triggers the key binding's command as an event and does not insert a character", ->
rootView.globalKeymap.bindKeys('.editor', 'x': 'fooCommand')
describe "global keymap wiring", ->
commandHandler = null
beforeEach ->
commandHandler = jasmine.createSpy('commandHandler')
rootView.on('foo-command', commandHandler)
rootView.globalKeymap.bindKeys('*', 'x': 'foo-command')
fooCommandHandler = jasmine.createSpy('fooCommandHandler')
rootView.editor.on('fooCommand', fooCommandHandler)
describe "when a key is typed in the editor that has a binding in the keymap", ->
it "triggers the key binding's command as an event and stops its propagation", ->
event = keydownEvent 'x', target: rootView.find('textarea')[0]
spyOn event, 'stopPropagation'
rootView.editor.aceEditor.onCommandKey event, 0, event.which
expect(commandHandler).toHaveBeenCalled()
expect(event.stopPropagation).toHaveBeenCalled()
event = keydownEvent 'x', target: rootView.find('textarea')[0]
rootView.editor.aceEditor.onCommandKey event, 0, event.which
expect(fooCommandHandler).toHaveBeenCalled()
describe "when a keydown event is triggered on the RootView (not originating from Ace)", ->
it "triggers matching keybindings for that event", ->
event = keydownEvent 'x', target: rootView[0]
rootView.trigger(event)
expect(commandHandler).toHaveBeenCalled()

View File

@@ -38,7 +38,7 @@ class Editor extends Template
@aceEditor.setKeyboardHandler
handleKeyboard: (data, hashId, keyString, keyCode, event) =>
if event and @keyEventHandler?.handleKeyEvent(event)
{command: {exec: ->}}
{ command: { exec: -> }}
else
null

View File

@@ -20,6 +20,6 @@ class GlobalKeymap
for bindingSet in candidateBindingSets
if command = bindingSet.commandForEvent(event)
$(event.target).trigger(command)
return
return true
currentNode = currentNode.parent()
false

View File

@@ -22,7 +22,7 @@ class RootView extends Template
initialize: ({url}) ->
@globalKeymap = new GlobalKeymap
@on 'keydown', (e) => @globalKeymap.handleKeyEvent(e)
@editor.keyEventHandler = @globalKeymap
@globalKeymap.bindKeys '*'
@@ -30,7 +30,7 @@ class RootView extends Template
'meta-w': 'close'
'meta-t': 'toggle-file-finder'
@on 'toggle-file-finder', (e) => @toggleFileFinder()
@on 'toggle-file-finder', => @toggleFileFinder()
if url
@project = new Project(fs.directory(url))