Rileva i popup bloccati in Chrome


103

Sono a conoscenza delle tecniche javascript per rilevare se un popup è bloccato in altri browser (come descritto nella risposta a questa domanda ). Ecco il test di base:

var newWin = window.open(url);

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

Ma questo non funziona in Chrome. La sezione "POPUP BLOCKED" non viene mai raggiunta quando il popup è bloccato.

Ovviamente, il test sta funzionando in una certa misura poiché Chrome in realtà non blocca il popup, ma lo apre in una piccola finestra ridotta a icona nell'angolo inferiore destro che elenca i popup "bloccati".

Quello che vorrei fare è sapere se il popup è stato bloccato dal blocco popup di Chrome. Cerco di evitare lo sniffing del browser a favore del rilevamento delle funzionalità. C'è un modo per farlo senza lo sniffing del browser?

Modifica : ora ho provato a utilizzarenewWin.outerHeight , newWin.lefte altre proprietà simili per raggiungere questo obiettivo. Google Chrome restituisce tutti i valori di posizione e altezza come 0 quando il popup è bloccato.

Sfortunatamente, restituisce gli stessi valori anche se il popup viene effettivamente aperto per un periodo di tempo sconosciuto. Dopo un periodo magico (un paio di secondi nel mio test), le informazioni sulla posizione e sulle dimensioni vengono restituite come valori corretti. In altre parole, non sono ancora più vicino a capirlo. Qualsiasi aiuto sarebbe apprezzato.


Yoav, la posizione mostra la stessa indipendentemente dal fatto che il popup sia bloccato o meno. Qualcun altro ha una risposta che non implica che l'utente attenda 3,5 secondi?

Le ultime soluzioni di InvisibleBacon e Andy non funzionano in Chrome 10: viene visualizzato il messaggio "failed for chrome" anche se il pop-up di prova è stato visualizzato correttamente. Qualche idea?

Penso che sarebbe necessaria una nuova domanda poiché alcune di queste soluzioni sembrano aver funzionato solo con le prime versioni di Chrome.
Bryan Field

1
@George Bailey Sono d'accordo, ma per essere chiari, alcuni di loro funzionano nella versione corrente di Chrome (19). L'idea originale di Andrew di usare outerHeight (o screenX, come altri hanno suggerito) sta funzionando bene per me, combinata con l'approccio setTimeout. Ma sì, cercare di dare un senso a tutte queste risposte è stato davvero fonte di confusione fino a quando non ho fatto i miei test.
regularmike

Risposte:


66

Ebbene, il "momento magico" di cui parli è probabilmente quando il DOM del popup è stato caricato. Oppure potrebbe essere quando tutto (immagini, CSS fuoribordo, ecc.) È stato caricato. Puoi testarlo facilmente aggiungendo un'immagine molto grande al popup (svuota prima la cache!). Se stavi usando un framework Javascript come jQuery (o qualcosa di simile), potresti usare l'evento ready () (o qualcosa di simile) per attendere il caricamento del DOM prima di controllare l'offset della finestra. Il pericolo in questo è che il rilevamento di Safari funzioni in modo conflittuale: il DOM del popup non sarà mai pronto () in Safari perché ti darà un handle valido per la finestra che stai cercando di aprire, indipendentemente dal fatto che si apra o non. (infatti, credo che il tuo codice di test popup sopra non funzionerà per Safari.)

Penso che la cosa migliore che puoi fare sia racchiudere il tuo test in un setTimeout () e dare al popup 3-5 secondi per completare il caricamento prima di eseguire il test. Non è perfetto, ma dovrebbe funzionare almeno il 95% delle volte.

Ecco il codice che utilizzo per il rilevamento cross-browser, senza la parte 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;
}

Quello che faccio è eseguire questo test dal genitore e avvolgerlo in un setTimeout (), dando alla finestra figlio 3-5 secondi per il caricamento. Nella finestra figlio, è necessario aggiungere una funzione di test:

test di funzionalita() {}

Il rilevatore di blocco dei popup verifica se la funzione "test" esiste come membro della finestra figlia.

AGGIUNTO 15 GIUGNO 2015:

Penso che il modo moderno per gestirlo sarebbe usare window.postMessage () per fare in modo che il bambino notifichi al genitore che la finestra è stata caricata. L'approccio è simile (il bambino dice al genitore che è caricato), ma i mezzi di comunicazione sono migliorati. Sono stato in grado di eseguire questo cross-domain dal bambino:

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

Il genitore ascolta questo messaggio usando:

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

Spero che questo ti aiuti.


Ricco, sei un guru dei popup javascript. Grazie. È esattamente quello di cui avevo bisogno.
Andrew Ensley,

4
Eventuali aggiornamenti su questo? Non sembra funzionare più ... In particolare in Chrome
Chris Wagner

Penso di aver trovato un modo per farlo funzionare per le nuove versioni di Chrome. Vedi la mia risposta per i dettagli.
InvisibleBacon

