Caret Position

Show the caret position when selecting text in a <textarea> or contenteditable <div>.

by secretgspot

HTML

<p>Non-editable text. Editable is below:</p>
<div id="test" contenteditable="true">Hello, some <b>bold</b> and <i>italic and <b>bold</b></i> text</div>
<table>
    <thead>
        <tr>
            <th>What</th>
            <th>Position</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Current:</td>
            <td id="caretPos">n/a</td>
        </tr>
        <tr>
            <td>Selection begin:</td>
            <td id="caretBegin">n/a</td>
        </tr>
        <tr>
            <td>Selection end:</td>
            <td id="caretEnd">n/a</td>
        </tr>
        <tr>
            <td>HTML tag begin:</td>
            <td id="htmlBegin">n/a</td>
        </tr>
        <tr>
            <td>HTML tag end:</td>
            <td id="htmlEnd">n/a</td>
        </tr>
        <tr>
            <td>Word begin:</td>
            <td id="wordBegin">n/a</td>
        </tr>
    </tbody>
</table>

<p>&nbsp;</p>
<textarea id="test2" rows="3" cols="30">Here is some text; try to select some.</textarea>
<table>
    <thead>
        <tr>
            <th>What</th>
            <th>Position</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Current:</td>
            <td id="caretPos2">n/a</td>
        </tr>
        <tr>
            <td>Selection begin:</td>
            <td id="caretBegin2">n/a</td>
        </tr>
        <tr>
            <td>Selection end:</td>
            <td id="caretEnd2">n/a</td>
        </tr>
        <tr>
            <td>Selection size:</td>
            <td id="caretSize2">n/a</td>
        </tr>
        <!--
        <tr>
            <td>Word begin:</td>
            <td id="wordBegin2">n/a</td>
        </tr>
        -->
    </tbody>
</table>

CSS

body {
    font-family: Calibri, Verdana, Arial, Helvetica, sans-serif;
    color: #444
}

#test, #test2 {
    font-family: Consolas, "Courier New", Courier, monospace;
    color: #000;
    margin-top: 0.5em;
    font-size: 1em;
}

table {
    border-collapse: collapse;
    margin: 1em;
}
th, td {
    border: 1px solid #444;
    padding: 0.3em;
}
th { font-weight: bold; }

JavaScript

var ie = (typeof document.selection != "undefined" && document.selection.type != "Control") && true;
var w3 = (typeof window.getSelection != "undefined") && true;



function getCaretPosition(element) {
    var caretOffset = 0;
    if (w3) {
        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 (ie) {
        var textRange = document.selection.createRange();
        var preCaretTextRange = document.body.createTextRange();
        preCaretTextRange.moveToElementText(element);
        preCaretTextRange.setEndPoint("EndToEnd", textRange);
        caretOffset = preCaretTextRange.text.length;
    }
    return caretOffset;
}

function getCaretHTMLBegin(element) {
    var caretOffset = 0;
    if (w3) {
        var range = window.getSelection().getRangeAt(0);
        var preCaretRange = range.cloneRange();
        preCaretRange.selectNodeContents(element);
        preCaretRange.setEnd(range.endContainer, range.beginOffset);
        caretOffset = preCaretRange.toString().length;
    } else if (ie) {
        caretOffset = 'n/a';
    }
    return caretOffset;
}

function getCaretBegin(element) {
    var caretOffset = 0;
    if (w3) {
        var range = window.getSelection().getRangeAt(0);
        var preCaretRange = range.cloneRange();
        preCaretRange.selectNodeContents(element);
        preCaretRange.setEnd(range.endContainer, range.beginOffset);
        caretOffset = preCaretRange.toString().length;
    } else if (ie) {
        var textRange = document.selection.createRange();
        var preCaretTextRange = document.body.createTextRange();
        preCaretTextRange.moveToElementText(element);
        preCaretTextRange.setEndPoint("EndToStart", textRange);
        caretOffset = preCaretTextRange.text.length;
    }
    return...