web-dev-qa-db-ja.com

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

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

var newWin = window.open(url);

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

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

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

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

Edit:私は今、newWin.outerHeightnewWin.left、およびこれを実現する他の同様のプロパティ。 Google Chromeは、ポップアップがブロックされると、すべての位置と高さの値を0として返します。

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

100
Andrew Ensley

あなたが言う「魔法の時間」は、おそらくポップアップのDOMがロードされたときです。または、すべて(画像、外部CSSなど)が読み込まれたときかもしれません。ポップアップに非常に大きなグラフィックを追加することで、これを簡単にテストできます(最初にキャッシュをクリアしてください!)。 jQuery(または同様のもの)などのJavascriptフレームワークを使用している場合、ready()イベント(または同様のもの)を使用して、DOMがロードされるのを待ってからウィンドウオフセットをチェックできます。これの危険性は、Safariの検出が競合する方法で動作することです:ポップアップのDOMは、実際に開くかどうかに関係なく、開こうとしているウィンドウの有効なハンドルを提供するため、Safariで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秒の読み込みを与えます。子ウィンドウで、テスト関数を追加する必要があります。

機能テスト() {}

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

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

お役に立てれば。

63
Ringo

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

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

以下は、ポップアップブロッカーチェックの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);

お役に立てれば! :)

12
Kevin B

Richの答えは、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の後でも、失敗したポップアップに対してゼロ以外の値を報告することがあります。私もこの動作を経験しましたが、ゼロmsのタイムアウト後にチェックを追加すると、screenXプロパティは常に一貫した値を出力するようです。

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

10
InvisibleBacon

これは私のために働いた:

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

OuterHeightとouterWidthは、chromeのためのものです。なぜなら、上記の 'about:blank'トリックはchromeではもう機能しないからです。

ここで提供されている答えをコピー/貼り付けます: 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.");
  }
}
4
Hamy

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

私が使用するコールバックアーキテクチャは、ポップアップがブロックされたときに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);
    }
};
2
pospi

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
}

undefinedを返す代わりにプロミスに失敗するようにコードを変更できます。iftry / catchこの場合。

2
kigiri

以下は、現在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
Kandelon

親に対するウィンドウの位置を確認します。 Chromeはウィンドウを表示しますほぼ画面外。

2
Jason Cohen

このフラグメントには上記のすべてが組み込まれています-何らかの理由で-StackOverflowは以下のコードブロックの最初と最後のコード行を除外しているので、ブログを書きました。完全な説明と残りの(ダウンロード可能な)コードについては、 mycode at thecodeabode.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
Ben

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の方法で賢明な人が他の人に違いをもたらす理由を伝えることができれば、私はそれを聞いてみたい。プログラムによるポップアップ。

2
Chris

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

答えは常に「はい」であるため、最近では「迷惑なポップアップがブロックされましたか?」という質問をする必要はありません。最良のアプローチは、ほとんどの場合に許可される直接クリックに対するwindow.open()への応答のみです。

1
bobince
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();
            } 
        };
    }
}
1
syed

こんにちは

上記のソリューションをわずかに変更し、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によって内部の高さが正しく設定されました。

変数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
Lars

(テストしたものから)わかる限り、Chromeは 'about:blank'の位置にあるウィンドウオブジェクトを返します。したがって、以下はすべてのブラウザで動作するはずです。

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