Search code examples
javascriptjqueryhtmlcontenteditable

Get Selected Element based on caret position in contenteditable Div


I'm trying to get the element that the caret is in at any given time within a contenteditable DIV.

So far, I am able to get the caret position within the text.

But I want to go a step further to actually get the element selected. For instance, if the caret is after the first letter in the word "wombat" in my example, the solution would also return the id of the selected element "wombatid" and not just the caret position. Any tips or solutions?

function getSelectionCharacterOffsetWithin(element) {
    var start = 0;
    var end = 0;
    var doc = element.ownerDocument || element.document;
    var win = doc.defaultView || doc.parentWindow;
    var sel;
    if (typeof win.getSelection != "undefined") {
        sel = win.getSelection();
        if (sel.rangeCount > 0) {
            var range = win.getSelection().getRangeAt(0);
            var preCaretRange = range.cloneRange();
            preCaretRange.selectNodeContents(element);
            preCaretRange.setEnd(range.startContainer, range.startOffset);
            start = preCaretRange.toString().length;
            preCaretRange.setEnd(range.endContainer, range.endOffset);
            end = preCaretRange.toString().length;
        }
    } else if ( (sel = doc.selection) && sel.type != "Control") {
        var textRange = sel.createRange();
        var preCaretTextRange = doc.body.createTextRange();
        preCaretTextRange.moveToElementText(element);
        preCaretTextRange.setEndPoint("EndToStart", textRange);
        start = preCaretTextRange.text.length;
        preCaretTextRange.setEndPoint("EndToEnd", textRange);
        end = preCaretTextRange.text.length;
    }
    return { start: start, end: end };
}

function reportSelection() {
  var selOffsets = getSelectionCharacterOffsetWithin( document.getElementById("editor") );
  document.getElementById("selectionLog").innerHTML = "Selection offsets: " + selOffsets.start + ", " + selOffsets.end+" <br> Selected Element's id: 'element here'";
}

window.onload = function() {
  document.addEventListener("selectionchange", reportSelection, false);
  document.addEventListener("mouseup", reportSelection, false);
  document.addEventListener("mousedown", reportSelection, false);
  document.addEventListener("keyup", reportSelection, false);
};
#editor {
  padding: 5px;
  border: solid green 1px;
}
Select something in the content below:

<div id="editor" contenteditable="true">A <i id="wombatid">wombat</i> is a marsupial native to <b id="australiaid">Australia</b></div>
<div id="selectionLog"></div>


Solution

  • To get ID you can try something like:

    document.querySelectorAll("#editor *").forEach(el => el.onclick = e => alert(e.target.id));
    

    here e.target will be your HTML element, it should work for any HTML element

    function getSelectionCharacterOffsetWithin(element) {
        var start = 0;
        var end = 0;
        var doc = element.ownerDocument || element.document;
        var win = doc.defaultView || doc.parentWindow;
        var sel;
        if (typeof win.getSelection != "undefined") {
            sel = win.getSelection();
            if (sel.rangeCount > 0) {
                var range = win.getSelection().getRangeAt(0);
                var preCaretRange = range.cloneRange();
                preCaretRange.selectNodeContents(element);
                preCaretRange.setEnd(range.startContainer, range.startOffset);
                start = preCaretRange.toString().length;
                preCaretRange.setEnd(range.endContainer, range.endOffset);
                end = preCaretRange.toString().length;
            }
        } else if ( (sel = doc.selection) && sel.type != "Control") {
            var textRange = sel.createRange();
            var preCaretTextRange = doc.body.createTextRange();
            preCaretTextRange.moveToElementText(element);
            preCaretTextRange.setEndPoint("EndToStart", textRange);
            start = preCaretTextRange.text.length;
            preCaretTextRange.setEndPoint("EndToEnd", textRange);
            end = preCaretTextRange.text.length;
        }
        return { start: start, end: end };
    }
    
    function reportSelection() {
      var selOffsets = getSelectionCharacterOffsetWithin( document.getElementById("editor") );
      document.getElementById("selectionLog").innerHTML = "Selection offsets: " + selOffsets.start + ", " + selOffsets.end+" <br> Selected Element's id: 'element here'";
    }
    
    window.onload = function() {
      document.addEventListener("selectionchange", reportSelection, false);
      document.addEventListener("mouseup", reportSelection, false);
      document.addEventListener("mousedown", reportSelection, false);
      document.addEventListener("keyup", reportSelection, false);
      document.querySelectorAll("#editor *").forEach(el => el.onclick = e => alert(e.target.id));
    };
    #editor {
      padding: 5px;
      border: solid green 1px;
    }
    Select something in the content below:
    
    <div id="editor" contenteditable="true">A <i id="wombatid">wombat</i> is a marsupial native to <b id="australiaid">Australia</b></div>
    <div id="selectionLog"></div>