Получить положение курсора в области contentEditable, содержащей содержимое HTML


у меня есть contentEditable элемент (может быть p, div, ...) и я хотел бы получить позицию каретки (курсора) в нем. Обычно я могу достичь этого с помощью этого фрагмента кода:

var position = window.getSelection().getRangeAt(0).startOffset;

Это прекрасно работает, пока элемент содержит только текст. Но когда элемент содержит некоторое форматирование HTML, возвращенная позиция относительно позиции каретки внутри включенного элемента HTML.

предположим, что содержимое contentEditable элемента таково:

AB<b>CD</b>EF

Если каре внутри <b></b>, скажем, между C и D, возвращаемая позиция с вышеуказанным кодом равна 1 вместо 3 (подсчитывается с начала содержимого contentEditable элемента)

может ли кто-нибудь придумать решение для этого ?

3 52

3 ответа:

обновление

Я написал более простую версию этого, которая также работает в IE

https://stackoverflow.com/a/4812022/96100

Ответ

это на самом деле более полезный результат, чем символа в тексте всего документа:startOffset свойства спектр дом (который является тем, что window.getSelection().getRangeAt() returns) - это смещение относительно его startContainer свойство (которое, кстати, не всегда является текстовым узлом). Однако, если вы действительно хотите смещение символа, вот функция, которая это сделает.

вот живой пример:http://jsfiddle.net/timdown/2YcaX/

вот функция:

function getCharacterOffsetWithin(range, node) {
    var treeWalker = document.createTreeWalker(
        node,
        NodeFilter.SHOW_TEXT,
        function(node) {
            var nodeRange = document.createRange();
            nodeRange.selectNode(node);
            return nodeRange.compareBoundaryPoints(Range.END_TO_END, range) < 1 ?
                NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
        },
        false
    );

    var charCount = 0;
    while (treeWalker.nextNode()) {
        charCount += treeWalker.currentNode.length;
    }
    if (range.startContainer.nodeType == 3) {
        charCount += range.startOffset;
    }
    return charCount;
}

Это очень старый пост, но все же одним из первых результатов поиска в Google, так что, возможно, еще пригодится. Это работает для меня, чтобы получить правильное положение с учетом html-тегов и новых строк, а также (протестировано на Firefox):

function getCaretPosition (node) {
    var range = window.getSelection().getRangeAt(0),
        preCaretRange = range.cloneRange(),
        caretPosition,
        tmp = document.createElement("div");

    preCaretRange.selectNodeContents(node);
    preCaretRange.setEnd(range.endContainer, range.endOffset);
    tmp.appendChild(preCaretRange.cloneContents());
    caretPosition = tmp.innerHTML.length;
    return caretPosition;
}

Он использует функциональность cloneContents для того, чтобы получить фактический HTML и добавляет пробуя на временное див для того, чтобы получить длину в HTML.

Если вы хотите вставить элемент, то вы могли бы попробовать сделать что-то вроде этого:

// Get range
var range = document.caretRangeFromPoint(event.clientX, event.clientY);
if (range)
  range.insertNode(elementWhichYouWantToAddToContentEditable);