確実にメッセージをフェードアウトする。
MacBookの温度は快適になったが、periodically_call_remoteの頃から、見て見ぬ振りをしていた現象がある。それは、時々モーダルウィンドウのメッセージが消えずに、いつまでも表示され続ける、という現象だ。そろそろちゃんと対処したい。昨日から、どのような条件で発生するのか詳しく観察したところ、以下のことが確認できた。
- メッセージが表示されている最中に、さらに更新ボタンを押してしまうと、新たなメッセージが追加表示され、それ以前のメッセージがいつまでも表示され続ける。
- ページ全体を読み込んでから5秒以内だと、メッセージが1つしかない場合でも、いつまでも表示され続ける。
現在のメッセージを描画するコードは以下のようになっている。
- app/views/layouts/_flash.rhtml
- ビュー
<div id="flash"> <% for name in [:notice, :warning, :message] %> <% if flash[name] %> <br /> <div class="flash"> <%= "<p style=\"color: green\">#{flash[name]}</p>" %> <% flash[name] = nil %> </div> <% end %> <% end %> <%= javascript_tag remote_function(:url=>{:action=>:check_flash_timer}) %> </div>
眺めていたら、上記現象は<div id="flash">タグがネストして*1、1ページに同じid属性が複数存在するために発生していると気付いた。そこで、メッセージごとにオリジナルなid属性を設定することを考えた。
通し番号を付加しようと思ったが、webアプリショーションの場合、値を保持し続けることに手間がかかる。ここでは、重複しない値が欲しいだけなので、現在時刻を数値に変換して利用することにした。以下のようにやってみた。
- app/views/layouts/_flash.rhtml
- ビュー
- 最初、flash_time = Time.nowとしていた。しかし、これだとパラメーターとして送信した時に、スペースが混じっているのでそれがエスケープされてしまい、ビューとコントローラーで異なるid属性を扱うことになってしまう。そのためto_iで整数に変換した。
<% flash_time = Time.now.to_i %><%#<------現在時刻を数値に変換 %> <div id=<%= "flash_#{flash_time}" %>><%#<------式展開例: flash_1180853704 %> <% for name in [:notice, :warning, :message] %> <% if flash[name] %> <br /> <div class="flash"> <%= "<p style=\"color: green\">#{flash[name]}<small><small>[#{Time.now.strftime('%Y/%m/%d %H:%M:%S')}]</small></small></p>" %> <% flash[name] = nil %> </div> <% end %> <% end %> <%#v------以下パラメータを追加:flash_time=>flash_time %> <%= javascript_tag remote_function(:url=>{:action=>:check_flash_timer, :flash_time=>flash_time}) %> </div>
- app/controllers/application.rb
- コントローラー
- ビューからparams[:flash_time]でid属性を受け取って、その部分に対してビジュアルエフェクトをかけている。params[:flash_time]は、メッセージを表示する直前の時刻を数値に変換した値が保存されている*2。
def check_flash_timer if request.xhr? render :update do |p| p.delay(5) do p.visual_effect(:DropOut, "flash_#{params[:flash_time]}", :duration => 2) end end else redirect_to :controller=>'csvs', :action=>'list' end end
さらに修正
これでメーッセージは確実にフェードアウトしてくれる、と思っていたら、まだ問題があった。to_iでは1秒間に2回以上更新ボタンを押さない限り問題ないのだが、試しに更新ボタンをダブルクリックしてみると、なんと1秒間に2回以上操作できてしまうではないか...。でも、この修正は簡単で、to_iをto_f*3にするだけでOK。これでメッセージがいつまでも表示され続けることがなくなった!