Evite bloqueadores de pop-up do navegador

172

Estou desenvolvendo um fluxo de autenticação OAuth puramente em JavaScript e quero mostrar ao usuário a janela "conceder acesso" em um pop-up, mas ele é bloqueado.

Como impedir que janelas pop-up criadas por um window.openou window.showModalDialogsejam bloqueadas pelos bloqueadores de pop-up dos diferentes navegadores?

Pablo Fernandez
fonte
11
Mesmo que fosse possível (não sei), se as pessoas usam bloqueadores de pop-up, você deve respeitá-lo. A maioria dos navegadores exibe uma mensagem quando um site tenta abrir um pop-up para que eles ainda possam vê-lo, se quiserem. Você pode colocar um comentário em seu site de que algum conteúdo é aberto em um pop-up e o usuário deve permitir que ele prossiga.
Felix Kling
5
A melhor prática seria: 1) Faça isso com sucesso 2) Feche as janelas, tranque a porta e se encoste de medo da multidão de usuários da web que estão chateados 3) Arrependa-se, remova o pop-up-busta-busta e respeite seu público.
Alex Mcp
Alex e Felix, atualizei a pergunta. Eu não vou usar o conhecimento para o mal :). Obrigado!
Pablo Fernandez
9
Gostaria de acrescentar que ignorar um bloqueador de pop-ups pode estar realmente tentando melhorar a experiência do usuário. Em um exemplo no qual estou trabalhando agora, estamos usando um aplicativo Javascript (baseado no ExtJS) e estamos tentando permitir que os usuários paguem usando paypal. Estamos dando a eles um botão no qual eles podem clicar para iniciar o paypal em uma nova janela, mas certas versões do IE estão bloqueando-o como um pop-up (mesmo que seja um clique no botão). Se eles agora ativarem o pop-up, a tela for recarregada e como um aplicativo JavaScript, perderemos o estado da janela e eles terão que começar de novo. Realmente: o problema é que o IE é burro.
NateDSaint 5/09/12
1
@FelixKling Sim, é possível. Os fabricantes de navegadores já pensaram nisso. Abrir um pop-up é bom na medida em que haja intenção do usuário (sinalizado pelo usuário clicando em um link ou botão). Os bloqueadores de pop-up devem respeitar a intenção do usuário. Se o bloqueador de pop-ups do IE não funcionar, é o bloqueador de pop-ups que está com defeito. Os usuários usam bloqueadores de pop-up para impedir que scripts abram pop-ups à vontade, não para bloquear pop-ups que eles mesmos tentaram abrir (clicando em um botão ou link).
Stijn de Witt

Respostas:

286

A regra geral é que os bloqueadores de pop-up serão ativados se window.open ou semelhante for invocado no javascript que não é invocado pela ação direta do usuário . Ou seja, você pode chamar window.openem resposta a um clique no botão sem ser atingido pelo bloqueador de pop-ups, mas se você colocar o mesmo código em um evento de timer, ele será bloqueado. A profundidade da cadeia de chamadas também é um fator - alguns navegadores mais antigos olham apenas para o chamador imediato, os navegadores mais novos podem voltar um pouco para ver se o chamador foi um clique do mouse etc. Mantenha-o o mais superficial possível para evitar os bloqueadores de pop-up.

dthorpe
fonte
2
Curiosamente, os pop-ups iniciados por meio de um evento de alteração vinculado a um elemento de seleção serão bloqueados (no Chrome, não no FF), mesmo que esse evento seja iniciado por uma ação direta do usuário, como um clique. Embora se vinculados a uma entrada, eles são permitidos. Estranho.
Ccnokes
6
Ninguém disse que o navegador era consistente. : P
dthorpe
8
Através de experimentos, eu tenho que entender que a profundidade da pilha não tem nada a ver com o bloqueador de pop-ups. Na verdade, verifica se window.open é chamado dentro de 1 segundo após a ação do usuário ou não. Testado no Chrome 46 e Firefox 42.
Mesqalito
O tempo limite de 1 segundo pode ser contornado nos dois navegadores, permitindo uma quantidade indefinida de tempo, usando a resposta @ tj-crowder nesta página . ) por um período de tempo antes de retornar uma resposta. O navegador travará enquanto ele 'carrega' a página. Em seguida, aciona o pop-up quando recebe uma resposta. No Chrome, no entanto, você deve adicionar um alert () antes do ajax () para fazer esse truque funcionar.
fanfare
184

Baseado em Jason Sebring é dica muito útil , e sobre o material coberto aqui e , eu encontrei uma solução perfeita para o meu caso:

