Posted at

window.openでモーダルぽくする

More than 3 years have passed since last update.


Chromeではwindow.showModalDialogは使用できません。

「WEBサイトでポップアップが開かれて、開かれた画面(子画面)で何か選択すると、

元の画面(親画面)に選択された内容が反映される。」

ていうやつWEBサイトを開発してたらよくありますよね?

そんな時のやりたいこと、、、、、、

- 子画面が開いている時は親画面をいじられたくない。

- 親画面のElementを操作したい。

- 子画面を閉じると、親画面にフォーカスを当てたい。

window.showModalDialogを使って子画面を開き、

子画面で親画面のElementを取得し、

子画面を閉じると親画面にフォーカスが当たってくれます。

親画面の処理

// windowをモードダルで開く

// 第一引数Url、第二引数子画面をに渡す値
window.showModalDialog('sub.html',this,'width=400, height=300');

子画面でボタンを押した時などの処理

// 親画面から渡ってきた値を取得

// 今回は親画面のElementを操作する為windowを渡した
var parentWindowObject = window.dialogArguments;

// 親画面のelement1を取得
var element1 = parentWindowObject.document.getElementById('hoge1');
// element1に値を設定
element1.value = '値1';
// 親画面のelement2を取得
var element2 = parentWindowObject.document.getElementById('hoge2');
// element1に値を設定
element2.value = '値2';
// 子画面の終了
window.close();

簡単ですね・・・・

でも

ChromeではshowModalDialogが使えません。

クリックイベントなどでshowModalDialogを記載して、ボタンを押しても

Chromeだとウンともスンとも言ってくれませんでしたorz

なので、僕は以下の方法で、やりたいことを実現しました。


showModalDialogが使えない時

親画面の処理

// 適当に高さを指定してwindow.openでポップアップ画面を開く

var openWindow = window.open('sub.html','sub','width=400, height=300');
// 親画面にシェードをかける処理を実施
~ 処理の内容は省略 ~

// 1秒間隔で子画面の状態を監視
var interval = setInterval(function()
{
// 子画面が閉じていたら
if(!openWindow || openWindow.closed)
{
// 親画面のシェードを外す処理
~ 処理の内容は省略 ~

// Intervalを破棄
clearInterval(interval);
// 画面が起動していたら
}
else
{
// 子画面にフォーカスを当てる
if(!openWindow.document.hasFocus())
{
openWindow.focus();
}
}
},1000);

子画面の処理① ~ボタン押下等の処理~

// 親画面の存在確認

// 存在しなかったら次画面(子画面)を閉じる
if(!window.opener || window.opener.closed)
{
window.close();
}
else
{
// 親画面を取得
var parentWindowObject = window.opener;
// 親画面のelement1を取得
var element1 = parentWindowObject.document.getElementById('hoge1');
// element1に値を設定
element1.value = '値1';
// 親画面のelement2を取得
var element2 = parentWindowObject.document.getElementById('hoge2');
// element1に値を設定
element2.value = '値2';
// 子画面の終了
window.close();
}

子画面の処理② ~子画面自身の状態確認~

    $(document).ready(function()

{
$(window).on("beforeunload",function(e)
{
window.opener.focus();
});
});

です。


まとめ

window.showModalDialogで渡した親画面のObjectについては

window.openの場合はwindow.openerで取得することができます。

window.openの戻り値は子画面のObjectになります。

またjQueryの処理になりますが、

子画面起動後、setIntervalを行うことにより、

Timer処理で子画面の状態を監視できます。

while等を使ってループさせてしまうと、画面が固まるので

setIntervalでTimer処理を行います。

子画面が閉じられたと判断したら

clearIntervalでTimer処理を破棄します。

子画面が開いているときは、

openWindow.document.hasFocus

で子画面にフォーカスが当たっているか判断して、

当たっていなかったらopenWindow.focusでフォーカスを当てます。

openWindow.document.hasFocusの判定を行わずに

フォーカスを当て続けると、テキストボックス等に値を入力しているときに

Window全体にフォーカスが当たってしまうので、入力が途中でキャンセルされちゃいます

最後に子画面の監視処理です。

今回はjQueryを使ってwindowのbeforeunloadイベントをバインドしました。

これにより×ボタンでWindowを閉じてもイベントをひろうことができます。

完全なモーダルの場合は子画面を閉じると親画面にフォーカスがあたるのですが、

window.openで起動するとモードレスになるので、

親画面を最小化したりして親画面のIEを見失った時には便利です。

以上