問題だらけのshowModalDialog
はじめに
ブラウザ上でのJavaScriptに、showModalDialogというメソッドがある。MDCのリファレンス(MDC)の説明*1を引用すると、
指定された HTML 文書を含む モーダルダイアログボックスを生成し、表示します。
という機能を持つメソッドだ。しかしながらこのメソッド、私が今回経験したが、問題山積だ。結論から言うと、使うべきでない。
本エントリでは、私が今回発見したshowModalDialogの問題点を列挙し、このメソッドが必要になりそうな場合の代替案を示す。
問題点1:ダイアログ側でwindow.openerがundefined
詳細
showModalDialogで開かれたダイアログに読み込まれたページ内のJavaScriptで、window.openerを取得するとundefinedとなるブラウザがある(ブラウザ依存)。
問題となるケースの例
開かれたダイアログでの処理終了時、開いたページをリロード(ASP.NETならポストバック)したい。このような場合に、ダイアログ側がwindow.opener経由で行うことができない。
対応策
showModalDialogの第2引数を使う。この引数を使えば、任意のオブジェクトを渡すことができる。従って、この引数に開く側のwindowオブジェクトを渡せば、ダイアログ側でそれを参照できる。なお、当該引数で渡された値を参照するには、window.dialogArgumentsプロパティを使う。
問題点2:ダイアログ側でのformのsubmitで、別ウィンドウが開いてしまう
確認ブラウザ
- Win XP SP3上のIE 6:該当
詳細
showModalDialogで開かれたダイアログに読み込まれたページ内で、formをsubmitすると、targetを設定していなくても、別ウィンドウが開いてしまうことがある。詳細な発生条件は不明だが、私が書いていたコードでは発生した。
問題となるケースの例
ASP.NETのポストバックでも発生する。
対応策
ダイアログ側のJavaScriptなどで、次の手順を踏む。
- window.name(自身のウィンドウ名)を設定
- submitするformのnameに、1で設定したのと同じ名前を設定
- formをsubmit
問題点3:ダイアログ側でwindow.openしたら、開かれるウィンドウにセッションが渡らない
詳細
ダイアログを子ウィンドウと呼ぶとするなら、言わば孫ウィンドウを開く場合がこれに該当する。孫ウィンドウにはセッションが渡らない。
技術的な理由
このページ(個人blog)、およびそのリンク先などによると、IEでは、showModalDialogで開かれたダイアログからwindow.openでウィンドウを開く場合、そのウィンドウ(孫ウィンドウ)を別のOSプロセスで開くのだそうだ。セッションは通常、同一プロセス内でのみ有効なCookieを使って実現されている。従ってこのCookieが孫ウィンドウに渡らず、セッションも渡らない。
対応策
問題点1で示した対応策と同じ方法で、ダイアログを開いたページ(親ウィンドウ)のwindowオブジェクトをダイアログ側で参照可能としておく。そして、ダイアログ側でwindow.openする場合は、ダイアログ自体のwindowオブジェクトでなく、親ウィンドウのwindowオブジェクトのopenメソッドを呼び出す。
しかしこの方法だと、孫ウィンドウのwindow.openerが子ウィンドウでなく親ウィンドウとなってしまう。なので、あまり良い方法とは言えない。しかし、他に方法はなさそうだ。
ここまでのまとめ:showModalDialogは使うべきでない
以上で示したように、showModalDialogには問題だらけだ。私にとって特に問題なのは、ブラウザ依存が多すぎることだ。ブラウザによる処理の分岐は、フレームワークが担当すべきで、アプリケーションではすべきでないと思う。ブラウザがバージョンアップする度にテストするなど、やっていられない。
従って、以降では代替案を示す。
代替案1:モーダルダイアログを設計から排除する
最優先すべきは、この案だと思う。ユーザーの自由を奪うモーダル反対!
Webアプリケーションでは、モーダルダイアログは邪道。というのが2010年現在では一般的だと思われる。インターネット上で見かけたことがないので(後述の擬似モーダルは除く)。
どうしてもモーダルダイアログにしなければならないという局面(例:そうしないとデータを破壊してしまう)など、ほとんど思いつかない。せいぜいGUI上での整合性が崩れるとか、その程度なはず。
代替案2:擬似モーダルダイアログを使う
どうしてもモーダルダイアログを使わなければならない。そんな窮地に追い込まれたら、せめて擬似的なモーダルダイアログで許してもらった方が良いだろう。擬似的なモーダルダイアログのサンプルを紹介しておく。
- YUI2(YUI公式)
- RadControls for ASP.NET AJAX(ベンダー公式)
ただしこの案のような、擬似的なウィンドウを使う場合、様々な制約が生じる。以下に例を挙げる。
- 親ウィンドウが閉じられた場合に、擬似ウィンドウだけを残すことができない
- 擬似ウィンドウを親ウィンドウの外に出せない
このように、擬似的なウィンドウも諸刃の剣なため、要注意だ。