2
Fondamentalmente c'è un bug in Chrome. Sebbene nasconda il popup, viene comunque eseguito e si ottiene ancora l'oggetto finestra, quindi i controlli regolari non funzionano. Ecco la soluzione che ha funzionato per me: var popup = window.open (url); if (popup) {popup.onload = function () {console.log (popup.innerHeight> 0? 'open': 'locked'); }} else {console.log ('bloccato'); } Esempio di lavoro qui: jsbin.com/uticev/3
Remy Sharp

1
Questa risposta non è più corretta, per favore cambiala con la risposta di @Predrag Stojadinović
Lucas B

16

Solo un miglioramento allo snipet di InvisibleBacon (testato in IE9, Safari 5, Chrome 9 e 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);
    };
}

Perché chiudere la finestra se i popup sono consentiti? non sarebbe chiudere il popup che volevi aprire in primo luogo?
elemjay19

3
Usando jQuery, invece di onload, farei $ (myPopup) .ready (). L'esecuzione locale del mio IE era troppo veloce e "onload" si era già verificato.
Matt Connolly

12

Quella che segue è una soluzione jQuery per il controllo del blocco dei popup. È stato testato in FF (v11), Safari (v6), Chrome (v23.0.127.95) e IE (v7 e v9). Aggiorna la funzione _displayError per gestire il messaggio di errore come meglio credi.

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

Uso:

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

Spero che questo ti aiuti! :)


Questo è davvero utile. Grazie per la condivisione.
Suvendu Shekhar Giri

Il tuo benvenuto Suvendu, sono contento che tu l'abbia trovato utile! Buona programmazione! :)
Kevin B

1
Ho modificato questo codice per passare dentro / intorno all'URL che sta tentando di essere aperto. Ciò consente al metodo _displayError () di visualizzare un avviso (sto usando toastr) che notifica all'utente che c'è un problema e fornisce un collegamento cliccabile che aggirerà la maggior parte dei blocchi poiché è un collegamento diretto. Grazie per la condivisione!!
Tyler Forsythe

@TylerForsythe hai altre informazioni sulla tua soluzione? Mi piacerebbe poter fornire un collegamento cliccabile direttamente al contenuto.
Joshua Dance,

1
@JoshuaDance Ecco una sintesi che ho appena creato per dimostrare il mio codice modificato e come lo invoco. Spero che sia d'aiuto! gist.github.com/tylerforsythe/452ceaad62f507d7cb7bd7ddbffe650c
Tyler Forsythe,

10

La risposta di Rich non funzionerà più per Chrome. Sembra che Chrome esegua effettivamente qualsiasi Javascript nella finestra popup ora. Ho finito per verificare un valore screenX pari a 0 per verificare la presenza di popup bloccati. Penso anche di aver trovato un modo per garantire che questa proprietà sia definitiva prima del controllo. Funziona solo per i popup sul tuo dominio, ma puoi aggiungere un gestore di onload come questo:

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

Come molti hanno riportato, la proprietà "screenX" a volte riporta un valore diverso da zero per i popup non riusciti, anche dopo l'onload. Ho riscontrato anche questo comportamento, ma se aggiungi il controllo dopo un timeout di zero ms, la proprietà screenX sembra sempre restituire un valore coerente.

Fammi sapere se ci sono modi per rendere questo script più robusto. Sembra però funzionare per i miei scopi.


Non per me, onloadnon spara mai.
foglia

9

Questo ha funzionato per me:

    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 e outerWidth sono per chrome perché il trucco "about: blank" dall'alto non funziona più in chrome.


1
Buona presa sulle modifiche di Chrome e grazie per l'aggiornamento qui. La tua risposta dovrebbe essere contrassegnata come corretta.
Lucas B

La larghezza esterna e l'altezza esterna non funzionano più neanche in Chrome
Roman

5

Copierò / incollerò semplicemente la risposta fornita qui: https://stackoverflow.com/a/27725432/892099 di DanielB. funziona su Chrome 40 ed è molto pulito. nessun trucco sporco o attesa comporta.

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

Che ne dici di un Promiseapproccio?

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

E puoi usarlo come il classico window.open

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

Potresti cambiare il codice in modo che fallisca la promessa invece di tornare undefined, ho solo pensato che iffosse un flusso di controllo più semplice rispetto try / catcha questo caso.


Funziona per rilevare gli adblocker delle estensioni di Chrome. +1
Micheal C Wallas

2

Controlla la posizione della finestra rispetto al genitore. Chrome fa apparire la finestra quasi fuori dallo schermo.


Lo proverò e ti farò sapere i miei risultati. Grazie.
Andrew Ensley,

Google Chrome segnala gli offset sinistro e superiore come 0 quando il popup è "bloccato". Pensavo fosse il mio biglietto d'oro, ma no. Riporta anche gli offset come 0 immediatamente dopo l'apertura effettiva. In un momento magico in futuro dopo l'apertura, gli offset in alto e a sinistra vengono riportati correttamente.
Andrew Ensley

