SSブログ

ほとんどイヤがらせ for Safari Only [JavaScript]

◆ほとんどイヤがらせ for Safari Only

今回は、俺が自分の環境で経験した、JavaScript のユーザーエージェント(ブラウザ)ごとに異なる挙動の一例です。

手元の環境で、Internet ExplorerFirefoxOperaSafariGoogle Chrome の中で、(環境や OS にもよると思いますが)Safari を除くブラウザは普通に動いてくれるのに、 Safari だけ「ほとんどイヤがらせ」になってしまった例を紹介します。

なお、今回のエントリーは、Safari の性能や機能に対する批判が目的ではありません。

Safari が特別劣ったブラウザとも思っていません。

これは、俺が開発中に、俺の環境でたまたま発生した事例であって、他の環境では発生しないかもしれないし、あるいは他のブラウザでも、まだ俺の知らない深刻な問題があるかもしれませんし。

その点をご理解の上、お読み頂ければと思います。

◆今回のひとこと

(俺の環境では)Safari のイベントハンドラの実装には気をつけろ!

document onclick イベントをひっかけて alert を出す処理を書いたら、Safari(5.0.3)だけ、永遠にダイアログ ボックスが開き続ける「ほとんどイヤがらせ」な代物ができちゃいました;;;。

他のブラウザ(Internet ExplorerFirefoxOperaGoogle 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 が(バブルアップではなく、領域が重なっているという観点で)拾っちゃうのかなあ?

やっぱり、俺の環境がおかしいのかなあ? それともスクリプトの書き方が悪い?

謎です。

とにかく、共通の処理で複数のブラウザに同じ挙動をさせたい場合、テストはしっかりやらないといけませんね。


nice!(5)  コメント(8)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 5

コメント 8

きゅんぱち

スノーレパードのサファリ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) 

One-for-you

いやぁ。きゅんぱち様みたいに凄いコメント各スキル無いんだけど、きっと、いつか、あ、みみしゃんプログラムの園に書いてあったと、気前酢ことがありますようにw
by One-for-you (2010-12-19 00:44) 

みみちゃん

どうぞ、気楽に気長におつきあいください♪
by みみちゃん (2010-12-19 11:29) 

One-for-you

うーん、イベント追加・削除、ウインドウロード・Unロード、イニシャル、スクリプト終了の流れなんですよね、年で終わらないんだろう?
by One-for-you (2010-12-21 22:22) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。