Chromeでブロックされたポップアップを検出する


103

他のブラウザでポップアップがブロックされているかどうかを検出するJavaScriptテクニックを知っています(この質問への回答で説明されています)。基本的なテストは次のとおりです。

var newWin = window.open(url);

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

ただし、これはChromeでは機能しません。ポップアップがブロックされていると、「ポップアップブロック」セクションに到達しません。

もちろん、Chromeは実際にはポップアップをブロックしないため、テストはある程度機能していますが、「ブロックされた」ポップアップをリストする右下の小さな最小化されたウィンドウで開きます。

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

編集:私は今を利用して試してみましたがnewWin.outerHeightnewWin.left、および他の同様の特性は、これを達成するために。Google Chromeは、ポップアップがブロックされると、すべての位置と高さの値を0として返します。

残念ながら、ポップアップが実際に未知の時間開かれたとしても、同じ値を返します。魔法の期間(私のテストでは数秒)の後、場所とサイズの情報が正しい値として返されます。言い換えれば、私はまだこれを理解することに近づいていません。任意の助けいただければ幸いです。


Yoav、ポップアップがブロックされているかどうかに関係なく、場所は同じです。他の誰かが、ユーザーに3.5秒待機させることを含まない答えを持っていますか?

InvisibleBaconおよびAndyの最新のソリューションがChrome 10で機能しない:テストポップアップが正常に表示された場合でも、「Chromeに失敗しました」というメッセージが表示されます。何か案が?

これらのソリューションの一部はChromeの初期バージョンでしか機能しないように見えるため、新しい質問が必要になると思います。
ブライアンフィールド

1
@George Bailey私も同意しますが、明確にするために、現在のバージョンのChrome(19)で動作するものもあります。AndrewのouterHeight(またはscreenX、他の人が示唆している)を使用するという当初のアイデアは、setTimeoutアプローチと組み合わせるとうまく機能します。しかし、そうです、私が自分でテストするまで、これらすべての答えを理解しようとすることは本当に混乱しました。
regularmike、2012年

これを試してください:stackoverflow.com/a/31299484/1927014
Vlada

回答:


66

まあ、あなたが言う「魔法の時間」は、ポップアップのDOMがロードされたときでしょう。あるいは、すべて(画像、外部CSSなど)がロードされたときかもしれません。非常に大きなグラフィックをポップアップに追加することでこれを簡単にテストできます(最初にキャッシュをクリアしてください!)jQuery(または類似のもの)のようなJavascriptフレームワークを使用している場合、ready()イベント(または類似のもの)を使用して、ウィンドウオフセットをチェックする前にDOMがロードされるのを待ちます。これの危険性は、Safariの検出が競合する方法で機能することです。ポップアップのDOMは、実際に開くかどうかに関係なく、開こうとしているウィンドウの有効なハンドルを提供するため、Safariでready()になることはありません。ない。(実際、上記のポップアップテストコードはSafariでは機能しないと思います。)

私ができる最善のことは、テストを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秒の読み込み時間を与えることです。子ウィンドウで、テスト関数を追加する必要があります。

機能テスト() {}

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

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)
}); 

お役に立てれば。


リッチ、あなたはJavaScriptポップアップの第一人者です。ありがとうございました。それがまさに私が必要としていたことです。
Andrew Ensley

4
これに関する更新はありますか?動作しなくなったようです...特にChrome
Chris Wagner

新しいバージョンのChromeでこれを機能させる方法を見つけたと思います。詳細については、私の回答を参照してください。
InvisibleBacon

