web-dev-qa-db-fra.com

Évitez les bloqueurs de popups du navigateur

Je développe un flux d'authentification OAuth uniquement en JavaScript et je souhaite montrer à l'utilisateur la fenêtre "Accorder l'accès" dans une fenêtre contextuelle, mais elle est bloquée.

Comment puis-je empêcher les fenêtres contextuelles créées par window.open ou window.showModalDialog d'être bloquées par les bloqueurs de fenêtres contextuelles des différents navigateurs?

139
Pablo Fernandez

La règle générale est que les bloqueurs de popup seront activés si window.open ou similaire est invoqué à partir de javascript non invoqué par action directe de l'utilisateur . Autrement dit, vous pouvez appeler window.open en réponse à un clic sur un bouton sans vous faire toucher par le bloqueur de popup, mais si vous mettez le même code dans un événement de minuterie, il sera bloqué. La profondeur de la chaîne d'appels est également un facteur - certains navigateurs plus anciens ne consultent que l'appelant immédiat. Les nouveaux navigateurs peuvent revenir en arrière pour voir si l'appelant a été un clic de souris, etc. Gardez-le aussi superficiel que possible pour éviter les bloqueurs de popup.

248
dthorpe

Basé sur Jason Sebring 's astuce très utile , et sur les éléments couverts ici et , j'ai trouvé la solution parfaite pour mon cas:

Pseudo-code avec extraits de code Javascript:

  1. créer immédiatement un popup vide sur l'action de l'utilisateur

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

    Facultatif: ajoutez un message d'information "en attente". Exemples:

    a) Une page HTML externe: remplacez la ligne ci-dessus par

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

    b) Texte: ajoutez la ligne suivante sous celle ci-dessus:

    importantStuff.document.write('Loading preview...');
    
  2. remplissez-le avec le contenu lorsqu'il est prêt (lorsque l'appel AJAX est renvoyé, par exemple)

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

Enrichissez l'appel en window.open avec les options supplémentaires dont vous avez besoin.

En fait, j'utilise cette solution pour une redirection mailto, et cela fonctionne sur tous mes navigateurs (Windows 7, Android). Le bit _blank permet à la redirection mailto de fonctionner sur mobile, btw.

Ton expérience? Un moyen d'améliorer cela?

153
Swiss Mister

En plus de Swiss Mister post, dans mon cas, le window.open a été lancé dans le cadre d’une promesse qui a activé le bloqueur de popup, ma solution était:

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

voici comment vous pouvez ouvrir un nouvel onglet en utilisant la réponse de promesse sans invoquer le bloqueur de popup.

19
David

En tant que bonne pratique, je pense que c'est une bonne idée de tester si un popup est bloqué et de prendre des mesures au cas par cas. Vous devez savoir que window.open a une valeur de retour, et cette valeur peut être null si l'action a échoué. Par exemple, dans le code suivant:

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

si le popup est bloqué, window.open retournera null. Donc, la fonction retournera false.

Par exemple, imaginez que vous appelez cette fonction directement à partir de n’importe quel lien avec target="_blank": si le popup est ouvert avec succès, en retournant false bloquera l'action du lien, sinon si le popup est bloqué, renvoyer true laissera le comportement par défaut (ouvrir une nouvelle fenêtre _blank ) et continuer.

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

De cette façon, vous aurez un popup si cela fonctionne, et une fenêtre _blank si ne pas.

Si le popup ne s'ouvre pas, vous pouvez:

  • ouvrez une fenêtre vierge comme dans l'exemple et continuez
  • ouvrir un faux popup (un iframe dans la page)
  • informer l'utilisateur ("veuillez autoriser les popups pour ce site")
  • ouvrez une fenêtre vierge puis informez l'utilisateur etc.
16
FrancescoMM

à partir de l'API JavaScript oauth de Google:

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

Voir la zone où il se lit:

Configuration de l'authentification

L'implémentation d'OAuth 2.0 par le client utilise une fenêtre contextuelle pour inviter l'utilisateur à se connecter et à approuver l'application. Le premier appel à gapi.auth.authorize peut déclencher des bloqueurs de popup, car il ouvre la fenêtre popup indirectement. Pour empêcher le bloqueur de fenêtres contextuelles de se déclencher lors d'appels autorisés, appelez gapi.auth.init (rappel) lors du chargement du client. Le rappel fourni sera exécuté lorsque la bibliothèque sera prête à passer des appels avec authentification. 

Je suppose que c'est lié à la vraie réponse ci-dessus dans la façon dont il explique s'il y a une réponse immédiate, cela ne déclenchera pas l'alarme contextuelle. Le "gapi.auth.init" fait en sorte que l'api se produit immédiatement.

Application pratique

J'ai créé un microservice d'authentification à source ouverte en utilisant le nœud passport sur npm et les différents packages de passeports pour chaque fournisseur. J'ai utilisé une approche de redirection standard au tiers en lui donnant une URL de redirection vers laquelle revenir. C’était programmatique afin que je puisse avoir différents endroits pour rediriger si je me connectais/m'inscris et sur des pages particulières. 

github.com/sebringj/athu

passportjs.org

8
Jason Sebring

Je ne voulais pas faire la nouvelle page à moins que le rappel soit retourné avec succès, alors je l'ai fait pour simuler l'utilisateur cliquer:

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

J'ai essayé plusieurs solutions, mais c'est la seule qui a réellement fonctionné pour moi dans tous les navigateurs.

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

0
pomobc