ほとんどイヤがらせ for Safari Only [JavaScript]
◆ほとんどイヤがらせ for Safari Only
今回は、俺が自分の環境で経験した、JavaScript のユーザーエージェント(ブラウザ)ごとに異なる挙動の一例です。
手元の環境で、Internet Explorer、Firefox、Opera、Safari、Google Chrome の中で、(環境や OS にもよると思いますが)Safari を除くブラウザは普通に動いてくれるのに、 Safari だけ「ほとんどイヤがらせ」になってしまった例を紹介します。
なお、今回のエントリーは、Safari の性能や機能に対する批判が目的ではありません。
Safari が特別劣ったブラウザとも思っていません。
これは、俺が開発中に、俺の環境でたまたま発生した事例であって、他の環境では発生しないかもしれないし、あるいは他のブラウザでも、まだ俺の知らない深刻な問題があるかもしれませんし。
その点をご理解の上、お読み頂ければと思います。
◆今回のひとこと
(俺の環境では)Safari のイベントハンドラの実装には気をつけろ!
document の onclick イベントをひっかけて alert を出す処理を書いたら、Safari(5.0.3)だけ、永遠にダイアログ ボックスが開き続ける「ほとんどイヤがらせ」な代物ができちゃいました;;;。
他のブラウザ(Internet Explorer、Firefox、Opera、Google Chrome)では、大丈夫でした。
ソースの書き方が悪いのかもしれないし、俺の環境がよくないのかもしれないし、Safari のイベント取得の仕組みが他のブラウザと違うのかもしれないし、原因はよくわかりません。
でも、こういうときって、最初に自分を疑ってかかったほうが、だいたい間違いないんですよね;;;。
以下が、問題のソースです。
普通に JavaScript の決まりごとの範囲で、複数のブラウザ共通で動くように書いたつもりだったんです。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Almost Browser Crusher for Safari</title>
<script type="text/javascript">
//<![CDATA[
// 環境エラー
function errorEnvironment() {
alert('ご使用の環境は、このスクリプトではサポートされません。');
}
// イベントを追加する addEvent
function addEvent(evt, func, cap) {
if (this.addEventListener)
this.addEventListener(evt, func, cap);
else if (this.attachEvent)
this.attachEvent('on' + evt, func);
else
errorEnvironment();
}
Object.prototype.addEvent = addEvent;
HTMLDocument.prototype.addEvent = addEvent;
Element.prototype.addEvent = addEvent;
// イベントを削除する removeEvent
function removeEvent(evt, func, cap) {
if (this.removeEventListener)
this.removeEventListener(evt, func, cap);
else if (this.detachEvent)
this.detachEvent('on' + evt, func);
else
errorEnvironment();
}
Object.prototype.removeEvent = removeEvent;
HTMLDocument.prototype.removeEvent = removeEvent;
Element.prototype.removeEvent = removeEvent;
// ドキュメントのクリック イベント
function onDocumentClick(evt) { alert('document がクリックされました。'); }
// ウィンドウのロード イベント
function onWindowLoad(evt) {
window.removeEvent('load', onWindowLoad, true);
window.addEvent('unload', onWindowUnload, true);
document.addEvent('click', onDocumentClick, false);
}
// ウィンドウのアンロード イベント
function onWindowUnload(evt) {
window.removeEvent('unload', onWindowUnload, true);
document.removeEvent('click', onDocumentClick, false);
}
// 唯一の初期化
window.addEvent('load', onWindowLoad, true);
//]]
</script>
</head>
<body>
<div style="width:480px;height:240px;border:solid 1px Black;">
</div>
</body>
</html>
やっていることはシンプルです。
document オブジェクトに対してクリックイベントをひっかけ、そのイベントハンドラで alert でダイアログボックスを表示しているだけです。
Safari 以外のブラウザは、期待通り、document を1回クリックするごとに、1度だけダイアログ ボックスが表示されます。
ところが Safari だけは、一度 document をクリックしてしまうと、延々とダイアログ ボックスが出てきました。
ダイアログ ボックスを閉じても閉じても、閉じるたびに新しいダイアログ ボックスが立ち上がってしまい、しかもこのダイアログ ボックスはモーダルなので、正常なブラウザの終了ができなくなります。
俺の環境は Windows 7 ですが、こうなるとタスクバーから Safari を閉じるはめになります。
ほとんどブラクラ状態。
う~ん、なんでかなあ・・・・・・。
普通は、親ウィンドウとダイアログ ボックスの window インスタンスは違う(=当然 document インスタンスも違う)ので、ダイアログで [OK] や [×] ボタンを押したとしても、バブルアップでイベントが上がっていくのはダイアログ側の window までのはずです。
親ウィンドウの window や document はダイアログとは別物ですから、無関係のはずなんですが・・・・・・。
それとも、別の window 上のイベントも、親ウィンドウの document が(バブルアップではなく、領域が重なっているという観点で)拾っちゃうのかなあ?
やっぱり、俺の環境がおかしいのかなあ? それともスクリプトの書き方が悪い?
謎です。
とにかく、共通の処理で複数のブラウザに同じ挙動をさせたい場合、テストはしっかりやらないといけませんね。
スノーレパードのサファリVer5.0.3 (6533.19.4)では、document を1回クリックするごとに、1度だけダイアログ ボックスが表示されます。
が、テキストが文字化けしてましたぁ♪
スノーレパードのサファリVer5.0.3 (6533.19.4)より投稿。
(^ー^)/
by きゅんぱち (2010-12-15 01:40)
Windows7のサファリVer5.0.3 (7533.19.4)では、たしかにダイアログ ボックスを閉じても閉じても、閉じるたびに新しいダイアログ ボックスが立ち上がってしまいますねぇ。
タスクバーからタスクマネージャを立ち上げて強制終了ってところですね。
Windows7のサファリVer5.0.3 (7533.19.4)より投稿。
by きゅんぱち (2010-12-15 01:57)
エクスプローラ9BETAでは、逆にdocument を1回クリックしても何も反応がないですよ。
ダイアログボックス1個も出てこないでした。
Mac&Win7両刃使いのきゅんぱちとしては(苦笑)、サファリではWin7のほうが若干新しいリリースになっているのがひっかかりました。
何か仕様の変更があったんでしょうかね?
エクスプローラ9BETAより投稿。
(^-^)
by きゅんぱち (2010-12-15 02:04)
Windows7のXPMode上のie8ではdocument を1回クリックするごとに、1度だけダイアログ ボックスが表示されます。
Windows7のXPMode上のie8から投稿。
by きゅんぱち (2010-12-15 02:23)
みなさま、nice!&こめんとありがとうございます。
きゅんぱちさん!
いろいろな環境で動作を確認して頂き、レポートまで頂きまして、誠にありがとうございます!
文字化けの問題は、おそらく以下の3つの整合が取れれば、解消します。
1)コピペ元のこのページの文字コード
2)HTML に保存した時の文字コード
3)ブラウザで使用する文字コード
特に3)に関しては、HTML の中で指定するべきものですが、俺はものぐさなもので端折っちゃってます、いけない、いけない;;;。
IE9 では、イベント周りが大きく変わっているらしいので(なんと、addEventListener に対応するだとか!?)期待通りに動作しない可能性は充分あり得るなあ、と思いました。
この現象にカチ会うまでは、実は「Safari はかなり安定したブラウザだな」という印象を持っていました。
というわけで、けっこうバージョンアップとかでもノーマークだったんです;;;。
どういう理由で Windows が先行したのかは、俺にもわかりませんねえ・・・・・・。
もしわかったら、お知らせしますね。
by みみちゃん (2010-12-15 20:29)
いやぁ。きゅんぱち様みたいに凄いコメント各スキル無いんだけど、きっと、いつか、あ、みみしゃんプログラムの園に書いてあったと、気前酢ことがありますようにw
by One-for-you (2010-12-19 00:44)
どうぞ、気楽に気長におつきあいください♪
by みみちゃん (2010-12-19 11:29)
うーん、イベント追加・削除、ウインドウロード・Unロード、イニシャル、スクリプト終了の流れなんですよね、年で終わらないんだろう?
by One-for-you (2010-12-21 22:22)