Ne vous souciez plus de la target dans vos liens

Pour les personnes en charge de l'édition de contenu, remplir des liens est souvent source de problème car, là où la page des termes et conditions avaient toujours été une page interne au site, la voilà devenu un fichier PDF ou une page plus globale hébergée sur un autre site web ; ce qui demande l'ouverture d'un nouvel onglet pour s'afficher. Et le pire dans tout cela, c'est que c'est juste pour la version du site en Vulcain ! Il va donc falloir laisser ces mêmes personnes gérer eux-mêmes la propriété target ou...

...utiliser un script intelligent qui va ajouter les target="_blank" là ou ils sont nécessaires !

Cela est également très pratique quand on rédige ses pages en Markdown.

Un peu d'histoire

Le fameux attribut target="_blank" que l'on utilise pour ouvrir une fenêtre dans un nouvel onglet à toujours été une petite source de conflit. Très utilisé lors de l'époque du HTML4, il a été boudée un certain temps durant la période xHTML car non valide. La bataille a donc fait rage entre :

  • ceux ne faisant que peu de cas des standards,
  • ceux affirmant que c'était à l'utilisateur de décider dans quel onglet ouvrir le lien (sans que ce même utilisateur ne sache comment faire), et
  • ceux faisant appel au JavaScript pour passer les validations...

Aujourd'hui de l'eau a été mis dans le vin puisque à l'heure du HTML5, la balise target est de nouveau autorisée.

Smart Target Injection

Explication

Voilà les règles établies pour savoir si un lien doit être ouvert dans un nouvel onglet, ou dans l'onglet courant : Si le lien a déjà l'attribut target de défini (à _blank, _self ou autre), on ne touche à rien, mais si cet attribut est absent alors :

  • si le lien pointe sur un nom de domaine différent, on ouvre la page dans un nouvel onglet
  • si le lien pointe sur notre site web, deux cas :
    • si c'est une page web on l'ouvre dans le même onglet,
    • si c'est un média/fichier (.pdf, .jpg, .png, .js, .mp4, etc.) on l'ouvre dans un nouvel onglet.

Code jQuery

Voici le petit code jQuery qui va faire cela. Si vous n'aimez pas jQuery, je vous propose une version de ce code en JavaScript natif plus bas et si vous voulez que vos target ne soient pas ajoutées côté client en JavaScript, vous pouvez toujours utiliser NodeAtlas !

/*
 * Pour tous les liens de la page courante...
 */
$(document.links).filter(function() {
    /*
     * ...garder ceux qui n'on pas déjà une `target` dans les attributs...
     */
    return !this.target;
}).filter(function() {
    /*
     * ...et garder les pages qui ne sont pas sur le nom de domaine courant...
     */
    return this.hostname !== window.location.hostname ||
        /*
         * ...ou qui ne sont pas des pages web (.pdf, .jpg, .png, .js, .mp4, etc.).
         */
        /\.(?!html?)([a-z]{0,3}|[a-zt]{0,4})$/.test(this.pathname);
/*
 * Pour toutes les pages conservées, ajouter l'attribut `target="_blank"`. 
 */
}).attr('target', '_blank');

À propos de la RegExp

Vous pouvez comprendre la RegExp utilisée ligne 17 sur cette page explicative.

Il est également bon de noter que dans ce code, seules les extensions .html et .htm s'ouvre dans l'onglet courant. Vous pouvez ajouter des extensions comme cela :

\.(?!html?|aspx?|php3?)([a-z]{0,3}|[a-zt]{0,4})$

ici les pages de type .htm, .html, .php, .php3, .asp et .aspx s'ouvrirons dans le même onglet.

Petit jeu de test

Voici une liste de lien à tester. Sachez que de mon côté, je les ai écris en Markdown ([Accueil relative « ./ »](./)) et que je ne me suis absolument pas soucié de la target (devinez comment ?!).

Code purement JavaScript

Si vous n'utilisez pas jQuery, voici le code :

var links = document.links;

for (var i = 0, linksLength = links.length; i < linksLength; i++) {
    if (!links[i].target) {
        if (
            links[i].hostname !== window.location.hostname || 
            /\.(?!html?)([a-z]{0,3}|[a-zt]{0,4})$/.test(links[i].pathname)
        ) {
            links[i].target = '_blank';
        } 
    }
}