Get caret index in contenteditable div including tags

helldrain picture helldrain · May 24, 2013 · Viewed 20.6k times · Source

I have a contentEditable div in which I have multiple tags (br, b, u, i) and text.

I need to get the caret index position relative to the div, including all the tags.

For example:

<div id="h" contenteditable="true">abc<b>def<br>ghi</b>jkl</div>

If the cursor is between g and h, I need the caret index position to be 14. The problem is that the found methods that use a treeWalker do not work in this case. The bold tag is not found... probably because it isn't closed. Also I have tried several methods but still no luck.

I need it to work in Firefox. Thank you.

Answer

Eric McCormick picture Eric McCormick · May 24, 2013

Have you tried this? Get a range's start and end offset's relative to its parent container

Direct link to the jsfiddle: https://jsfiddle.net/TjXEG/1/

Function code:

function getCaretCharacterOffsetWithin(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;
}

function showCaretPos() {
    var el = document.getElementById("test");
    var caretPosEl = document.getElementById("caretPos");
    caretPosEl.innerHTML = "Caret position: " + getCaretCharacterOffsetWithin(el);
}

document.body.onkeyup = showCaretPos;
document.body.onmouseup = showCaretPos;