ilP*_*tiz 1 javascript range selection contenteditable rich-text-editor
我正在尝试一下contentEditable并遇到这个问题:我有以下js片段
var range = document.getSelection().getRangeAt(0);
var newNode = document.createElement("span");
newNode.className = "customStyle";
range.surroundContents(newNode);
这个HTML片段:
<ul>
    <li>the <b>only entry</b> of the list</li>
</ul>
<p>Some text here in paragraph</p>
js代码允许使用<span>标记包装当前选择.
当选择包括整个HTML标签(例如,选择'唯一条目')时,它完美地工作,但当然,当选择仅包括其结尾之一时(例如,从'条目'选择'有些',两者都包括在内) .
虽然我知道这个问题并非无足轻重,但我正在寻找有关最佳方法的建议.提前致谢!
如果您只对包装文本部分感兴趣,那么基本方法是:
<span>元素中的每个文本节点这是我的Rangy库的类应用程序模块采用的方法.
我创建了一个例子,主要是使用改编自Rangy的代码:
function getNextNode(node) {
    var next = node.firstChild;
    if (next) {
        return next;
    }
    while (node) {
        if ( (next = node.nextSibling) ) {
            return next;
        }
        node = node.parentNode;
    }
}
function getNodesInRange(range) {
    var start = range.startContainer;
    var end = range.endContainer;
    var commonAncestor = range.commonAncestorContainer;
    var nodes = [];
    var node;
    // Walk parent nodes from start to common ancestor
    for (node = start.parentNode; node; node = node.parentNode) {
        nodes.push(node);
        if (node == commonAncestor) {
            break;
        }
    }
    nodes.reverse();
    // Walk children and siblings from start until end is found
    for (node = start; node; node = getNextNode(node)) {
        nodes.push(node);
        if (node == end) {
            break;
        }
    }
    return nodes;
}
function getNodeIndex(node) {
    var i = 0;
    while ( (node = node.previousSibling) ) {
        ++i;
    }
    return i;
}
function insertAfter(node, precedingNode) {
    var nextNode = precedingNode.nextSibling, parent = precedingNode.parentNode;
    if (nextNode) {
        parent.insertBefore(node, nextNode);
    } else {
        parent.appendChild(node);
    }
    return node;
}
// Note that we cannot use splitText() because it is bugridden in IE 9.
function splitDataNode(node, index) {
    var newNode = node.cloneNode(false);
    newNode.deleteData(0, index);
    node.deleteData(index, node.length - index);
    insertAfter(newNode, node);
    return newNode;
}
function isCharacterDataNode(node) {
    var t = node.nodeType;
    return t == 3 || t == 4 || t == 8 ; // Text, CDataSection or Comment
}
function splitRangeBoundaries(range) {
    var sc = range.startContainer, so = range.startOffset, ec = range.endContainer, eo = range.endOffset;
    var startEndSame = (sc === ec);
    // Split the end boundary if necessary
    if (isCharacterDataNode(ec) && eo > 0 && eo < ec.length) {
        splitDataNode(ec, eo);
    }
    // Split the start boundary if necessary
    if (isCharacterDataNode(sc) && so > 0 && so < sc.length) {
        sc = splitDataNode(sc, so);
        if (startEndSame) {
            eo -= so;
            ec = sc;
        } else if (ec == sc.parentNode && eo >= getNodeIndex(sc)) {
            ++eo;
        }
        so = 0;
    }
    range.setStart(sc, so);
    range.setEnd(ec, eo);
}
function getTextNodesInRange(range) {
    var textNodes = [];
    var nodes = getNodesInRange(range);
    for (var i = 0, node, el; node = nodes[i++]; ) {
        if (node.nodeType == 3) {
            textNodes.push(node);
        }
    }
    return textNodes;
}
function surroundRangeContents(range, templateElement) {
    splitRangeBoundaries(range);
    var textNodes = getTextNodesInRange(range);
    if (textNodes.length == 0) {
        return;
    }
    for (var i = 0, node, el; node = textNodes[i++]; ) {
        if (node.nodeType == 3) {
            el = templateElement.cloneNode(false);
            node.parentNode.insertBefore(el, node);
            el.appendChild(node);
        }
    }
    range.setStart(textNodes[0], 0);
    var lastTextNode = textNodes[textNodes.length - 1];
    range.setEnd(lastTextNode, lastTextNode.length);
}
document.onmouseup = function() {
    if (window.getSelection) {
        var templateElement = document.createElement("span");
        templateElement.className = "highlight";
        var sel = window.getSelection();
        var ranges = [];
        var range;
        for (var i = 0, len = sel.rangeCount; i < len; ++i) {
            ranges.push( sel.getRangeAt(i) );
        }
        sel.removeAllRanges();
        // Surround ranges in reverse document order to prevent surrounding subsequent ranges messing with already-surrounded ones
        i = ranges.length;
        while (i--) {
            range = ranges[i];
            surroundRangeContents(range, templateElement);
            sel.addRange(range);
        }
    }
};.highlight {
  font-weight: bold;
  color: red;
}Select some of this text and it will be highlighted:
<ul>
    <li>the <b>only entry</b> of the list</li>
</ul>
<p>Some text here in paragraph</p>
<ul>
    <li>the <b>only entry</b> of the list</li>
</ul>
<p>Some text here in paragraph</p>
<ul>
    <li>the <b>only entry</b> of the list</li>
</ul>
<p>Some text here in paragraph</p>