Pseudo-código com trechos de Javascript:

  1. crie imediatamente um pop-up em branco na ação do usuário

    var importantStuff = window.open('', '_blank');

    Opcional: adicione uma mensagem informativa "em espera". Exemplos:

    a) Uma página HTML externa: substitua a linha acima por

    var importantStuff = window.open('http://example.com/waiting.html', '_blank');

    b) Texto: adicione a seguinte linha abaixo da linha acima:

    importantStuff.document.write('Loading preview...');
  2. preencha com conteúdo quando estiver pronto (quando a chamada AJAX for retornada, por exemplo)

    importantStuff.location.href = 'http://shrib.com';

Enriqueça a chamada para window.open com as opções adicionais necessárias.

Na verdade, eu uso essa solução para redirecionar o mailto e funciona em todos os meus navegadores (Windows 7, Android). o_blank bit ajuda o redirecionamento mailto a funcionar em dispositivos móveis.

Sua experiência? Alguma maneira de melhorar isso?

Senhor suíço
fonte
1
? Então, o que você faz se não for da ação do usuário no navegador? Para o meu exemplo, depois autentica usuários contra servidor, ele deve abrir uma nova aba
Don Cheadle
@mmcrae não faça isso. Seja o que for que você pretende fazer, existe uma maneira melhor do que uma janela pop-up. Caso contrário, é provável que eu nunca queira ver seu site. Os navegadores de hoje garantem que você não consiga fazer isso - consulte a resposta de @dthorpe .
Swiss Mister
5
Whatever it is you intend to do, there is a better way than a popup windowri muito? Generalização estranha. O cliente deseja que a página em que ele se autenticou permaneça aberta, e o novo site / página inicial após a autenticação para abrir em uma nova guia. Sim, não meu idéia de excelente experiência ao usuário ... mas parece razoável
Don Cheadle
@mmcrae. Sente-se e pense seriamente. Eu prometo que você encontrará uma "ação do usuário" no cenário que você descreve. O ponto principal da minha resposta é que você cria a janela pop-up quando tem a ação do usuário - e a preenche com conteúdo posteriormente. Dica para o seu caso: o usuário pressiona "autenticar" -> criar o pop-up (vazio); o temporizador está ativo ou a resposta do servidor está de volta ou o que for -> preencha o conteúdo no pop-up.
Swiss Mister
3
Dica útil, se a solicitação do ajax falhar, ligue importantStuff.closepara fechar a nova guia e forneça e alerte na página original.
Goose
24

Além disso, o Swiss Mister post, no meu caso, o window.open foi lançado dentro de uma promessa, que ativou o bloqueador de pop-ups, minha solução foi: em angular:

$scope.gotClick = function(){

  var myNewTab = browserService.openNewTab();
  someService.getUrl().then(
    function(res){
        browserService.updateTabLocation(res.url, myNewTab);

    }
  );
};

browserService:

this.openNewTab = function(){
     var newTabWindow = $window.open();
     return newTabWindow;
}

this.updateTabLocation = function(tabLocation, tab) {
     if(!tabLocation){
       tab.close();
     }
     tab.location.href = tabLocation;
}

é assim que você pode abrir uma nova guia usando a resposta da promessa e não invocando o bloqueador de pop-ups.

David
fonte
1
Isso levou à minha solução! Onde eu criei uma variável contendo a guia aberta e preenchi o URL após o carregamento dos dados. Obrigado. const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
jonas
1
Se você tem o bloqueador de pop-up habilitado isso não vai resolver o problema com o bloqueador de pop-up ...
Alejandro Vales
A solução jAlejandro Vales jonas funcionará apenas se o código for executado a partir de um evento onClick ou de qualquer interação do usuário. Quando você tenta abrir uma nova guia via windows.open dentro de uma promessa, tempo limite, inscreva-se ... o navegador acha que é uma manipulação do usuário, portanto a solução é criar uma instância antes de entrar na promessa, basta alterar a href como Jonas fez
David
@ David Muito obrigado !!! Eu não aconteceu para ver o .thenem seguida, resposta e é por isso que fiquei tão confuso: / SRY ...
Alejandro Vales
@ David Isso é ótimo! Funciona como um encanto. Se eu pudesse incomodá-lo com apenas mais uma pergunta - você sabe como fazer isso funcionar no Edge também? Um empurrão a um recurso certo seria de grande ajuda ...
dzenesiz
21

Como boa prática, acho que é uma boa ideia testar se um pop-up foi bloqueado e tomar alguma ação. Você precisa saber que window.open tem um valor de retorno e esse valor pode ser nulo se a ação falhar. Por exemplo, no seguinte código:

