デフォルトの確認ダイアログ

Railsではデータの削除時などに簡単に確認ダイアログを表示する仕組みが用意されています。
下に示すlink_to メソッドの引数に data: {confirm: 'メッセージ' } のように記述することにより、 リンクやボタンをクリックする際にブラウザに組み込まれている確認ダイアログを表示させることができます。

      <%= link_to message_path(message), method: :delete, data: { confirm: 'Are you sure?' } do %>
        <i class="uk-icon-times"></i>
        <%= t('buttons.destroy') %>
      <% end %>

しかし、Chromeでは次の図のように、少しがっかりしてしまうような確認ダイアログが表示されてしまいます。

default-dialog

ブラウザ毎に確認ダイアログのデザインは異なりますが、Chromeがもっとも残念な感じがします・・・
今回は、この確認ダイアログをUIkitの確認ダイアログが表示されるように変更してみたいと思います。 参考にしたのは下記のサイトです。本文でなく、コメントのコードの方を採用してみました。

http://thelazylog.com/custom-dialog-for-data-confirm-in-rails/


確認ダイアログを表示している正体は・・・

Railsで確認ダイアログを簡単に表示させることができるのは、Railsアプリケーションを新規に生成する際に jquery_ujsというライブラリが組み込まれているからです。
app/assets/javascripts/application.jsに次のような記述があることが確認できると思います。

//= require jquery

//= require jquery_ujs

確認ダイアログの制御はこのライブラリのJavaScriptで行われており、この処理を変更することによって 別のダイアログを表示させたいと思います。

とは言え、このライブラリを変更するのではなく、モンキーパッチ的ではありますがイベントを横取りするかたちになります。
(カスタマイズし易い実装してくださっているような気がします。勉強になります。)


UIkitの確認ダイアログが表示されるように変更する

JavaScriptでもCoffeeScriptでも構いませんが、今回はCoffeeの方で実装してみます。
また、今回は確認ダイアログが画面中央に表示されるオプションを指定しました。

$ ->

  #******************************

  # 確認ダイアログ data-confirm のカスタマイズ

  #******************************


  $(document.body).on 'confirm', (event) ->
    elem = event.target
    message = $(elem).data('confirm')

    UIkit.modal.confirm(
      message
      ->
        $(elem).data('confirm', null)
        $(elem).trigger('click.rails')
      center: true
    )
    false

それでは、削除時の確認ダイアログが変わるか確認してみましょう。

custom-dialog

見事にUIkitのモーダルの確認ダイアログが表示されました。 しかし・・・ドロップダウンメニューに「削除する」のリンクを設けていたため、ダイアログと重なってしまいました。

UIkitのドキュメントを確認したところ、dropdown のコンテナのクラスに uk-dropdown-close を追加する ことによって、「削除する」リンククリック時にドロップダウンメニューを非表示にすることができました。(助かりました)


ボタンを変更してみる

続いて気になるのがボタンが英語になっている部分ですね。
OK、Cancelくらい誰でもわかるよ!って聞こえてきそうですが、変更できるそうなので試してみます。

先ほどのCoffeeScriptにオプションを追加します。

  $(document.body).on 'confirm', (event) ->
    elem = event.target
    message = $(elem).data('confirm')

    UIkit.modal.confirm(
      message
      ->
        $(elem).data('confirm', null)
        $(elem).trigger('click.rails')
      center: true
      labels: { 'Ok': 'はい', 'Cancel': 'キャンセル'}  # <= 追加

    )
    false

日本語をそのまま記述してしまっている点も何とかしたいところですが、今回はここまで。
最終的には以下のような確認ダイアログになりました。

custom-dialog-finally

あっさりし過ぎという声も聞こえてきそうですが、後はCSSを変更したり、 UIkitのカスタムテーマを適用したりして対応することになるでしょう。


おまけ

確認ダイアログがUIkitのモーダルに変わりましたが、どうしてデフォルトで表示されていた 確認ダイアログは表示されなくなったのでしょう?

それは、先ほどのCoffeeScriptの最後の行をfalseからtrueに変更してみればわかります。

https://github.com/rails/jquery-ujs/blob/master/src/rails.js

から一部ソースコードを抜粋しますが

allowAction: function(element) {
  var message = element.data('confirm'),
      answer = false, callback;
  if (!message) { return true; }

  if (rails.fire(element, 'confirm')) { // <= ここでイベント発火、UIkitの確認ダイアログが表示される

    try {
      answer = rails.confirm(message);  // <= falseが戻ればデフォルトの確認ダイアログは表示されない

    } catch (e) {
      (console.error || console.log).call(console, e.stack || e);
    }
    callback = rails.fire(element, 'confirm:complete', [answer]);
  }
  return answer && callback;
},

jquery_ujsのgemのコードが変わってしまうと、ここで紹介した方法は使えなくなる可能性があります。

公式のページでカスタマイズ方法を紹介してもらっていれば心配ないのですが見当たらないので・・・