背景を暗くするモーダルウィンドウで表示したい!(Control.Modalの使い方)その2

前回までに、モーダルウィンドウが表示できるようになった。今回は調子に乗って、ユーザー環境設定ページに加え、パスワード変更、ユーザ情報編集*1ページもモーダルウィンドウ化することにした。(管理者以外の一般ユーザーが操作するサブページは全てモーダルウィンドウ化することにした。)前回まで設定が終わっているiframe: trueのモーダルウィンドウなら、その作業はとっても簡単だ!

モーダルウィンドウの追加

  1. モーダルウィンドウで表示したいページへのリンクに、:class=>"modal"を追記する。
  2. キャンセルリンクをモーダルウィンドウを閉じるJavaScriptに変更する。
  3. submitボタンを押した後のページ遷移を同じページの再表示に変更する。
以下、パスワード変更ページのモーダルウィンドウ化の作業例
app/views/layouts/_menu2.rhtml
1 :class=>"modal"を追記
...(途中省略)...
<div id="navcontainer">
  <ul id="navlist">
  <%= link_if_authorized_current 'CSVリスト', 
          {:controller=>'csvs', :action=>'list'}, :wrap_in=>"li" %>
  <%= link_if_authorized_current '設定', 
          {:controller=>'defaults', :action=>'edit_preference'}, :wrap_in=>"li", :class=>"modal" %>
  <%= link_if_authorized_current 'パスワード変更', 
          {:controller=>'user', :action=>'change_password'}, :wrap_in=>"li", :class=>"modal" %><%#<------追記 %>
...(途中省略)...
app/views/user/change_password.rhtml
2 キャンセルリンクをモーダルウィンドウを閉じるJavaScriptに変更
<%#= link_to _('Cancel'), :action => 'home' %>
<%= link_to_function 'キャンセル', "parent.Control.Modal.close();" %><%#<------変更後 %>
app/controllers/user_controller.rb
3 submitボタンを押した後のページ遷移を同じページの再表示に変更
  def change_password
    return if generate_filled_in
    if do_change_password_for(@user)
      #redirect_back_or_default :action => 'change_password'
      render :action => 'change_password' #<------変更後
    end
  end


このように、ちょっとした変更でモーダルウィンドウ化することが可能だ。しかし、やっているうちに細かなところが気になってくるものだ。現状、ウィンドウのサイズが640×480固定(以下のJavaScriptの中で設定しているため)であるが、それぞれのサブページに最適な大きさに変更したくなってきた。

app/views/layouts/_menu2.rhtml
レイアウト(メニューの描画を担当)
  • 現状は、以下のように、JavaScriptの中でサイズを固定してしまっている。
...(途中省略)...
<%= javascript_tag <<END_javascript_tag
  // $$('a.modal')は、<a class="modal">である要素オブジェクト(element)を全て取得する。
  $$('a.modal').each(function(link){
    new Control.Modal(link,{
      iframe: true,
      width: 640,
      height: 480
    });
  });
END_javascript_tag
%>

モーダルウィンドウごとにサイズを指定する

そこで、Control.Modalのページで紹介されている、id属性を利用した方法でやってみた。上記のclass属性を利用したモーダルウィンドウで表示するJavaScriptを、以下のように変更する。

app/views/layouts/_menu2.rhtml
レイアウト(id属性でモーダルウィンドウを表示する)
<%#= javascript_tag <// イベントを監視して、ウィンドウがロードされたら、id属性のURLをモーダルウィンドウで開く。
	// $('modal_preference')は、id属性がmodal_preferenceである要素オブジェクト(element)を示す。
	Event.observe( window,'load',function(){
                // ユーザー環境設定用のウィンドウ
		new Control.Modal( $('modal_preference'),{
			iframe: true,
			width: 576,
			height: 360
		});

                // パスワード変更用のウィンドウ
		new Control.Modal( $('modal_password'),{
			iframe: true,
			width: 768,
			height: 480
		});

                // ユーザー情報編集用のウィンドウ
		new Control.Modal( $('modal_user'),{
			iframe: true,
			width: 768,
			height: 520
		});
	});
