Rangy + ContentEditable +设置插入和替换选择

时间:2011-12-13 13:10:47

标签: jquery html contenteditable rangy

我有以下代码片段将插入符号设置为给定的索引index

var el = $("#subjectMessage"), index = 9 ;
var range = rangy.createRange();
range.setStart(el[0].childNodes[0], index);
range.collapse(true);
var sel = rangy.getSelection();
sel.setSingleRange(range);

当我将输入元素添加到contentEditable div时会出现问题,我不能再将插入符号设置在所需的位置了。

我想将这些输入视为div中的一个位置(就好像它们只是一个字符一样)。

除此之外,我还需要类似的代码来替换此contentEditable div中的选择,并使用我自己的一些文本,并且我并不熟悉( at all )与rangy一起了解如何使这项工作......

非常欢迎所有帮助!

这是你可以玩的小提琴:

http://jsfiddle.net/ee93P/

1 个答案:

答案 0 :(得分:7)

Rangy的Selection和Range API是标准DOM Selection和Range API的超集,因此适用于MDN(RangeSelection等地方的文档。

您遇到的问题是范围边界表示为包含DOM节点内的偏移量。例如,在下面的HTML中,插入符号表示为管道符:

<p>Foo<br>b|ar</p>

...插入符号范围的起点和终点边界相同,并在文本节点“bar”中设置为偏移1。

如果要将位置设置为<p>元素的文本内容中的偏移量,则需要进行一些DOM遍历。我基于another answer of mine编写了一个这样的实现。这是天真的实现:它没有考虑任何可能被隐藏的文本(例如,通过CSS或通过在一个或元素内部),并且可能有浏览器差异(IE与其他所有内容)有换行符,并且需要没有折叠空格的帐户(例如2个或更多连续的空格字符折叠到页面上的一个可见空间)。这是一个棘手的事情,这是正确的,这就是为什么我一般不会推荐它。我打算为Rangy写一个基于文本的模块来处理所有这些,但我还没有开始。

http://jsfiddle.net/ee93P/2/

代码:

function setCaretCharIndex(containerEl, index) {
    var charIndex = 0, stop = {};

    function traverseNodes(node) {
        if (node.nodeType == 3) {
            var nextCharIndex = charIndex + node.length;
            if (index >= charIndex && index <= nextCharIndex) {
                rangy.getSelection().collapse(node, index - charIndex);
                throw stop;
            }
            charIndex = nextCharIndex;
        }
        // Count an empty element as a single character. The list below may not be exhaustive.
        else if (node.nodeType == 1
                 && /^(input|br|img|col|area|link|meta|link|param|base)$/i.test(node.nodeName)) {
            charIndex += 1;
        } else {
            var child = node.firstChild;
            while (child) {
                traverseNodes(child);
                child = child.nextSibling;
            }
        }
    }

    try {
        traverseNodes(containerEl);
    } catch (ex) {
        if (ex != stop) {
            throw ex;
        }
    }
}