2
基本的に、Chromeにはバグがあります。ポップアップを非表示にしますが、それでも実行され、ウィンドウオブジェクトが返されます。そのため、定期的なチェックは機能しません。これが私のために働いた解決策です:var popup = window.open(url); if(popup){popup.onload = function(){console.log(popup.innerHeight> 0? 'open': 'blocked'); }} else {console.log( 'blocked'); ここでの動作例:jsbin.com/uticev/3
Remy Sharp

1
この回答は正しくありません。@ PredragStojadinovićの回答に変更してください
Lucas B

16

InvisibleBaconのスニペット(IE9、Safari 5、Chrome 9およびFF 3.6でテスト済み)の1つの改善点:

var myPopup = window.open("popupcheck.htm", "", "directories=no,height=150,width=150,menubar=no,resizable=no,scrollbars=no,status=no,titlebar=no,top=0,location=no");
if (!myPopup)
    alert("failed for most browsers");
else {
    myPopup.onload = function() {
        setTimeout(function() {
            if (myPopup.screenX === 0) {
                alert("failed for chrome");
            } else {
                // close the test window if popups are allowed.
                myPopup.close();  
            }
        }, 0);
    };
}

ポップアップが許可されているのに、なぜウィンドウを閉じるのですか?そもそもあなたが開きたいと思っていたポップアップを閉じていませんか?
elemjay19 2012

3
onloadの代わりにjQueryを使用して、$(myPopup).ready()を実行します。ローカルでのIEの実行は速すぎ、 "onload"は既に発生しています。
Matt Connolly

12

以下は、ポップアップブロッカーチェックに対するjQueryソリューションです。FF(v11)、Safari(v6)、Chrome(v23.0.127.95)、IE(v7&v9)でテストされています。_displayError関数を更新して、必要に応じてエラーメッセージを処理します。

var popupBlockerChecker = {
        check: function(popup_window){
            var _scope = this;
            if (popup_window) {
                if(/chrome/.test(navigator.userAgent.toLowerCase())){
                    setTimeout(function () {
                        _scope._is_popup_blocked(_scope, popup_window);
                     },200);
                }else{
                    popup_window.onload = function () {
                        _scope._is_popup_blocked(_scope, popup_window);
                    };
                }
            }else{
                _scope._displayError();
            }
        },
        _is_popup_blocked: function(scope, popup_window){
            if ((popup_window.innerHeight > 0)==false){ scope._displayError(); }
        },
        _displayError: function(){
            alert("Popup Blocker is enabled! Please add this site to your exception list.");
        }
    };

使用法:

var popup = window.open("http://www.google.ca", '_blank');
popupBlockerChecker.check(popup);

お役に立てれば!:)


これは本当に役に立ちます。共有いただきありがとうございます。
Suvendu Shekhar Giri、

ようこそスベンドゥさん、お役に立てて嬉しいです!幸せなコーディング!:)
ケビンB

1
このコードを微調整して、開こうとしているURLの内部/周辺を渡します。これにより、_displayError()メソッドは、問題があることをユーザーに通知するアラート(私はtoastrを使用)を表示し、直接リンクであるためほとんどのブロッカーを回避するクリック可能なリンクを提供できます。共有してくれてありがとう!
タイラーフォーサイス

@TylerForsytheあなたはあなたのソリューションについてもっと情報がありますか?コンテンツへの直接クリック可能なリンクを提供できるようになりたいです。
ジョシュアダンス

1
@JoshuaDanceこれは、変更したコードとそれを呼び出す方法を示すために作成した要点です。それが役に立てば幸い! gist.github.com/tylerforsythe/452ceaad62f507d7cb7bd7ddbffe650c
Tyler Forsythe

10

リッチの答えは、Chromeではもう機能しません。Chromeがポップアップウィンドウで実際にJavascriptを実行しているようです。ブロックされたポップアップをチェックするために、screenX値0をチェックすることになりました。チェックする前に、このプロパティが最終的なものであることを保証する方法も見つけたと思います。これはドメインのポップアップでのみ機能しますが、次のようなonloadハンドラーを追加できます。

var myPopup = window.open("site-on-my-domain", "screenX=100");
if (!myPopup)
    alert("failed for most browsers");
else {
    myPopup.onload = function() {
        setTimeout(function() {
            if (myPopup.screenX === 0)
                alert("failed for chrome");
        }, 0);
    };
}

多くの人が報告したように、 "screenX"プロパティは、onloadの後でも、失敗したポップアップに対してゼロ以外を報告することがあります。私もこの動作を経験しましたが、0ミリ秒のタイムアウト後にチェックを追加すると、screenXプロパティは常に一貫した値を出力するように見えます。

このスクリプトをより堅牢にする方法があるかどうか教えてください。私の目的のために働くようですが。


それは私のためではなく、onload決して発砲しません。

9

