El siguiente código será útil para envolver la etiqueta span para todo tipo de etiquetas. Por favor revise el código y use la lógica para su implementación.
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';
}
}
}
}
}
}
¿Cómo podemos envolver el texto seleccionado con un lapso si el texto seleccionado cruza los límites del nodo? Cualquier solución (no importa cuán complicada) sería muy apreciada. –
@JoshGrinberg: Eso no sería posible porque habría etiquetas no coincidentes (por ejemplo, 'foo bar baz'). Probablemente, primero tendría que manipular las etiquetas ya existentes para que el área que desea envolver solo esté contenida en un nodo. – rvighne
@Tim Down Estoy usando su biblioteca rangy para crear notas en el texto seleccionado.Casi lo he hecho, pero me he quedado atascado en un problema: mostrar un punto antes del texto seleccionado, pero en el caso de elementos múltiples, cuando trato de crear una nota sobre eso, aparece el punto varias veces, debido a la creación de varias etiquetas de extensión debido a elementos múltiples ¿Cómo puedo aplicar una clase en el primer nodo para el texto seleccionado? –