innerText ?

Je vous propose aujourd’hui un bon vieux post technique pour briser cette longue période de silence…

Il y a peu, j’ai eu besoin de récupérer le contenu textuel d’un tag HTML. Concrètement, je voulais lire le texte se trouvant dans un fil d’Ariane, sans récupérer le contenu HTML de ce tag. Pour faire simple, à partir de ceci :

<ol id="breadcrumbs">
	<li><a href="index.php">Accueil</a> &raquo;</li>
	<li><a href="news.php">News</a> &raquo;</li>
	<li>Le point sur la crise financière...</li>
</ol>

Je voulais obtenir quelque chose comme :

Accueil &raquo; News &raquo; Le point sur la crise financière...

En passant, et comme je vous vois déjà venir, je suis au courant que mon markup n’est pas sémantique… Je devrais virer les &raquo; et les remplacer par un background sur le a (ou mieux : utiliser la pseudo-classe CSS :after mais c’est encore loin d’être supporté sur tous nos navigateurs…)

Bref, ce dont j’avais besoin n’était pas quelque chose comme innerHTML (qui m’aurait donné tout le contenu HTML du ol, ce qui inclut les tags li et a) mais plutôt quelque chose comme innerText.

Est-ce que innerText existe ?

Oui et non… A vrai dire, cela fonctionne partout sauf sur les navigateurs dont le moteur de rendu est Gecko, c’est-à-dire Mozilla Firefox, principalement… Gecko fait le même boulot via la propriété textContent et il a raison car c’est le standard W3C.

Pour pouvoir récupérer le contenu textuel d’un tag, de façon cross-browsers, il faut donc tester si textContent existe, l’utiliser si ce test s’avère positif et utiliser innerText dans tous les autres cas.

Comment tester que innerText (ou textContent) existe ?

Simplement en testant sur un élément qui est toujours présent dans un document, l’élément body, par exemple :

var hasInnerText = !!document.getElementsByTagName('body')[0].innerText;

Maintenant, vous pouvez tester et vérifier la valeur de hasInnerText avant d’utiliser innerText ou textContent.

Mais cela me semble un peu laborieux… Pourquoi ne pas créer une fonction qui renverra toujours le bon résultat, quel que soit le navigateur utilisé ? Le top du top est d’ajouter une méthode directement sur Element via le prototypage :

Element.prototype.text = function() {
	return !!document.getElementsByTagName('body')[0].innerText ? this.innerText : this.textContent;
}

Vous pouvez désormais utiliser cette expression, elle donne le résultat espéré :

document.getElementById('breadcrumbs').text();

Cela résout ce problème dont je suis sans doute un des seuls sur terre à m’être posé (quoique). Pendant que vous êtes en train de paniquer à propos de la crise, de votre argent en banque, de vos investissements et du pouvoir d’achat, j’essaye de m’occuper comme je peux…

9 Comments

  1. Marin's avatar Marin says:

    Je ferais aussi un check sur la methode text(). Je ne la rajouterai que si elle n’existe pas (on sait jamais que ce soit rajouté par un futur browser/framework).

    (et pssst un “s” a breadcrumbs comme on a dit :p)

    Like

  2. Oncle Tom's avatar Oncle Tom says:

    C’est bien pratique comme fonctionnalité.
    À noter que des frameworks comme jQuery proposent une méthode aboutissant à la même chose ($(el).text()).

    Like

  3. Mère Teresa's avatar Mère Teresa says:

    Marin> L’ajout de la méthode en modifiant le prototype pallie à ce souci, je pense.

    Like

  4. streaming's avatar streaming says:

    Merci, c’est super pratique !

    Like

  5. Martius's avatar Martius says:

    Le javascript brut étant un peu obscur pour moi (je devrais avoir honte, tout faire faire aux frameworks) j’ai du mal à saisir le but du “!!”, pourquoi une double négation ?

    Like

  6. Oncle Tom's avatar Oncle Tom says:

    D’ailleurs j’y repense, on peut même faire plus performant : faire la détection lors de la création du prototype et non lors de l’appel de chaque fonction.

    
    Element.prototype.text = !!document.getElementsByTagName('body')[0].innerText ? function(){ return this.innerText; } : function(){ return this.textContent; };
    

    Ainsi, la détection n'est faite qu'1 fois en tout et non 1 fois par appel de text().

    Like

  7. Streaming's avatar Streaming says:

    Merci beaucoup. Cela fonctionne nickel!

    Like

Leave a reply to Oncle Tom Cancel reply