これは私のために働きました:

    cope.PopupTest.params = 'height=1,width=1,left=-100,top=-100,location=no,toolbar=no,menubar=no,scrollbars=no,resizable=no,directories=no,status=no';
    cope.PopupTest.testWindow = window.open("popupTest.htm", "popupTest", cope.PopupTest.params);

    if( !cope.PopupTest.testWindow
        || cope.PopupTest.testWindow.closed
        || (typeof cope.PopupTest.testWindow.closed=='undefined')
        || cope.PopupTest.testWindow.outerHeight == 0
        || cope.PopupTest.testWindow.outerWidth == 0
        ) {
        // pop-ups ARE blocked
        document.location.href = 'popupsBlocked.htm';
    }
    else {
        // pop-ups are NOT blocked
        cope.PopupTest.testWindow.close();
    }

上からの「about:blank」トリックがChromeで機能しないため、outerHeightとouterWidthはChrome用です。


1
クロームの変更を十分に把握しており、ここで更新していただきありがとうございます。あなたの答えは正しいとマークする必要があります。
Lucas B

outerWidthとouterHeightはChromeでも機能しません
Roman

5

ここに提供されている回答をコピー/貼り付けます:https : //stackoverflow.com/a/27725432/892099 by DanielB。chrome 40で動作し、非常にクリーンです。汚いハックや待機は含まれません。

function popup(urlToOpen) {
  var popup_window=window.open(urlToOpen,"myWindow","toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=yes, width=400, height=400");            
  try {
    popup_window.focus();   
  }
  catch (e) {
    alert("Pop-up Blocker is enabled! Please add this site to your exception list.");
  }
}

3

どの程度Promiseのアプローチ?

const openPopUp = (...args) => new Promise(s => {
  const win = window.open(...args)
  if (!win || win.closed) return s()
  setTimeout(() => (win.innerHeight > 0 && !win.closed) ? s(win) : s(), 200)
})

そして、あなたは古典のようにそれを使うことができます window.open

const win = await openPopUp('popuptest.htm', 'popuptest')
if (!win) {
  // popup closed or blocked, handle alternative case
}

returnの代わりにpromiseが失敗するようにコードを変更することもできます。これは、この場合よりも簡単な制御フローundefinedだと思いました。iftry / catch


これは、Chrome拡張アドブロッカーを検出するために機能します。+1
Micheal C Wallas

2

親を基準にしたウィンドウの位置を確認します。Chromeでは、ウィンドウがほとんど画面外に表示されます。


私はそれを試して、あなたに私の結果を知らせます。ありがとう。
Andrew Ensley 2009年

Google Chromeは、ポップアップが「ブロックされている」場合、左と上のオフセットを0として報告します。これは私のゴールデンチケットだと思いましたが、違います。実際に開いた直後にも、オフセットは0として報告されます。開いた後の不思議な時点で、上と左のオフセットが正しく報告されます。
Andrew Ensley 2009年

チェックする前にオフセットが設定されていることを保証するように見える方法について私の投稿をチェックしてください。
InvisibleBacon

2

Chromeでポップアップが開かないという同様の問題がありました。ユーザーがクリックしたときにウィンドウを開くだけで、onloadポップアップのような卑劣なことをしようとしていなかったので、私は苛立ちました。firebugコマンドラインからwindow.open()を含む関数を実行しても機能し、実際にリンクをクリックしても機能しなかったため、私は二重に不満を感じていました。これが私の解決策です:

間違った方法:イベントリスナーからwindow.open()を実行しています(私の場合、DOMノードのonclickイベントメソッドにdojo.connectを実行しています)。

