The caret and the stick

From XPUB & Lens-Based wiki

PZI'er Andre wonders, if only I could know where in some formatted HTML the user has clicked. I know I can use a textarea but I want to have html, and I don't really want the text in question to be editable.

Here's a solution using html5's new contenteditable attribute and some helpful "selection" code from a popular answer website.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>

<script src="/lib/jquery/jquery.js"></script>
<script>
$(document).ready(function () {
    $("#editable").focus(function() {
        captureSelection();
        console.log("change of focus", selection, range);
        $(this).blur();
    });

// Populates selection and range variables
var editable = document.getElementById('editable'),
    selection, range;

var captureSelection = function(e) {
    // Don't capture selection outside editable region
    var isOrContainsAnchor = false,
        isOrContainsFocus = false,
        sel = window.getSelection(),
        parentAnchor = sel.anchorNode,
        parentFocus = sel.focusNode;

    while(parentAnchor && parentAnchor != document.documentElement) {
        if(parentAnchor == editable) {
            isOrContainsAnchor = true;
        }
        parentAnchor = parentAnchor.parentNode;
    }

    while(parentFocus && parentFocus != document.documentElement) {
        if(parentFocus == editable) {
            isOrContainsFocus = true;
        }
        parentFocus = parentFocus.parentNode;
    }

    if(!isOrContainsAnchor || !isOrContainsFocus) {
        return;
    }

    selection = window.getSelection();

    // Get range (standards)
    if(selection.getRangeAt !== undefined) {
        range = selection.getRangeAt(0);

    // Get range (Safari 2)
    } else if(
        document.createRange &&
        selection.anchorNode &&
        selection.anchorOffset &&
        selection.focusNode &&
        selection.focusOffset
    ) {
        range = document.createRange();
        range.setStart(selection.anchorNode, selection.anchorOffset);
        range.setEnd(selection.focusNode, selection.focusOffset);
    } else {
        // Failure here, not handled by the rest of the script.
        // Probably IE or some older browser
    }
};

// Recalculate selection while typing
editable.onkeyup = captureSelection;


});
</script>
<style>
body { margin: 50px; }
</style>
</head>
<body>
<div contenteditable id="editable">
Hello <s>world</s>.
</div>

</body>
</html>