エンジニアの落とし穴 ~Chrome移行編~
お疲れ様です!ニシザワです。
今年でエンジニア歴6年目となる私ですが、エンジニアをやっていれば、想定しないエラーだとか、挙動に戸惑う事が多々あります。
中には、おま環なのか調べてみても上手く検索に引っかからない事もあります。
そういった事象について、私が引っかかった落とし穴とその対策を紹介したいと思います。
題しましては、「エンジニアの落とし穴」!!
第1回の今回は、「Chrome移行編」です。では、さっそく本題に行ってみましょう!
目次
Chrome移行について
Internet Explorer(以下、IE)のサポート終了が2022年6月と差し迫っています。
Webアプリケーションを担当しているエンジニアの方々は対応を迫られた、もしくは現在進行形で迫られていることかと思います。
私も例のごとく対応を行ったのですが、ざっと以下のような懸念がありました。
1.パッケージが対応しているのか
2.UIに影響はないか
3.現行のプログラムに影響はないか
1に関しては、パッケージの対応ブラウザ(何なら推奨ブラウザ)だったので問題ありません。
2についても、そんなに凝ったことはせずhtml,cssを使ったシンプルなデザインだった為、特に影響はありません。
引っかかったポイントは3です。こちらについて、詳しく紹介していきます。
落とし穴① モーダルウィンドウが使えない
今回対応が必要だった変更はこれだけでした。
Chromeでは、セキュリティの観点からwindow.showModalDialog()が使えません。
モーダルウィンドウとは、ブラウザ上で表示させる子ウィンドウで、子ウィンドウを閉じるまで親ウィンドウを操作させなく出来ます。
後続処理に必ず入力したパラメータが必要だったりする場合には、便利な機能ですね。裏画面を操作できないので、誤操作も少なくなります。
私が担当しているシステムではモーダルを使って、裏で実行する処理に必要なパラメータをユーザに入力させる仕組みが実装されていました。
実際にChromeで実行してみるとモーダルが表示されず後続処理が動かない状態に。。(´┐`)
対応策はネットでちょっと調べれば出てきますが、コールバック関数とwindow.openで代用可能です!
実装例を見ていきましょう。
<title>親画面</title>
<script src="/showModal.js>
<script>
function execShowModalDialog(){
parm = showParmPrompt();
if(parm == null){
//入力が無ければ処理を終了
return;
}
document.getElementById('parameter').value = parm;
$.ajax({
//~~~~省略~~~~
});
}
</script>
main.html
function showModal(){
var parameter;
parameter = window.showModalDialog("/sub.html","prompt","dialogWidth=500px,dialogHeight=220;scroll=no");
return parameter;
}
showModal.js
<title>子画面</title>
<script>
function okBtnClicked(){
window.returnValue=document.form1.password.value;
window.close();
}
</script>
<form id="form1" method="post" name="form1" onSubmit="return false;">
<div>
<input type="text" name="parameter">
</div>
<div>
<button type="button" class="radius button" id="okBtn" onclick="okBtnClicked();">実行</button>
<button type="button" class="radius button" id="cancelBtn" onclick="window.close();">キャンセル</button>
</div>
</form>
sub.html
所々端折ったり改竄していますが、大体こんな感じの実装でした。
これをChromeに対応させるには、showModal.jsで使用しているwindow.showModalDialog()をwindow.open()に置き換える必要があります。
早速、置き換えてみましょう!
※親画面の変更は無し
function showModal(){
var parameter;
var callback = 'callback1';
//コールバック関数
window[callback] = function(returnValue){
parameter = returnValue.parameter;
return parameter;
}
var openWindow = window.open('/sub.html',callback,'width=500,height=400,menubar=no,location=no,resizable=no,scrollbars=no,status=no');
}
showModal.js
<title>子画面</title>
<script>
function okBtnClicked(){
var callback = window.name;
var returnValue = { parameter: document.form1.parameter.value }
wiondow.opener[callback](returnValue);
window.close();
}
</script>
<form id="form1" method="post" name="form1" onSubmit="return false;">
<div>
<input type="text" name="parameter">
</div>
<div>
<button type="button" class="radius button" id="okBtn" onclick="okBtnClicked();">実行</button>
<button type="button" class="radius button" id="cancelBtn" onclick="window.close();">キャンセル</button>
</div>
</form>
sub.html
軽く調べて出てきた記事などを参考に実装したプログラムがこちらです。
案外、簡単に実装できる? ボタン押したらモーダル開いたし、出来たー!
と思ったのもつかの間、実行ボタンを押しても後続処理が実行されない。。。(゚A゚ )
デベロッパーモードでデータの流れを確認してみると、子画面が開いた時点でreturn文が実行されてる!Σ(‼❍ฺω❍ฺ‼)
原因を調べてみるも、中々このような事象が発生したという記事にたどり着かない。
改めてモーダルの仕様について小一時間調べてみると、window.showModalDialogとwindow.openで動作の異なる部分が判明しました。
落とし穴② showModalDialogとopenの決定的な違い
今回一番頭を悩ませた動作の違い、それは「同期処理」と「非同期処理」の違いです。
慣れている方であればそりゃそうだろと思うでしょうが、恥ずかしながら当時の自分は、気付くまで結構時間がかかりました。。
showModalDialogは「同期処理」。子画面が閉じるまで、裏の画面処理(main.htmlとshowModal.js)は止まってくれます。
対してopenは「非同期処理」なので、裏の画面処理が進んでreturn文まで実行してしまう為、
子画面でいくらパラメータを入力しても空振ってしまいます。(*→ω←)
子画面を表示したいだけとか、親画面で入力したものを子画面に渡すなら気にする必要ないですが、今回は影響大ありでした。
というわけで、main.htmlとshowModal.jsを修正して非同期処理に対応させましょう!
<title>親画面</title>
<script src="/showModal.js>
<script>
function execShowModalDialog(){
parm = showParmPrompt();
}
</script>
main.html
function showModal(){
var parameter;
var callback = 'callback1';
//コールバック関数
window[callback] = function(returnValue){
parameter = returnValue.parameter;
//親画面で実行していた後続処理
if(parm == null){
//入力が無ければ処理を終了
return;
}
document.getElementById('parameter').value = parm;
$.ajax({
//~~~~省略~~~~
});
}
var openWindow = window.open('/sub.html',callback,'width=500,height=400,menubar=no,location=no,resizable=no,scrollbars=no,status=no');
}
showModal.js
※子画面は変更無し
これで対応完了です!
実際は、このmain.htmlに該当する画面が20本近くあり、全て改修する羽目になったのはまた別の話。。。
まとめ
いかがだったでしょうか。
ブラウザ移行対応を行うのは、初めてだったこともあり思わぬ落とし穴にハマってしまいましたが、良い勉強になりました!
大抵の事は調べればわかりますが、落とし穴を回避する為には、予め考えながら実装すること、実装後の確認を重点的に行う事が大切ですね。
この記事が僅かながらでもChrome移行への参考になれば幸いです。
それではまた!