dojo.connect(myNode, "onclick", function() {
    window.open();
}

正しい方法:window.open()を呼び出したノードのonclickプロパティに関数を割り当てる。

myNode.onclick = function() {
    window.open();
}

そしてもちろん、必要に応じて、同じonclickイベントのイベントリスナーを実行することもできます。この変更により、Chromeが「どのサイトにもポップアップの表示を許可しない」に設定されていても、ウィンドウを開くことができました。喜び。

Chromeの使い方を賢く知っている人が私たちに影響を与える理由を教えてくれるなら、ぜひ聞いてみたいと思いますが、これは悪意のあるプログラムによるポップアップへの扉を閉めるための試みにすぎないと思われます。


ソリューションを共有していただきありがとうございます。できます。これは、Chromeでポップアップを開くための最良かつ最もクリーンな方法です。あなたの答えはトップでなければなりません。残りの解決策は、単に「ダーティ」なハックです。
Mandeep Janjua 2013

2

こちらが現在Chromeで動作しているバージョンです。Richのソリューションを少し変更しただけですが、タイミングを処理するラッパーも追加しました。

function checkPopupBlocked(poppedWindow) {
 setTimeout(function(){doCheckPopupBlocked(poppedWindow);}, 5000);
}

function doCheckPopupBlocked(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.outerWidth == 0) {
            // This is usually Chrome's doing. The outerWidth (and most other size/location info)
         // will be left at 0, EVEN THOUGH the contents of the popup will exist (including the
         // test function we check for next). The outerWidth starts as 0, so a sufficient delay
         // after attempting to pop is needed.
            result = true;
        }
        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);
        //}
    }

    if(result)
     alert("The popup was blocked. You must allow popups to use this site.");
}

使用するには、次のようにします。

var popup=window.open('location',etc...);
checkPopupBlocked(popup);

ポップアップがブロックされると、警告メッセージが5秒の猶予期間の後に表示されます(これは調整できますが、5秒で十分安全です)。


2

このフラグメントは上記のすべてを組み込んでいます-何らかの理由で-StackOverflowは以下のコードブロックのコードの最初と最後の行を除外しているので、私はそれにブログを書きました。完全な説明と残りの(ダウンロード可能な)コードについては、 codeabode.blogspot.comにある私のブログを参照してください。

var PopupWarning = {

    init : function()
    {

        if(this.popups_are_disabled() == true)
        {
            this.redirect_to_instruction_page();
        }
    },

    redirect_to_instruction_page : function()
    {
        document.location.href = "http://thecodeabode.blogspot.com";
    },

    popups_are_disabled : function()
    {
        var popup = window.open("http://localhost/popup_with_chrome_js.html", "popup_tester", "width=1,height=1,left=0,top=0");

        if(!popup || popup.closed || typeof popup == 'undefined' || typeof popup.closed=='undefined')
        {
            return true;
        }

        window.focus();
        popup.blur();

        //
        // Chrome popup detection requires that the popup validates itself - so we need to give
        // the popup time to load, then call js on the popup itself
        //
        if(navigator && (navigator.userAgent.toLowerCase()).indexOf("chrome") > -1)
        {
            var on_load_test = function(){PopupWarning.test_chrome_popups(popup);};     
            var timer = setTimeout(on_load_test, 60);
            return;
        }


        popup.close();
        return false;
    },

    test_chrome_popups : function(popup)
    {
        if(popup && popup.chrome_popups_permitted && popup.chrome_popups_permitted() == true)
        {
            popup.close();
            return true;
        }

        //
        // If the popup js fails - popups are blocked
        //
        this.redirect_to_instruction_page();
    }
};

PopupWarning.init();

2

ここには多くの解決策があります。これは私のものであり、現在受け入れられている回答(最新のChromeでは機能せず、タイムアウトでラップする必要がある)から取得したソリューションと、このスレッドの関連ソリューションを使用します(実際にはjQueryではなくバニラJSです)を使用しています。 。

Mineはtrue、ポップアップがブロックされたときに送信されるコールバックアーキテクチャを使用しますfalse

window.isPopupBlocked = function(popup_window, cb)
{
    var CHROME_CHECK_TIME = 2000;       // the only way to detect this in Chrome is to wait a bit and see if the window is present

    function _is_popup_blocked(popup)
    {
        return !popup.innerHeight;
    }

    if (popup_window) {
        if (popup_window.closed) {
            // opened OK but was closed before we checked
            cb(false);
            return;
        }
        if (/chrome/.test(navigator.userAgent.toLowerCase())) {
            // wait a bit before testing the popup in chrome
            setTimeout(function() {
                cb(_is_popup_blocked(popup_window));
            }, CHROME_CHECK_TIME);
        } else {
            // for other browsers, add an onload event and check after that
            popup_window.onload = function() {
                cb(_is_popup_blocked(popup_window));
            };
        }
    } else {
        cb(true);
    }
};

