Detectar pop-up bloqueado no Chrome

Estou ciente das técnicas de javascript para detectar se um popup está bloqueado em outros navegadores (como descrito na resposta a esta pergunta ). Aqui está o teste básico:

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

Mas isso não funciona no Chrome. A seção “POPUP BLOCKED” nunca é alcançada quando o popup é bloqueado.

É claro que o teste está funcionando, já que o Chrome não bloqueia o pop-up, mas o abre em uma pequena janela minimizada no canto inferior direito, que lista os pop-ups “bloqueados”.

O que eu gostaria de fazer é saber se o pop-up foi bloqueado pelo bloqueador de pop-ups do Chrome. Eu tento evitar farejar o navegador em favor da detecção de resources. Existe uma maneira de fazer isso sem o navegador sniffing?

Edit : Agora tentei fazer uso de newWin.outerHeight , newWin.left e outras propriedades semelhantes para conseguir isso. O Google Chrome retorna todos os valores de posição e altura como 0 quando o pop-up é bloqueado.

Infelizmente, ele também retorna os mesmos valores, mesmo que o pop-up seja realmente aberto por um período de tempo desconhecido. Após algum período mágico (alguns segundos no meu teste), as informações de localização e tamanho são retornadas como os valores corretos. Em outras palavras, eu ainda não estou mais perto de descobrir isso. Qualquer ajuda seria apreciada.

   

    Bem, o “tempo mágico” de que você fala é provavelmente quando o DOM do popup foi carregado. Ou então pode ser quando tudo (imagens, CSS externo, etc.) tiver sido carregado. Você pode testar isso facilmente adicionando um gráfico muito grande ao pop-up (limpe seu cache primeiro!). Se você estivesse usando um JavaScript Framework como o jQuery (ou algo similar), você poderia usar o evento ready () (ou algo semelhante) para aguardar o carregamento do DOM antes de verificar o deslocamento da janela. O perigo disso é que a detecção do Safari funciona de maneira conflitante: o DOM do popup nunca estará pronto () no Safari, porque ele lhe dará um identificador válido para a janela que você está tentando abrir – se ele realmente abre ou não. (na verdade, acredito que seu código de teste acima não funcionará para o safari.)

    Acho que a melhor coisa que você pode fazer é quebrar seu teste em um setTimeout () e dar o popup de 3-5 segundos para concluir o carregamento antes de executar o teste. Não é perfeito, mas deve funcionar pelo menos 95% do tempo.

    Aqui está o código que uso para a detecção de vários navegadores, sem a parte do Google 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; } 

    O que eu faço é executar este teste do pai e envolvê-lo em um setTimeout (), dando a janela filho 3-5 segundos para carregar. Na janela filho, você precisa adicionar uma function de teste:

    teste de funcionamento() {}

    O detector de bloqueador de pop-ups testa para ver se a function “teste” existe como membro da janela filho.

    ADICIONADO 15 DE JUNHO DE 2015:

    Eu acho que a maneira moderna de lidar com isso seria usar window.postMessage () para que o filho avise ao pai que a janela foi carregada. A abordagem é semelhante (a criança diz que o pai está carregado), mas o meio de comunicação melhorou. Consegui fazer esse domínio cruzado da criança:

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

    O pai ouve esta mensagem usando:

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

    Espero que isto ajude.

    Apenas uma melhoria para o snipet do InvisibleBacon (testado no 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); }; } 

    O seguinte é uma solução jQuery para checagem de bloqueador de popup. Foi testado em FF (v11), Safari (v6), Chrome (v23.0.127.95) e IE (v7 e v9). Atualize a function _displayError para manipular a mensagem de erro como achar melhor.

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

    Espero que isto ajude! 🙂

    A resposta de Rich não funcionará mais para o Chrome. Parece que o Chrome na verdade executa qualquer JavaScript na janela pop-up agora. Acabei de verificar um valor screenX de 0 para verificar se há pop-ups bloqueados. Eu também acho que encontrei uma maneira de garantir que essa propriedade é final antes de verificar. Isso só funciona para pop-ups em seu domínio, mas você pode adicionar um manipulador onload assim:

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

    Como muitos relataram, a propriedade “screenX” às vezes informa não-zero para pop-ups com falha, mesmo após o onload. Também experimentei esse comportamento, mas se você adicionar a verificação após um tempo limite de zero ms, a propriedade screenX sempre exibirá um valor consistente.

    Deixe-me saber se existem maneiras de tornar esse script mais robusto. Parece funcionar para meus propósitos embora.

    Isso funcionou para mim:

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

    O outerHeight e o outerWidth são para chrome porque o truque ‘about: blank’ acima não funciona mais no chrome.

    Vou apenas copiar / colar a resposta fornecida aqui: https://stackoverflow.com/a/27725432/892099 por DanielB. funciona no cromo 40 e é muito limpo. Não hacks sujos ou espera envolve.

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

    Verifique a posição da janela em relação ao pai. O Chrome faz a janela aparecer quase fora da canvas.

    Eu tive um problema semelhante com pop-ups não abrindo no Chrome. Eu estava frustrado porque não estava tentando fazer algo sorrateiro, como um popup onload, apenas abrindo uma janela quando o usuário clicava. Eu estava muito frustrado porque executar minha function que incluía o window.open () da linha de comando do firebug funcionava, enquanto que clicar no link não funcionava! Aqui estava a minha solução:

    Caminho errado: executando window.open () de um ouvinte de evento (no meu caso, dojo.connect para o método de evento onclick de um nó DOM).

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

    Caminho certo: atribuir uma function à propriedade onclick do nó que chamou window.open ().

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

    E, claro, ainda posso fazer ouvintes de evento para o mesmo evento onclick se eu precisar. Com essa alteração, eu poderia abrir minhas janelas mesmo que o Chrome estivesse definido como “Não permitir que nenhum site mostre pop-ups”. Alegria.

    Se alguém que seja sábio nos modos do Chrome puder dizer a todos nós por que ele faz a diferença, adoraria ouvi-lo, embora eu suspeite que seja apenas uma tentativa de fechar a porta em popups programáticos maliciosos.

    Aqui está uma versão que está atualmente funcionando no Chrome. Apenas uma pequena alteração da solução de Rich, embora eu tenha adicionado em um wrapper que lida com o tempo também.

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

    Para usá-lo basta fazer isso:

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

    Se o popup for bloqueado, a mensagem de alerta será exibida após o período de carência de 5 segundos (você pode ajustá-lo, mas 5 segundos devem ser bastante seguros).

    Este fragment incorpora todos os itens acima – Por alguma razão – o StackOverflow está excluindo as primeiras e últimas linhas de código no bloco de código abaixo, então eu escrevi um blog sobre ele. Para uma explicação completa e o resto do código (para download), dê uma olhada no meu blog em 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(); 

    Uau, com certeza existem muitas soluções aqui. Isso é meu, ele usa soluções retiradas da resposta aceita atualmente (que não funciona no Chrome mais recente e exige que ele seja encerrado em um tempo limite), bem como uma solução relacionada neste segmento (que é na verdade baunilha JS, não jQuery) .

    O meu usa uma arquitetura de retorno de chamada que será enviada como true quando o pop-up estiver bloqueado e, caso contrário, será 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); } }; 

    A resposta de Jason é o único método que eu posso pensar também, mas confiar em uma posição como essa é um pouco desonesto!

    Hoje em dia, você não precisa fazer a pergunta “o meu pop-up não solicitado foi bloqueado?”, Porque a resposta é invariavelmente “sim” – todos os principais navegadores têm o bloqueador de pop-up ativado por padrão. Melhor abordagem é sempre apenas para window.open () em resposta a um clique direto, que é quase sempre permitido.

    OI

    Modifiquei ligeiramente as soluções descritas acima e acho que está funcionando para o Chrome, pelo menos. Minha solução é feita para detectar se o popup está bloqueado quando a página principal é aberta, não quando o pop-up é aberto, mas tenho certeza que existem algumas pessoas que podem modificá-lo. 🙂 A desvantagem aqui é que a janela pop-up é exibida por alguns segundos (pode ser possível encurtar um pouco) quando não há bloqueador de pop-up.

    Eu coloquei isso na seção da minha janela ‘principal’

      

    O popuptest se parece com isso:

     < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">   Popup test      

    Como eu chamo a function de teste na página pop-up após 3500 ms, o innerheight foi definido corretamente pelo Chrome.

    Eu uso a variável popUpsBlocked para saber se os popups são exibidos ou não em outros javascripts. ou seja

     function ShowConfirmationMessage() { if(popUpsBlocked) { alert('Popups are blocked, can not display confirmation popup. A mail will be sent with the confirmation.'); } else { displayConfirmationPopup(); } mailConfirmation(); } 
     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(); } }; } } 

    Tanto quanto eu posso dizer (pelo que eu testei) o Chrome retorna um object de janela com a localização de ‘about: blank’. Então, o seguinte deve funcionar para todos os navegadores:

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