Je veux envelopper un texte sélectionné dans un conteneur div avec span, est-ce possible?
Un utilisateur sélectionnera un texte et cliquera sur un bouton. L'événement de clic de bouton que je souhaite envelopper le texte sélectionné avec un élément span Je peux obtenir le texte sélectionné en utilisant window.getSelection()
mais comment connaître sa position exacte dans la structure du DOM?
Si la sélection est entièrement contenue dans un seul nœud de texte, vous pouvez le faire à l'aide de la méthode surroundContents()
de la plage obtenue à partir de la sélection. Cependant, ceci est très fragile: cela ne fonctionne pas si la sélection ne peut pas être logiquement entourée d'un seul élément (généralement, si la plage dépasse les limites des nœuds, bien que ce ne soit pas la définition precise ). Pour ce faire dans le cas général, vous avez besoin d’une approche plus compliquée.
De plus, les DOM Range
et window.getSelection()
ne sont pas pris en charge dans IE <9. Vous aurez besoin d'une autre approche pour ces navigateurs. Vous pouvez utiliser une bibliothèque telle que mon propre Rangy pour normaliser le comportement du navigateur. Le module applicateur class peut être utile pour cette question.
Exemple simple surroundContents()
jsFiddle: http://jsfiddle.net/VRcvn/
Code:
function surroundSelection(element) {
if (window.getSelection) {
var sel = window.getSelection();
if (sel.rangeCount) {
var range = sel.getRangeAt(0).cloneRange();
range.surroundContents(element);
sel.removeAllRanges();
sel.addRange(range);
}
}
}
function wrapSelectedText() {
var selection= window.getSelection().getRangeAt(0);
var selectedText = selection.extractContents();
var span= document.createElement("span");
span.style.backgroundColor = "yellow";
span.appendChild(selectedText);
selection.insertNode(span);
}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam rhoncus gravida magna, quis interdum magna mattis quis. Fusce tempor sagittis varius. Nunc at augue at erat suscipit bibendum id nec enim. Sed eu odio quis turpis hendrerit sagittis id sit amet justo. Cras ac urna purus, non rutrum nunc. Aenean nec vulputate ante. Morbi scelerisque sagittis hendrerit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla tristique ligula fermentum tortor semper at consectetur erat aliquam. Sed gravida consectetur sollicitudin.
<input type="button" onclick="wrapSelectedText();" value="Highlight" />
c'est possible. Vous devez utiliser l'API de plage et la méthode Range.surroundContents (). Il place le nœud dans lequel le contenu est encapsulé au début de la plage spécifiée . Voir https://developer.mozilla.org/en/DOM/range.surroundContents
surroundContents ne fonctionne que si votre sélection ne contient que du texte et pas de HTML. Voici une solution plus flexible, ainsi que multi-navigateur. Cela va insérer une étendue comme ceci:
<span id="new_selection_span"><!--MARK--></span>
La plage est insérée avant la sélection, devant la balise HTML d'ouverture la plus proche.
var span = document.createElement("span");
span.id = "new_selection_span";
span.innerHTML = '<!--MARK-->';
if (window.getSelection) { //compliant browsers
//obtain the selection
sel = window.getSelection();
if (sel.rangeCount) {
//clone the Range object
var range = sel.getRangeAt(0).cloneRange();
//get the node at the start of the range
var node = range.startContainer;
//find the first parent that is a real HTML tag and not a text node
while (node.nodeType != 1) node = node.parentNode;
//place the marker before the node
node.parentNode.insertBefore(span, node);
//restore the selection
sel.removeAllRanges();
sel.addRange(range);
}
} else { //IE8 and lower
sel = document.selection.createRange();
//place the marker before the node
var node = sel.parentElement();
node.parentNode.insertBefore(span, node);
//restore the selection
sel.select();
}
S'il vous plaît trouver le code ci-dessous sera utile pour envelopper la balise span pour tout type de balises. Veuillez parcourir le code et utiliser la logique pour votre implémentation.
getSelectedText(this);
addAnnotationElement(this, this.parent);
function getSelectedText(this) {
this.range = window.getSelection().getRangeAt(0);
this.parent = this.range.commonAncestorContainer;
this.frag = this.range.cloneContents();
this.clRange = this.range.cloneRange();
this.start = this.range.startContainer;
this.end = this.range.endContainer;
}
function addAnnotationElement(this, elem) {
var text, textParent, origText, prevText, nextText, childCount,
annotationTextRange,
span = this.htmlDoc.createElement('span');
if (elem.nodeType === 3) {
span.setAttribute('class', this.annotationClass);
span.dataset.name = this.annotationName;
span.dataset.comment = '';
span.dataset.page = '1';
origText = elem.textContent;
annotationTextRange = validateTextRange(this, elem);
if (annotationTextRange == 'textBeforeRangeButIntersect') {
text = origText.substring(0, this.range.endOffset);
nextText = origText.substring(this.range.endOffset);
} else if (annotationTextRange == 'textAfterRangeButIntersect') {
prevText = origText.substring(0, this.range.startOffset);
text = origText.substring(this.range.startOffset);
} else if (annotationTextRange == 'textExactlyInRange') {
text = origText
} else if (annotationTextRange == 'textWithinRange') {
prevText = origText.substring(0, this.range.startOffset);
text = origText.substring(this.range.startOffset,this.range.endOffset);
nextText = origText.substring(this.range.endOffset);
} else if (annotationTextRange == 'textNotInRange') {
return;
}
span.textContent = text;
textParent = elem.parentElement;
textParent.replaceChild(span, elem);
if (prevText) {
var prevDOM = this.htmlDoc.createTextNode(prevText);
textParent.insertBefore(prevDOM, span);
}
if (nextText) {
var nextDOM = this.htmlDoc.createTextNode(nextText);
textParent.insertBefore(nextDOM, span.nextSibling);
}
return;
}
childCount = elem.childNodes.length;
for (var i = 0; i < childCount; i++) {
var elemChildNode = elem.childNodes[i];
if( Helper.isUndefined(elemChildNode.tagName) ||
! ( elemChildNode.tagName.toLowerCase() === 'span' &&
elemChildNode.classList.contains(this.annotationClass) ) ) {
addAnnotationElement(this, elem.childNodes[i]);
}
childCount = elem.childNodes.length;
}
}
function validateTextRange(this, elem) {
var textRange = document.createRange();
textRange.selectNodeContents (elem);
if (this.range.compareBoundaryPoints (Range.START_TO_END, textRange) <= 0) {
return 'textNotInRange';
}
else {
if (this.range.compareBoundaryPoints (Range.END_TO_START, textRange) >= 0) {
return 'textNotInRange';
}
else {
var startPoints = this.range.compareBoundaryPoints (Range.START_TO_START, textRange),
endPoints = this.range.compareBoundaryPoints (Range.END_TO_END, textRange);
if (startPoints < 0) {
if (endPoints < 0) {
return 'textBeforeRangeButIntersect';
}
else {
return "textExactlyInRange";
}
}
else {
if (endPoints > 0) {
return 'textAfterRangeButIntersect';
}
else {
if (startPoints === 0 && endPoints === 0) {
return "textExactlyInRange";
}
else {
return 'textWithinRange';
}
}
}
}
}
}