1

ジェイソンの答えも私が考えることができる唯一の方法ですが、そのような立場に頼ることは少し危険です!

答えは常に「はい」なので、「未承諾のポップアップはブロックされましたか?」という質問をする必要はありません。すべての主要なブラウザーでデフォルトでポップアップブロッカーがオンになっています。最善の方法は、ほとんど常に許可されている直接クリックに応じてwindow.open()を呼び出すことだけです。


2
私はベストプラクティスなどを知っていますが、このタスクを実行する必要がある状況にあります。それが私がこの質問をした理由であり、「私がすべきですか」ではありません。
Andrew Ensley 2009年

1

こんにちは

上記の解決策を少し変更し、少なくともChromeで機能していると思います。私の解決策は、ポップアップが開かれたときではなく、メインページが開かれたときにポップアップがブロックされているかどうかを検出するように作成されていますが、それを変更できる人がいると思います。:-)ここでの欠点は、ポップアップウィンドウが表示されることです。ポップアップブロッカーがない場合、数秒間(少し短くすることが可能な場合があります)。

これを「メイン」ウィンドウのセクションに配置しました

<script type="text/JavaScript" language="JavaScript">

 var mine = window.open('popuptest.htm','popuptest','width=1px,height=1px,left=0,top=0,scrollbars=no');
 if(!mine|| mine.closed || typeof mine.closed=='undefined')
  {
    popUpsBlocked = true       
    alert('Popup blocker detected ');
    if(mine)
      mine.close();
 }
 else
 {
    popUpsBlocked = false    
    var cookieCheckTimer = null;
    cookieCheckTimer =  setTimeout('testPopup();', 3500);
 }


function testPopup()
{
  if(mine)
  {
    if(mine.test())
    {
       popUpsBlocked = false;
    }
    else
    {
        alert('Popup blocker detected ');
         popUpsBlocked = true;
     }
    mine.close();
}

} 
</script>

popuptestは次のようになります。

<!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>Popup test</title>
<script type="text/javascript" language="Javascript">
   function test() {if(window.innerHeight!=0){return true;} else return false;}
</script>
</head>

<body>
</body>
</html>

3500ミリ秒後にポップアップページのテスト関数を呼び出すと、Chromeによってinnerheightが正しく設定されました。

変数popUpsBlockedを使用して、他のJavaScriptでポップアップが表示されるかどうかを確認します。すなわち

function ShowConfirmationMessage()
{
if(popUpsBlocked)
 { 
  alert('Popups are blocked, can not display confirmation popup. A mail will be sent with the confirmation.');
 } 
 else
 { 
  displayConfirmationPopup();
 }
 mailConfirmation();
}

残念ながら、これはポップアップしようとしているページが私たちによって制御されていることを前提としています。自分が制御できない外部ページを開く必要があります。
ローマン

1
function openPopUpWindow(format)
{   
    var win = window.open('popupShow.html',
                          'ReportViewer',
                          'width=920px,height=720px,left=50px,top=20px,location=no,directories=no,status=no,menubar=no,toolbar=no,resizable=1,maximize:yes,scrollbars=0');

    if (win == null || typeof(win) == "undefined" || (win == null && win.outerWidth == 0) || (win != null && win.outerHeight == 0) || win.test == "undefined") 
    {
        alert("The popup was blocked. You must allow popups to use this site.");  
    }
    else if (win)
    {
        win.onload = function()
        {          
            if (win.screenX === 0) {
                alert("The popup was blocked. You must allow popups to use this site.");
                win.close();
            } 
        };
    }
}

0

私が知る限り(私がテストしたものから)、Chromeは「about:blank」の場所を持つウィンドウオブジェクトを返します。したがって、以下はすべてのブラウザーで機能するはずです。

var newWin = window.open(url);
if(!newWin || newWin.closed || typeof newWin.closed=='undefined' || newWin.location=='about:blank')
{
    //POPUP BLOCKED
}

ブロックされていないポップアップでも、場所は「about:blank」のままです。私はChrome v28.0.1500.72でテストしました
ローマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.