@ledsun blog

無味の味は佳境に入らざればすなわち知れず

jQueryUIダイアログの上に自作モーダルダイアログをつくって要素をフォーカスするときの注意

次のようにjQueryUIダイアログの上にさらに、自作のモーダルダイアログを開く時の話です。

f:id:ledsun:20210608015618p:plain
jQueryUIダイアログの上に自作モーダルダイアログを開く

「すでにjQueryUIダイアログを使っているのだから、自作のモーダルダイアログは要らないだろう?」という疑問はその通りだと思います。すでに作成済みの自作モーダルダイアログ使い回したいときだと、考えてください。

このとき自作モーダルダイアログのinput要素またはbutton要素にフォーカスを当てたいです。 ところがこれが上手く行きません。 jQueryUIダイアログのフォーカスが奪われます。

https://github.com/jquery/jquery-ui/blob/1.12.1/ui/widgets/dialog.js#L868-L879 の実装を見ると

this._on( this.document, {
  focusin: function( event ) {
    if ( isOpening ) {
      return;
    }

    if ( !this._allowInteraction( event ) ) {
      event.preventDefault();
      this._trackingInstances()[ 0 ]._focusTabbable();
    }
  }
} );

documentのfoucsinイベント監視して、フォーカスを戻しています。 しかもやんちゃなことに、キャプチャリングフェーズです。 自作のモーダルダイアログ内のフォーカスを当てたいHTML要素のイベントが届く前に、このコードは実行されます。

jQueryUIダイアログの上のモーダルダイアログではフォーカスをとれないのか?というとそんなことはありません。 例えばjQueryUIダイアログの上に、jQueryUIダイアログを表示することは可能です。 その判定をしているのがthis._allowInteraction( event )です。

https://github.com/jquery/jquery-ui/blob/1.12.1/ui/widgets/dialog.js#L841-L849

_allowInteraction: function( event ) {
  if ( $( event.target ).closest( ".ui-dialog" ).length ) {
    return true;
  }

  // TODO: Remove hack when datepicker implements
  // the .ui-front logic (#8989)
  return !!$( event.target ).closest( ".ui-datepicker" ).length;
},

何を見ているかというとui-dialogクラスの有無です。

つまり、自作のモーダルダイアログにもui-dialogクラスを追加してあげれば、フォーカスを当てられます。

蛇足

jQueryUIは2016年が最後のリリースなので、それ以降はソースコードの修正はあまりしていないと思っていました。 今回ソースコードを見てみると2020年から、ちょこちょこコミットされていることに気がつきました。

f:id:ledsun:20210608021645p:plain
jQueryUIのコミット

https://github.com/jquery/jquery-ui/graphs/code-frequency