用字符串替换文本选择而不破坏选择之外的标记

时间:2013-04-24 15:56:44

标签: javascript jquery html replace

假设我有这个HTML:

<div class="edit" contenteditable="true">
   <b>Example text</b>
   Text outside
   <b>
      <i>
         <u>underlined and italic and bold</u>
      italic and bold</i></b>
   more Text
   <br>
   after the line break
</div>

为了方便起见,我有这个javascript函数,它返回给定元素中选择结束的偏移量:

var getCaretCharacterOffsetWithin = function(element) {
  var caretOffset = 0;
  if (typeof window.getSelection != "undefined") {
    var range = window.getSelection().getRangeAt(0);
    var preCaretRange = range.cloneRange();
    preCaretRange.selectNodeContents(element);
    preCaretRange.setEnd(range.endContainer, range.endOffset);
    caretOffset = preCaretRange.toString().length;
  } else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
    var textRange = document.selection.createRange();
    var preCaretTextRange = document.body.createTextRange();
    preCaretTextRange.moveToElementText(element);
    preCaretTextRange.setEndPoint("EndToEnd", textRange);
    caretOffset = preCaretTextRange.text.length;
  }
  return caretOffset;
 }

假设用户已选择从outside开始并在italic and bold内结束,所以它看起来像这样:

"outsideunderlined and italic and bolditalic and bo"

如何在不损坏<b>Example text</b>和选择后出现的文本的情况下替换整个字符串。 如果我们替换的字符串是空字符串"",结果应如下所示:

<div class="edit" contenteditable="true">
   <b>Example text</b>
   Text 
   ld
   more Text
   <br>
   after the line break
</div>

我不关心选择中的标签是否保留我不确定哪种方式更容易。

如果您不清楚,请询问。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

这个答案不适用于IE8-(现在)。此函数用replaceString替换所选文本,并选择新插入的节点。您可能希望之后规范化DOM,可能是相邻或空文本节点。

问我有什么不清楚。

function replSel(replaceString) {
    var sel = getSelection(), rng, startNode, endNode, comAnc, sOff;
    if (sel.rangeCount) {
        rng = sel.getRangeAt(0);
        sOff = rng.startOffset;
        if (rng.startContainer === rng.endContainer) {
            rng.endContainer.nodeValue =
                  rng.endContainer.nodeValue.substring(0, sOff) + replaceString
                  + rng.endContainer.nodeValue.substring(rng.endOffset);
            rng.setStart(rng.startContainer, sOff);
            rng.setEnd(rng.endContainer, sOff + replaceString.length);
        } else {
            comAnc = rng.commonAncestorContainer;
            rng.startContainer.nodeValue =
                    rng.startContainer.nodeValue.substring(0, sOff);
            // rng.startOffset is set to 0 when the node value is changed
            // That's fine for the range's end, but not for the start.
            rng.setStart(rng.startContainer, sOff);
            rng.endContainer.nodeValue =
                    rng.endContainer.nodeValue.substring(rng.endOffset);
            startNode = rng.startContainer;
            while (startNode.parentNode !== comAnc) {
                while (startNode.nextSibling)
                    startNode.parentNode.removeChild(startNode.nextSibling);
                startNode = startNode.parentNode;
            }
            endNode = rng.endContainer;
            while (endNode.parentNode !== comAnc) {
                while (endNode.previousSibling)
                    endNode.parentNode.removeChild(endNode.previousSibling);
                endNode = endNode.parentNode;
            }
            while (startNode.nextSibling !== endNode)
                comAnc.removeChild(startNode.nextSibling);
            comAnc.insertBefore(
                    document.createTextNode(replaceString), endNode);
        }
        sel.removeAllRanges();
        sel.addRange(rng);
    }
}
相关问题