function pop(url,w,h) {
    n=window.open(url,'_blank','toolbar=0,location=0,directories=0,status=1,menubar=0,titlebar=0,scrollbars=1,resizable=1,width='+w+',height='+h);
    if(n==null) {
        return true;
    }
    return false;
}

se o pop-up estiver bloqueado, window.open retornará nulo. Portanto, a função retornará false.

Como exemplo, imagine chamar essa função diretamente de qualquer link com target="_blank": se o pop-up for aberto com êxito, o retorno falsebloqueará a ação do link; caso contrário, se o pop-up for bloqueado, o retorno truepermitirá o comportamento padrão (abrir nova janela _blank) e continuar .

<a href="http://whatever.com" target="_blank" onclick='return pop("http://whatever.com",300,200);' >

Dessa forma, você terá um pop-up, se funcionar, e uma janela em branco, se não estiver.

Se o pop-up não abrir, você pode:

  • abra uma janela em branco como no exemplo e continue
  • abra um pop-up falso (um iframe dentro da página)
  • informe o usuário ("permita pop-ups neste site")
  • abra uma janela em branco e informe o usuário etc.
FrancescoMM
fonte
Obrigado. Trabalhou!
Bcktr
8

da API JavaScript oauth do Google:

http://code.google.com/p/google-api-javascript-client/wiki/Authentication

Veja a área onde se lê:

Configurando autenticação

A implementação do cliente do OAuth 2.0 usa uma janela pop-up para solicitar que o usuário entre e aprove o aplicativo. A primeira chamada para gapi.auth.authorize pode acionar bloqueadores de pop-up, pois abre indiretamente a janela pop-up. Para impedir que o bloqueador de pop-ups seja acionado em chamadas de autenticação, chame gapi.auth.init (retorno de chamada) quando o cliente carregar. O retorno de chamada fornecido será executado quando a biblioteca estiver pronta para fazer chamadas de autenticação.

Eu acho que está relacionado à resposta real acima, em como ela explica se existe uma resposta imediata, não dispara o alarme pop-up. O "gapi.auth.init" está fazendo com que a API aconteça imediatamente.

Aplicação prática

Fiz um microsserviço de autenticação de código aberto usando o passaporte do nó no npm e os vários pacotes de passaporte para cada provedor. Usei uma abordagem de redirecionamento padrão para terceiros, fornecendo um URL de redirecionamento para o qual retornar. Isso era programático, então eu poderia ter lugares diferentes para redirecionar para o login / inscrição e em páginas específicas.

github.com/sebringj/athu

passportjs.org

Jason Sebring
fonte
3

Tentei várias soluções, mas a dele é a única que realmente funcionou para mim em todos os navegadores

let newTab = window.open(); newTab.location.href = url;

pomobc
fonte
2
Isso simplesmente não funciona para as pessoas que têm o bloqueador de pop-up habilitado
Alejandro Vales
o que é url? não está atribuído.
shinriyo
@shinriyo url é o link para qualquer página que você queira acessar, por exemplohttp://example.com
pomobc
@AlejandroVales tenho bloqueador de pop-up ativado e funciona. O problema é que window.open()não é possível abrir uma nova janela programaticamente e, se precisarmos, essa resposta é uma das opções. Com a newTabvariável que fazemos referência window.open()e mais tarde podemos chamá-la, insira o urlque precisamos, no meu caso, url de algum blob, e a nova guia será aberta com o URL inserido.
stanimirsp
0

Eu não queria criar a nova página, a menos que o retorno de chamada retornasse com êxito, por isso fiz isso para simular o clique do usuário:

function submitAndRedirect {
  apiCall.then(({ redirect }) => {
      const a = document.createElement('a');
      a.href = redirect;
      a.target = '_blank';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
  });
}
user3479425
fonte
3
não funciona para mim no Chrome 62. O pop-up (página) é bloqueado.
s.ermakovich
1
Sim, você está certo - eu também achei isso inconsistente. Eu acabei fazendo minha chamada api síncrona
user3479425
-8

A maneira mais fácil de se livrar disso é:

  1. Não use document.open ().
  2. Em vez disso, use this.document.location.href = location; onde local é o URL a ser carregado

Ex:

<script>
function loadUrl(location)
{
this.document.location.href = location;
}</script>

<div onclick="loadUrl('company_page.jsp')">Abc</div>

Isso funcionou muito bem para mim. Felicidades

Pramod Shetty
fonte
2
Que tal abrir o URL em uma nova guia?
3 regras