narawagames narawagames - 2 months ago 7
HTML Question

How do I get the element being edited?

I'm developing a webapp, and I'm having a problem with the JavaScript.

The following is a simplified version of the HTML causing the problem. I have some nested

contenteditable
divs
(I replaced the real content with placeholder text):

<div contenteditable="true" id="div1">
text
<div contenteditable="inherit" id="div2">
text
<div contenteditable="inherit" id="div3">
text
</div>
text
</div>
text
</div>


I want to get the element that's selected (being edited by the user) via JavaScript, but so far I haven't found a way to do it (successfully).




What I have tried and why it doesn't work:

I have tried using
document.activeElement
, which is supposed to return whichever element is in focus. Normally this works, but it doesn't produce the desired result when working with nested
contenteditable
elements. Instead of returning the element that's being edited by the user, it returns the uppermost
contenteditable
ancestor.

For instance, if
div2
was selected/being edited,
document.activeElement
returns
div1
. If
div3
was selected/being edited,
document.activeElement
also returns
div1
.

So I guess
document.activeElement
is not the right way to go about this.





How do I get the most specific element that's being edited, not just its uppermost
contenteditable
ancestor?

Answer

I did it by inserting a dummy element at the caret position and finding it's direct parent.

function getActiveDiv() {
    var sel = window.getSelection();
    var range = sel.getRangeAt(0);
    var node = document.createElement('span');
    range.insertNode(node);
    range = range.cloneRange();
    range.selectNodeContents(node);
    range.collapse(false);
    sel.removeAllRanges();
    sel.addRange(range);
    var activeDiv = node.parentNode;
    node.parentNode.removeChild(node);
    return activeDiv;
}

I did an example on fiddle: https://jsfiddle.net/shhe05cj/4/

I run it on every keypress event that's bind to the relevant divs.

I based it on another thread that did something similar:Set caret position right after the inserted element in a contentEditable div

Comments