How to give keyboard focus to modal panel?


#1

I am creating a package that asks for some input from the user. I am creating a form with a text box, and a dropdown. I can give the panel focus by physically clicking on it, but I want to avoid this because you have to take your fingers off the keyboard. Do I need to give focus to the panel, to the div, or to an item in the form?

Some of what I’ve tried so far in my toggle command:

toggle: () ->
console.log(‘MultiThemeApplicator.toggle: now in toggle’);

if @localThemeSelectorPanel.isVisible()
  @localThemeSelectorPanel.hide()
else
  @localThemeSelectorPanel.show()
  @localThemeSelectorPanel.getElement().focus()
  #$("#themeDropdown").focus()
  #$("#themeText").get(0).focus()
  $("#themeText")[0].focus()

  @selectorView = document.createElement('div')
  @selectorView.classList.add('local-theme-selector-view')
  $('.local-theme-selector-view').attr( tabindex: '0')

Here’s my form:

  form = $('<form/>')
    .attr( id: 'input-form', class: 'apply-theme-form')
    .submit( (@applyLocalTheme.bind @) )

  form.appendTo(@selectorView)

  $('<input/>').attr(
    type: 'text'
    name: 'theme'
    id: 'themeText'
  ).appendTo(form)

  $('#themeText').on "click", () ->
    console.log "now in themeText click handler"
    $(this).html("abc")

  $('#themeText').trigger( "click")

  $('<input id="apply-theme-submit"/>').attr(
    type: 'submit'
    value: 'Apply Local Theme'
  ).appendTo(form)
  themeDropdown = $('<select id="themeDropdown" name="selectTheme">')

  for theme in LocalThemeSelectorView::ThemeLookup
    $('<option>', {
      value: theme.baseDir,
      text: theme.themeName})
    .appendTo(themeDropdown)

  themeDropdown.appendTo(form)

Sorry, about the crappy documention, but I’m hoping this is an easy question and won’t require a lot of detail. Could someone possibly recommend an existing package that already deals with this. The ctrl-shift-p seems to somehow be able to do it.


#2

This worked for me.

  1. Define an atom event handler where I give focus to an element in the form (that is in the modal panel)

    focusModalPanel: () ->
    $(’#themeText’).focus()

  2. Create a subscription (listener) for this event in the context of ‘atom-workspace’

    @subscriptions.add atom.commands.add ‘atom-workspace’,
    ‘multi-theme-applicator:applyLocalTheme’: => @applyLocalTheme()
    ‘local-theme-selector-view:focusModalPanel’: => @focusModalPanel() # <- add

  3. add key binding to keymap.cson:

“atom-workspace”:
“ctrl-alt-v”: “multi-theme-applicator:toggle”
“ctrl-alt-shift-v”: “multi-theme-applicator:applyLocalTheme”
“ctrl-alt-shift-y”: “local-theme-selector-view:focusModalPanel” #<- add

So when the modal panel comes, I guess the ‘atom-workspace’ still has focus. I then press the key binding "ctrl-alt-shift-y’, and that drives my event handler which gives focus to the element. Now my modal dialog has keyboard focus. I did try giving this element focus in the constructor of the modal dialog, but it didn’t work.

I also don’t know why the editor doesn’t automatically give the modal dialog focus when it first comes up.

Anyway, the answer is to give focus to an element in the dialog, at the right time (e.g not during initialization).

I’m sure there’s a better way to do this, but this will do for now.