END_javascript_tag
%>

上記JavaScriptの変更に伴って、今までclass="modal"としていた箇所を、例えばid="modal_preference"と変更すれば、576×360サイズのユーザー環境設定用のモーダルウィンドウで表示することが出来る。リンクの中で、上記JavaScript中の$('id属性の名前')を、id属性に設定すれば、一致するウィンドウ属性で表示してくれるようになるのだ。ビューでは、以下のようにid属性を指定した。

app/views/layouts/_menu2.rhtml
1 :id=>"modal_preference"に変更
...(途中省略)...
<div id="navcontainer">
  <ul id="navlist">
  <%= link_if_authorized_current 'CSVリスト', 
          {:controller=>'csvs', :action=>'list'}, :wrap_in=>"li" %>
  <li><%= link_if_authorized_current '設定', 
          {:controller=>'defaults', :action=>'edit_preference'}, :id=>"modal_preference" %></li>
  <li><%= link_if_authorized_current 'パスワード変更', 
          {:controller=>'user', :action=>'change_password'}, :id=>"modal_password" %></li>
...(途中省略)...
      • id属性を利用する時は、:wrap_in=>"li"オプションは使えない...。:wrap_in=>"li"と :id=>"modal_preference"を同時に使うと、liタグとaタグの両方に同じ名前のid属性が設定されてしまい、JavaScriptが正常に動かなくなってしまうようだ。そのため、:wrap_in=>"li"を削除して、idタグで直接囲う方法に変更した。
      • モーダールウィンドウを表示するJavaScriptの設定は、Control.ModalのAdvanced Usageで紹介されている通り、もっと細かな設定も可能だ。

パラメーターでウィンドウサイズを指定

ところが、たかがウィンドウサイズを設定するだけで、慣れないJavaScriptをその都度追記しなくてはならないのは、とても面倒に思えてきた...。モーダルウィンドウが増えたら、管理するのも大変だ。JavaScriptの中で、ウィンドウサイズもパラメーターとして受け取ることが出来れば良いのだ。試行錯誤の結果、class属性で指定する方法に戻して、以下のようにやってみた。

app/views/layouts/_menu2.rhtml
レイアウト(class属性でモーダルウィンドウを表示する)
  • メソッド getAttribute("属性名称") を利用すると、属性名称の値を取得することが出来るようだ。
  • 変数linkには、class="modal"であるaタグの1つが、オブジェクトとして代入されている。
<%= javascript_tag <<'END_javascript_tag'
  // $$('a.modal')は、<a class="modal">である要素オブジェクト(element)を全て取得する。
  $$('a.modal').each(function(link){
		new Control.Modal(link,{
		        iframe: true,
		        width: link.getAttribute("width"),
		        height: link.getAttribute("height")
		});
  });
END_javascript_tag
%>
app/views/layouts/_menu2.rhtml
:class=>"modal"に戻して、:width、:height属性を指定
...(途中省略)...
<div id="navcontainer">
  <ul id="navlist">
  <%= link_if_authorized_current 'CSVリスト', 
          {:controller=>'csvs', :action=>'list'}, :wrap_in=>"li" %>
  <%= link_if_authorized_current '設定', 
          {:controller=>'defaults', :action=>'edit_preference'}, :wrap_in=>"li", 
          :class=>"modal", :width=>576, :height=>360 %>
  <%= link_if_authorized_current 'パスワード変更', 
          {:controller=>'user', :action=>'change_password'}, :wrap_in=>"li", 
          :class=>"modal", :width=>768, :height=>480 %>
...(途中省略)...


これで、複数のウィンドウに自由にサイズ指定できるようになった!

参考ページ

JavaScriptについて、以下のページが大変参考になりました。感謝です。

*1:画面左上のユーザー名のリンクで移動するページ