mirror of
https://github.com/atom/atom.git
synced 2026-01-23 22:08:08 -05:00
RootView can no longer be focused.
Allowing root view to be focused was stealing focus away from the editor whenever a click event made it to the root view. This unnecessary switching of focus was interfering with the ability to drag tabs. But if RootView can't be focused, focus ends up being returned to the document body when there are no focusable elements. This would be fine, except for the fact that we frequently bind global events on root view, and so they aren't triggered when events are triggered on the body. We could just bind all global events on the body, but this would require us to always attach elements to the DOM during specs, which is a serious performance killer in specs. The workaround is in the keymap. When the keymap handles a key event that was triggered on the body, it triggers the corresponding semantic event on the root view anyway, so from the event perspective, it's as if the root view actually had focus. The only place this might fall down is if someone wants to capture raw key events. But that's the keymap's job anyway, and we maybe add a hook on the keymap if such a need ever arises.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
Keymap = require 'keymap'
|
||||
$ = require 'jquery'
|
||||
RootView = require 'root-view'
|
||||
|
||||
describe "Keymap", ->
|
||||
fragment = null
|
||||
@@ -23,8 +24,8 @@ describe "Keymap", ->
|
||||
keymap.bindKeys '.command-mode', 'x': 'deleteChar'
|
||||
keymap.bindKeys '.insert-mode', 'x': 'insertChar'
|
||||
|
||||
deleteCharHandler = jasmine.createSpy 'deleteCharHandler'
|
||||
insertCharHandler = jasmine.createSpy 'insertCharHandler'
|
||||
deleteCharHandler = jasmine.createSpy('deleteCharHandler')
|
||||
insertCharHandler = jasmine.createSpy('insertCharHandler')
|
||||
fragment.on 'deleteChar', deleteCharHandler
|
||||
fragment.on 'insertChar', insertCharHandler
|
||||
|
||||
@@ -149,6 +150,19 @@ describe "Keymap", ->
|
||||
keymap.handleKeyEvent(keydownEvent('y', target: target))
|
||||
expect(bazHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the event's target is the document body", ->
|
||||
it "triggers the mapped event on the rootView", ->
|
||||
rootView = new RootView
|
||||
keymap.bindKeys 'body', 'x': 'foo'
|
||||
fooHandler = jasmine.createSpy("fooHandler")
|
||||
rootView.on 'foo', fooHandler
|
||||
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: document.body))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when at least one binding partially matches the event's keystroke", ->
|
||||
[quitHandler, closeOtherWindowsHandler] = []
|
||||
|
||||
|
||||
@@ -201,11 +201,11 @@ describe "RootView", ->
|
||||
expect(rootView.find('#two')).not.toMatchSelector(':focus')
|
||||
|
||||
describe "when there are no visible focusable elements", ->
|
||||
it "retains focus itself", ->
|
||||
it "surrenders focus to the body", ->
|
||||
rootView.remove()
|
||||
rootView = new RootView(require.resolve 'fixtures')
|
||||
rootView.attachToDom()
|
||||
expect(rootView).toMatchSelector(':focus')
|
||||
expect(document.activeElement).toBe $('body')[0]
|
||||
|
||||
describe "panes", ->
|
||||
[pane1, newPaneContent] = []
|
||||
|
||||
@@ -93,9 +93,8 @@ window.keyIdentifierForKey = (key) ->
|
||||
"U+00" + charCode.toString(16)
|
||||
|
||||
window.keydownEvent = (key, properties={}) ->
|
||||
event = $.Event "keydown", _.extend({originalEvent: { keyIdentifier: keyIdentifierForKey(key) }}, properties)
|
||||
# event.keystroke = (new Keymap).keystrokeStringForEvent(event)
|
||||
event
|
||||
properties = $.extend({originalEvent: { keyIdentifier: keyIdentifierForKey(key) }}, properties)
|
||||
$.Event("keydown", properties)
|
||||
|
||||
window.mouseEvent = (type, properties) ->
|
||||
if properties.point
|
||||
|
||||
@@ -99,6 +99,7 @@ class Keymap
|
||||
b.specificity - a.specificity
|
||||
|
||||
triggerCommandEvent: (keyEvent, commandName) ->
|
||||
keyEvent.target = rootView[0] if keyEvent.target == document.body and window.rootView
|
||||
commandEvent = $.Event(commandName)
|
||||
commandEvent.keyEvent = keyEvent
|
||||
aborted = false
|
||||
|
||||
@@ -18,7 +18,7 @@ class RootView extends View
|
||||
disabledPackages: []
|
||||
|
||||
@content: ->
|
||||
@div id: 'root-view', tabindex: 0, =>
|
||||
@div id: 'root-view', =>
|
||||
@div id: 'horizontal', outlet: 'horizontal', =>
|
||||
@div id: 'vertical', outlet: 'vertical', =>
|
||||
@div id: 'panes', outlet: 'panes'
|
||||
|
||||
@@ -205,7 +205,7 @@ describe 'FuzzyFinder', ->
|
||||
expect(finder.miniEditor.isFocused).toBeFalsy()
|
||||
|
||||
describe "when no editors are open", ->
|
||||
it "detaches the finder and focuses the previously focused element", ->
|
||||
it "detaches the finder and surrenders focus to the body", ->
|
||||
rootView.attachToDom()
|
||||
rootView.getActiveEditor().destroyActiveEditSession()
|
||||
|
||||
@@ -217,7 +217,7 @@ describe 'FuzzyFinder', ->
|
||||
finder.cancel()
|
||||
|
||||
expect(finder.hasParent()).toBeFalsy()
|
||||
expect($(document.activeElement).view()).toBe rootView
|
||||
expect(document.activeElement).toBe $('body')[0]
|
||||
expect(finder.miniEditor.isFocused).toBeFalsy()
|
||||
|
||||
describe "cached file paths", ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'#root-view':
|
||||
'body':
|
||||
'meta-\\': 'tree-view:toggle'
|
||||
'meta-|': 'tree-view:reveal-active-file'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user