Get caret HTML position in contenteditable DIV

I am having troubles figuring out how to get caret position in a DIV container that contains HTML tags.

I am using this JavaScript function to do that:

function  getCaretPosition()
{
    if (window.getSelection && window.getSelection().getRangeAt)
    {
            var range = window.getSelection().getRangeAt(0);
            var selectedObj = window.getSelection();
            var rangeCount = 0;
            var childNodes = selectedObj.anchorNode.parentNode.childNodes;
            for (var i = 0; i < childNodes.length; i++)
            {
                if (childNodes[i] == selectedObj.anchorNode)
                {
                        break;
                    }
                        if(childNodes[i].outerHTML)
                        {
                rangeCount += childNodes[i].outerHTML.length;
            }
            else if(childNodes[i].nodeType == 3)
            {
                            rangeCount += childNodes[i].textContent.length;                       
            }
        }
        return range.startOffset + rangeCount;
    }
    return -1;
}

However, it finds a caret position of the text in my DIV container, when I need to find the caret position including HTML tags. For example:

<DIV class="peCont" contenteditable="true">Text goes here along with <b>some <i>HTML</i> tags</b>.</DIV>;

(please note, that HTML tags are normal tags and are not displayed on the screen when the function is returning caret position)

If I click right between H and TML, the aforementioned function will find caret position without any problems. But I am getting the contents of DIV box in HTML format (including all tags), and if I want to insert something at that caret's position, I will be off by a few or many characters.

I went through many posts, but all I could find is either <TEXTAREA> caret postions, or functions similar to what I have posted. So far I still cannot find a solution to get a caret position in a text that has HTML formatting.

Can anyone help, please?

PS. Here's JQuery/Javascript code that I wrote for the link button:

$('#pageEditor').on('click', '.linkURL', function()
{
    var cursorPosition;
    cursorPosition = getCaretPosition();
    var contentID = $(this).parent().parent().attr('id');
    var userSelected = getSelectionHtml();
    var checkLink = userSelected.search('</a>');
    var anchorTag = 0;
    if(checkLink == -1)
    {
        var currentContents = $('#'+contentID+' .peCont').html();
        var indexOfSelection = currentContents.indexOf(userSelected);
        var getPossibleAnchor = currentContents.slice(indexOfSelection, indexOfSelection+userSelected.length+6);
        anchorTag = getPossibleAnchor.search('</a>');
    }

    if(checkLink > 0 || anchorTag > 0)
    {
        //alert(checkLink);
        document.execCommand('unlink', false, false);

    }
    else
    {
        $('#'+contentID+' .peCont').append('<div id="linkEntry"><label for="urlLink">Please enter URL for the link:<label><input type="text" id="urlLink" /></div>');
        $('#linkEntry').dialog({
             buttons: { 
                "Ok": function() 
                {
                    var attribute = $('#urlLink').val();
                    var newContentWithLink = '';
                    if(attribute != '')
                    {
                        if(userSelected != '')
                        {
                            var currentContent = $('#'+contentID+' .peCont').html();
                            var replacement = '<a href="'+attribute+'">'+userSelected+'</a>';
                            newContentWithLink = currentContent.replace(userSelected, replacement);
                        }
                        else
                        {
                            var currentTextContent = $('#'+contentID+' .peCont').html();
                            var userLink = '<a href="'+attribute+'">'+attribute+'</a>';
                            if(cursorPosition > 0)
                            {
                                var contentBegin = currentTextContent.slice(0,cursorPosition);
                                var contentEnd = currentTextContent.slice(cursorPosition,currentTextContent.length);
                                newContentWithLink = contentBegin+userLink+contentEnd;
                            }
                            else
                            {
                                newContentWithLink = attribute+currentTextContent;
                            }
                        }
                        $('#'+contentID+' .peCont').empty();
                        $('#'+contentID+' .peCont').html(newContentWithLink);
                    }
                    $(this).dialog("close"); 
                } },
             closeOnEscape:true,
             modal:true,
             resizable:false,
             show: { effect: 'drop', direction: "up" },
             hide: { effect: 'drop', direction: "down" },
             width:460,
             closeText:'hide',
             close: function()
             {
                $(this).remove();
             }
        });

        $('#linkEntry').on('keypress', function(urlEnter)
        {
            if(urlEnter.which == 13)
            {
                var attribute = $('#urlLink').val();
                var newContentWithLink = '';
                if(userSelected != '')
                {
                    var currentContent = $('#'+contentID+' .peCont').html();
                    var replacement = '<a href="'+attribute+'">'+userSelected+'</a>';
                    newContentWithLink = currentContent.replace(userSelected, replacement);
                }
                else
                {
                    var currentTextContent = $('#'+contentID+' .peCont').html();
                    var userLink = '<a href="'+attribute+'">'+attribute+'</a>';
                    if(cursorPosition > 0)
                    {
                        var contentBegin = currentTextContent.slice(0,cursorPosition);
                        var contentEnd = currentTextContent.slice(cursorPosition,currentTextContent.length);
                        newContentWithLink = contentBegin+userLink+contentEnd;
                    }
                    else
                    {
                        newContentWithLink = attribute+currentTextContent;
                    }
                }
                $('#'+contentID+' .peCont').empty();
                $('#'+contentID+' .peCont').html(newContentWithLink);
                $(this).dialog("close");
            }
        });
    }
});

Answers


I created a simple fiddle for you that does what you want.

This should work in recent versions of Firefox, Chrome and Safari.

It's your homework to add Opera and IE support if you need.


Need Your Help

android fast pixel access and manipulation

android image android-canvas draw pixel

I'm trying to port an emulator that i have written in java to android. Things have been going nicely, I was able to port most of my codes with minor changes however due to how emulation works, I ne...