Подтвердить что ты не робот

Получить позицию каретки (курсора) в 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 (подсчитывается с начала содержимого содержимого contentable)

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

4b9b3361

Ответ 1

UPDATE

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

fooobar.com/questions/21551/...

Старый ответ

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

Вот живой пример: 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;
}

Ответ 2

Это очень старый пост, но все же один из первых результатов поиска в 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 и добавляет documentfragment во временный div, чтобы получить длину html.

Ответ 3

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

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