Disporre un nodo di testo selezionato con estensione

Voglio racchiudere un testo selezionato in un contenitore div con span, è ansible?

Un utente selezionerà un testo e farà clic su un pulsante, sul pulsante clic sull’evento Voglio avvolgere il testo selezionato con l’elemento span. Posso ottenere il testo selezionato usando window.getSelection() ma come sapere la sua esatta posizione nella struttura DOM?

Se la selezione è completamente contenuta all’interno di un singolo nodo di testo, è ansible farlo utilizzando il metodo surroundContents() dell’intervallo ottenuto dalla selezione. Tuttavia, questo è molto fragile: non funziona se la selezione non può essere logicamente circondata in un singolo elemento (generalmente, se l’intervallo supera i limiti del nodo, sebbene questa non sia la definizione precisa ). Per fare questo nel caso generale, è necessario un approccio più complicato.

Inoltre, DOM Range e window.getSelection() non sono supportati in IE <9. Avrai bisogno di un altro approccio per quei browser. Puoi utilizzare una libreria come il mio Rangy per normalizzare il comportamento del browser e potresti trovare il modulo dell'applier di classe utile per questa domanda.

Semplice esempio di surroundContents() jsFiddle: http://jsfiddle.net/VRcvn/

Codice:

 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.  

è ansible. È necessario utilizzare l’intervallo API e il metodo Range.surroundContents (). Posiziona il nodo in cui il contenuto viene inserito all’inizio dell’intervallo specificato. vedere https://developer.mozilla.org/en/DOM/range.surroundContents

surroundContents funziona solo se la tua selezione contiene solo testo e nessun HTML. Ecco una soluzione più flessibile e cross-browser. Questo inserirà una span come questa:

  

Lo span viene inserito prima della selezione, davanti al tag HTML di apertura più vicino.

 var span = document.createElement("span"); span.id = "new_selection_span"; span.innerHTML = ''; 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(); } 

Si prega di trovare il codice sottostante sarà utile per il wrapping del tag span per tutti i tipi di tag. Per favore passa attraverso il codice e usa la logica per la tua implementazione.

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