atsukanrockのブログ

Microsoft系技術を中心にぼちぼち更新します

問題だらけのshowModalDialog

はじめに

ブラウザ上でのJavaScriptに、showModalDialogというメソッドがある。MDCのリファレンス(MDC)の説明*1を引用すると、

指定された HTML 文書を含む モーダルダイアログボックスを生成し、表示します。

という機能を持つメソッドだ。しかしながらこのメソッド、私が今回経験したが、問題山積だ。結論から言うと、使うべきでない。

本エントリでは、私が今回発見したshowModalDialogの問題点を列挙し、このメソッドが必要になりそうな場合の代替案を示す。

問題点1:ダイアログ側でwindow.openerがundefined

確認ブラウザ
  • Win XP SP3上のIE 6:該当
  • Win XP SP3上のSafari 4.0.4:非該当(showModalDialogを呼び出したwindowオブジェクトを取得可能)
詳細

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などで、次の手順を踏む。

  1. window.name(自身のウィンドウ名)を設定
  2. submitするformのnameに、1で設定したのと同じ名前を設定
  3. formをsubmit

問題点3:ダイアログ側でwindow.openしたら、開かれるウィンドウにセッションが渡らない

確認ブラウザ
  • Win XP SP3上のIE 6:該当
  • Win XP SP3上のSafari 4.0.4:非該当

後述の技術的な理由から推測すると、IE限定だと思われる。

詳細

ダイアログを子ウィンドウと呼ぶとするなら、言わば孫ウィンドウを開く場合がこれに該当する。孫ウィンドウにはセッションが渡らない。

技術的な理由

このページ(個人blog)、およびそのリンク先などによると、IEでは、showModalDialogで開かれたダイアログからwindow.openでウィンドウを開く場合、そのウィンドウ(孫ウィンドウ)を別のOSプロセスで開くのだそうだ。セッションは通常、同一プロセス内でのみ有効なCookieを使って実現されている。従ってこのCookieが孫ウィンドウに渡らず、セッションも渡らない。

対応策

問題点1で示した対応策と同じ方法で、ダイアログを開いたページ(親ウィンドウ)のwindowオブジェクトをダイアログ側で参照可能としておく。そして、ダイアログ側でwindow.openする場合は、ダイアログ自体のwindowオブジェクトでなく、親ウィンドウのwindowオブジェクトのopenメソッドを呼び出す。

しかしこの方法だと、孫ウィンドウのwindow.openerが子ウィンドウでなく親ウィンドウとなってしまう。なので、あまり良い方法とは言えない。しかし、他に方法はなさそうだ。

ここまでのまとめ:showModalDialogは使うべきでない

以上で示したように、showModalDialogには問題だらけだ。私にとって特に問題なのは、ブラウザ依存が多すぎることだ。ブラウザによる処理の分岐は、フレームワークが担当すべきで、アプリケーションではすべきでないと思う。ブラウザがバージョンアップする度にテストするなど、やっていられない。

従って、以降では代替案を示す。

代替案1:モーダルダイアログを設計から排除する

最優先すべきは、この案だと思う。ユーザーの自由を奪うモーダル反対!

Webアプリケーションでは、モーダルダイアログは邪道。というのが2010年現在では一般的だと思われる。インターネット上で見かけたことがないので(後述の擬似モーダルは除く)。

どうしてもモーダルダイアログにしなければならないという局面(例:そうしないとデータを破壊してしまう)など、ほとんど思いつかない。せいぜいGUI上での整合性が崩れるとか、その程度なはず。

代替案2:擬似モーダルダイアログを使う

どうしてもモーダルダイアログを使わなければならない。そんな窮地に追い込まれたら、せめて擬似的なモーダルダイアログで許してもらった方が良いだろう。擬似的なモーダルダイアログのサンプルを紹介しておく。

ただしこの案のような、擬似的なウィンドウを使う場合、様々な制約が生じる。以下に例を挙げる。

  • 親ウィンドウが閉じられた場合に、擬似ウィンドウだけを残すことができない
  • 擬似ウィンドウを親ウィンドウの外に出せない

このように、擬似的なウィンドウも諸刃の剣なため、要注意だ。

最後に

本文中でリンクを張れなかったので、MSDNへのリンクMSDN*2)も張っておく。

*1:Geckoエンジン(Firefoxなどが使用)の仕様

*2:MSDNということは、IEの仕様ということだろうか