1. ホーム
  2. javascript

[解決済み] Chromeでブロックされたポップアップを検出する

2022-12-20 12:23:26

質問

私は、ポップアップが他のブラウザでブロックされているかどうかを検出する javascript のテクニックを知っています ( この質問に対する答え ). ここに基本的なテストがあります。

var newWin = window.open(url);

if(!newWin || newWin.closed || typeof newWin.closed=='undefined')
{
    //POPUP BLOCKED
}

しかし、これはChromeではうまくいきません。 ポップアップがブロックされると、"POPUP BLOCKED"セクションに到達することはありません。

もちろん、Chrome は実際にはポップアップをブロックしませんが、右下隅の小さな最小化されたウィンドウでポップアップを開き、ブロックされたポップアップを一覧表示するので、テストはある程度うまくいっています。

私がやりたいことは、ポップアップが Chrome のポップアップ ブロッカーによってブロックされたかどうかを判断できるようにすることです。 私は、機能検出を優先して、ブラウザーのスニッフィングを避けようとしています。ブラウザーのスニッフィングなしでこれを行う方法はありますか?

編集 : 現在、私は newWin.outerHeight , newWin.left などのプロパティを使って実現します。 Google Chromeは、ポップアップがブロックされた場合、すべてのpositionとheightの値を0として返します。

残念ながら、ポップアップが未知の時間実際に開かれた場合でも、同じ値が返されます。 いくつかの魔法のような期間 (私のテストでは数秒) の後、位置とサイズの情報は正しい値として返されます。 つまり、まだ解明には至っていないのです。 どのようなヘルプでもかまいません。

どのように解決するのですか?

あなたが言う「魔法の時間」とは、おそらくポップアップの DOM が読み込まれたときのことでしょう。あるいは、すべてのもの (画像、外部 CSS など) が読み込まれたときかもしれません。非常に大きなグラフィックをポップアップに追加することで簡単にテストすることができます (最初にキャッシュをクリアしてください!)。jQueryのようなJavascriptフレームワークを使用している場合、ready()イベント(または同様のもの)を使用して、ウィンドウオフセットをチェックする前にDOMがロードされるのを待つことができます。この場合の危険は、Safariの検出が相反する方法で動作することです。SafariではポップアップのDOMは決してready()にならず、開こうとしているウィンドウの有効なハンドルが与えられるため、それが実際に開くかどうかにかかわらず、です。(実際、上記のポップアップのテストコードはサファリでは動作しないと思います。)

あなたができる最善のことは、テストをsetTimeout()でラップして、テストを実行する前にポップアップの読み込みを完了するために3-5秒を与えることだと思います。これは完璧ではありませんが、少なくとも 95% の時間で動作するはずです。

以下は、私がクロスブラウザ検出に使用しているコードで、Chromeの部分を除いたものです。

function _hasPopupBlocker(poppedWindow) {
    var result = false;

    try {
        if (typeof poppedWindow == 'undefined') {
            // Safari with popup blocker... leaves the popup window handle undefined
            result = true;
        }
        else if (poppedWindow && poppedWindow.closed) {
            // This happens if the user opens and closes the client window...
            // Confusing because the handle is still available, but it's in a "closed" state.
            // We're not saying that the window is not being blocked, we're just saying
            // that the window has been closed before the test could be run.
            result = false;
        }
        else if (poppedWindow && poppedWindow.test) {
            // This is the actual test. The client window should be fine.
            result = false;
        }
        else {
            // Else we'll assume the window is not OK
            result = true;
        }

    } catch (err) {
        //if (console) {
        //    console.warn("Could not access popup window", err);
        //}
    }

    return result;
}

私が行うことは、親からこのテストを実行し、それを setTimeout() でラップして、子ウィンドウがロードするのに3-5秒を与えることです。子ウィンドウでは、テスト関数を追加する必要があります。

関数 test() {}

ポップアップブロッカー検出器は、"test"関数が子ウィンドウのメンバーとして存在するかどうかを確認するためにテストします。

2015年6月15日に追加されました。

現代的な対処法としては、window.postMessage()を使って、子から親にウィンドウがロードされたことを通知させるのが良いかと思います。アプローチは似ていますが (子が親にロードされたことを伝える)、通信手段は改善されています。私はこれを子からクロスドメインで行うことができました。

$(window).load(function() {
  this.opener.postMessage({'loaded': true}, "*");
  this.close();
});

親は、このメッセージを使用してリッスンします。

$(window).on('message', function(event) {     
  alert(event.originalEvent.data.loaded)
}); 

これが役立つといいのですが。