API JavaScript Selection et Range
Apprenez à manipuler la sélection de texte et les plages dans le DOM avec les interfaces JavaScript Selection et Range.
Lorsqu'un utilisateur fait glisser le curseur sur du texte dans une page, le navigateur enregistre ce qui a été sélectionné. JavaScript expose ces informations — et vous permet de créer vous-même des sélections — à travers deux interfaces DOM liées :
- Un
Rangeest une paire de points de délimitation (un début et une fin) à l'intérieur du document. Il décrit quelle partie du document vous visez, jusqu'à un décalage de caractère précis à l'intérieur d'un nœud texte. Un range peut exister purement en mémoire sans que l'utilisateur en ait conscience. - Une
Selectioncorrespond à ce que l'utilisateur a actuellement surligné. Il s'agit essentiellement d'un wrapper autour d'un ou plusieurs ranges, lié au surlignage à l'écran et au curseur de texte (caret).
Ces API sont utiles lorsque vous devez construire un éditeur de texte enrichi, une fonctionnalité « surligner et commenter », un remplacement personnalisé ou tout ce qui lit, déplace ou stylise du texte sélectionné par programmation. Ce chapitre couvre la construction de ranges, la lecture et la modification de la sélection de l'utilisateur, ainsi que leur combinaison pour surligner et insérer du contenu.
Ce chapitre s'appuie sur la structure du DOM. Si les types de nœuds et les décalages vous sont inconnus, lisez d'abord Propriétés des nœuds : type, balise et contenu et Modifier le document.
Comprendre l'interface Selection
L'interface Selection représente le texte que l'utilisateur a surligné, ou la position actuelle du caret lorsque rien n'est surligné. Vous y accédez avec la méthode globale window.getSelection() (souvent simplement getSelection()). En interne, une sélection contient zéro ou plusieurs objets Range ; en pratique, la plupart des navigateurs ne conservent qu'un seul range, donc getRangeAt(0) est la façon courante de le lire.
La manière la plus rapide de voir ce qui est sélectionné est toString(), qui retourne le texte sélectionné sous forme de string :
// After the user highlights something on the page:
const selectedText = window.getSelection().toString();
console.log(selectedText); // whatever the user highlightedPropriétés et méthodes utiles de Selection
rangeCount: Le nombre de ranges dans la sélection —0lorsque rien n'est sélectionné. Vérifiez toujours cela avant d'appelergetRangeAt.toString(): Retourne le texte sélectionné sous forme de string.getRangeAt(index): Retourne leRangeà l'index donné (utilisez0pour la sélection actuelle).addRange(range): Ajoute unRangeà la sélection, en le surlignant à l'écran.removeAllRanges(): Efface entièrement la sélection.removeRange(range): Supprime un range spécifique. La plupart des navigateurs ne conservent qu'un seul range, doncremoveAllRanges()est le choix pratique.collapse(node, offset): Réduit la sélection à un seul point (un caret vide) à l'intérieur denode.
Un pattern courant consiste à lire la sélection actuelle, la modifier, puis écrire une nouvelle sélection — removeAllRanges() suivi de addRange().
Exemple pratique : surligner du texte
Pour surligner ce que l'utilisateur a sélectionné, récupérez son range, extrayez les nœuds sélectionnés du document, enveloppez-les dans un <span> stylisé, et remettez ce span à l'emplacement du contenu.
extractContents()retire le contenu sélectionné du DOM et le retourne sous forme de fragment de document, laissant le range vide (réduit) à cet endroit — ce qui est exactement là où nous insérons ensuite le span.
<div id="text">Select some of this text and press the button.</div>
<button onclick="highlightText()">Highlight</button>
<script>
function highlightText() {
const selection = window.getSelection();
if (!selection.rangeCount) return false;
const range = selection.getRangeAt(0);
const span = document.createElement('span');
span.style.backgroundColor = 'yellow';
const fragment = range.extractContents();
span.appendChild(fragment);
range.insertNode(span);
}
</script>Explorer l'interface Range
Un Range marque un fragment du document avec deux points de délimitation — un début et une fin — chacun défini par un nœud et un décalage. La signification du décalage dépend du nœud :
- Dans un nœud texte, le décalage est un index de caractère (par ex. le décalage
5se situe entre le 5e et le 6e caractère). - Dans un nœud élément, le décalage compte les nœuds enfants (par ex. le décalage
0est avant le premier enfant).
Créez un range vide avec document.createRange(), puis positionnez ses délimitations. Vous pouvez trouver les nœuds à cibler avec getElementById / querySelector.
Définir les délimitations
const p = document.querySelector('p');
const textNode = p.firstChild; // the text inside <p>
const range = document.createRange();
range.setStart(textNode, 0); // start at the first character
range.setEnd(textNode, 5); // end before the 6th character
console.log(range.toString()); // first 5 characters of the paragraphDeux raccourcis couvrent les cas les plus courants pour éviter de calculer manuellement les décalages :
selectNode(node)— le range englobe le nœud et ses balises environnantes.selectNodeContents(node)— le range englobe uniquement ce qui est à l'intérieur du nœud.
Méthodes utiles de Range
setStart(node, offset)/setEnd(node, offset): Positionne les délimitations de début et de fin.selectNode(node)/selectNodeContents(node): Définit les deux délimitations autour d'un nœud ou de son contenu.toString(): Le texte à l'intérieur du range.cloneContents(): Retourne une copie du contenu du range sous forme de fragment de document, sans toucher au document.extractContents(): Déplace le contenu hors du document dans un fragment et le retourne.deleteContents(): Supprime le contenu du range et ne retourne rien.cloneRange(): Retourne une copie de l'objet range lui-même (pas de son contenu).insertNode(node): Insère un nœud au début du range.surroundContents(node): Enveloppe le contenu du range à l'intérieur denode— pratique pour le surlignage, mais lève une exception si le range coupe partiellement un élément non-texte.
Retenez la différence :
cloneContents()copie,extractContents()déplace et retourne,deleteContents()supprime et abandonne.
Exemple pratique : extraction de texte
Cet exemple lit tout ce qui se trouve à l'intérieur d'un élément avec un range et transforme le texte sans toucher au DOM original :
<div id="content">This is some sample text for extraction.</div>
<button onclick="extractText()">Extract and Manipulate</button>
<script>
function extractText() {
const range = document.createRange();
const content = document.getElementById('content');
range.selectNodeContents(content);
const extractedText = range.toString();
const manipulatedText = extractedText.replace('sample', 'example'); // Manipulating text
alert(manipulatedText);
}
</script>Dans l'exemple ci-dessus, le script remplace le mot « sample » par « example » dans le texte extrait avant de l'afficher dans une boîte d'alerte. Il s'agit d'une manipulation basique, mais elle montre comment commencer à travailler avec le texte une fois extrait.
Opérations avancées sur le texte
Au-delà de la manipulation de texte de base, les interfaces Selection et Range permettent des opérations plus complexes comme l'insertion de nœuds directement dans le document.
Exemple : Insérer du texte
Cet exemple utilise un div contenteditable : l'utilisateur clique pour placer le caret, et le bouton insère 'Hello World' à cet endroit précis. Notez comment deleteContents() supprime d'abord tout ce qui est sélectionné, puis le nouveau nœud texte est inséré et re-sélectionné pour que le caret se positionne après.
<div id="editable" contenteditable="true" style="border: 1px solid #ccc; padding: 10px; min-height: 50px;">
Click here and set the cursor position.
</div>
<button onclick="insertText()">Insert 'Hello World'</button>
<script>
function insertText() {
const editableDiv = document.getElementById('editable');
const sel = window.getSelection();
// Check if the selection is within the editable div
if (!sel.rangeCount || !editableDiv.contains(sel.getRangeAt(0).commonAncestorContainer)) return;
const range = sel.getRangeAt(0);
range.deleteContents(); // Clears any selected text
const textNode = document.createTextNode('Hello World');
range.insertNode(textNode);
sel.removeAllRanges(); // Clear the previous selection
sel.addRange(range); // Re-select the new text node
}
</script>Résumé
- Un
Rangeest deux points de délimitation (nœud + décalage) décrivant un fragment du document ; créez-en un avecdocument.createRange()et positionnez-le avecsetStart/setEndou les raccourcisselectNode/selectNodeContents. - Une
Selection, obtenue viawindow.getSelection(), encapsule le surlignage à l'écran de l'utilisateur. Lisez-la avectoString()etgetRangeAt(0); réécrivez-la avecremoveAllRanges()+addRange(). - Pour le contenu :
cloneContents()copie,extractContents()déplace et retourne,deleteContents()supprime, etinsertNode/surroundContentsremettent des nœuds en place.
Ensemble, ces méthodes permettent de surligner, extraire et insérer du contenu avec précision — la base des éditeurs de texte enrichi et des outils d'annotation.
Continuer : Modifier le document · Propriétés des nœuds : type, balise et contenu · Recherche : getElement* et querySelector