Controlla il mio post per un modo che sembra garantire che gli offset siano impostati prima del controllo.
InvisibleBacon

2

Ho avuto un problema simile con i popup che non si aprivano in Chrome. Ero frustrato perché non stavo cercando di fare qualcosa di subdolo, come un popup di caricamento, semplicemente aprendo una finestra quando l'utente faceva clic. Ero DOPPIO frustrato perché l'esecuzione della mia funzione che includeva window.open () dalla riga di comando di firebug funzionava, mentre in realtà non facevo clic sul mio collegamento! Ecco la mia soluzione:

Modo sbagliato: eseguire window.open () da un listener di eventi (nel mio caso, dojo.connect al metodo dell'evento onclick di un nodo DOM).

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

Modo giusto: assegnare una funzione alla proprietà onclick del nodo che ha chiamato window.open ().

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

E, naturalmente, posso ancora creare listener di eventi per lo stesso evento onclick, se necessario. Con questa modifica, potevo aprire le mie finestre anche se Chrome era impostato su "Non consentire a nessun sito di mostrare popup". Gioia.

Se qualcuno saggio nei modi di Chrome può dire al resto di noi perché fa la differenza, mi piacerebbe sentirlo, anche se sospetto che sia solo un tentativo di chiudere la porta a popup programmatici dannosi.


Grazie per aver condiviso la tua soluzione. Funziona. Questo è il modo migliore e più pulito per aprire i popup in Chrome. La tua risposta dovrebbe essere in cima. Il resto delle soluzioni sono solo hack "sporchi".
Mandeep Janjua

2

Ecco una versione che attualmente funziona in Chrome. Solo una piccola modifica rispetto alla soluzione di Rich, anche se ho aggiunto un involucro che gestisce anche i tempi.

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

Per usarlo basta fare questo:

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

Se il popup viene bloccato, il messaggio di avviso verrà visualizzato dopo il periodo di tolleranza di 5 secondi (è possibile modificarlo, ma 5 secondi dovrebbero essere abbastanza sicuri).


2

Questo frammento incorpora tutto quanto sopra - Per qualche motivo - StackOverflow esclude la prima e l'ultima riga di codice nel blocco di codice sottostante, quindi ho scritto un blog su di esso. Per una spiegazione completa e il resto del codice (scaricabile) dai un'occhiata al mio blog su 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

Wow, ci sono sicuramente molte soluzioni qui. Questo è mio, utilizza soluzioni prese dalla risposta attualmente accettata (che non funziona nell'ultimo Chrome e richiede di avvolgerlo in un timeout), nonché una soluzione correlata su questo thread (che in realtà è JS vanilla, non jQuery) .

Il mio utilizza un'architettura di callback che verrà inviata truequando il popup viene bloccato e in falsealtro modo.

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

La risposta di Jason è l'unico metodo a cui riesco a pensare, ma affidarmi a una posizione del genere è un po 'rischioso!

In questi giorni, non hai davvero bisogno di porre la domanda "il mio popup non richiesto è stato bloccato?", Perché la risposta è invariabilmente "sì" - tutti i principali browser hanno il blocco popup attivato per impostazione predefinita. L'approccio migliore è sempre window.open () in risposta a un clic diretto, che è quasi sempre consentito.


2
Conosco le migliori pratiche, ecc. Ma mi trovo in una situazione in cui ho bisogno di portare a termine questo compito. Ecco perché ho posto questa domanda e non "dovrei?"
Andrew Ensley,

1

CIAO

Ho modificato leggermente le soluzioni sopra descritte e penso che funzioni almeno per Chrome. La mia soluzione è fatta per rilevare se il popup è bloccato quando viene aperta la pagina principale, non quando viene aperto il popup, ma sono sicuro che ci sono alcune persone che possono modificarlo. :-) Lo svantaggio qui è che viene visualizzata la finestra popup per un paio di secondi (potrebbe essere possibile accorciarlo un po ') quando non è presente alcun blocco popup.

Lo metto nella sezione della mia finestra "principale"

<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>

Il test popup ha questo aspetto:

<!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>

Poiché chiamo la funzione di test nella pagina popup dopo 3500 ms, l'altezza interna è stata impostata correttamente da Chrome.

Uso la variabile popUpsBlocked per sapere se i popup vengono visualizzati o meno in altri javascript. vale a dire

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

Questo purtroppo presuppone che la pagina che stai cercando di visualizzare sia controllata da noi. Devo aprire una pagina esterna su cui non ho alcun controllo.
Roman

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

Per quanto ne so (da quello che ho testato) Chrome restituisce un oggetto finestra con posizione "about: blank". Quindi, quanto segue dovrebbe funzionare per tutti i browser:

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

la posizione sarà ancora "about: blank" anche per il pop-up che non è bloccato. Ho provato su Chrome v28.0.1500.72
Roman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.