12

Given this HTML code:

<div contenteditable>
    ....
    <span> child-element </span>
    ....
</div>

When the user clicks on the SPAN element (in order to place the caret inside it), and then presses a character key on the keyboard (in order to edit the text-content of the SPAN element), a keydown, keypress, and keyup event will be fired.

However, the target property of those corresponding event objects is not the SPAN element, but the DIV element itself.

Live demo: (Also on jsFiddle)

$('div').keydown(function(e) {
    alert( e.target.nodeName );
});
div { border:2px solid red; padding:10px; margin:10px; }
span { background-color:yellow; }
<div contenteditable>
    BEFORE
    <span>SPAN</span>
    AFTER
</div>

<p>
    Click on the yellow SPAN element (to place the caret inside it), and then press a character key (to change the text-content of the SPAN element). The alert-box shows that the event-target is the DIV element, not the SPAN element...
</p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

How can I determine whether or not the key-event occurred inside a SPAN element?

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385

2 Answers2

17

This can be done using the selection APIs:

$('div').keydown(function(e) {
    if (document.selection) {
        alert(document.selection.createRange().parentElement().tagName); // IE
    } else {
        // everyone else
        alert(window.getSelection().anchorNode.parentNode.tagName); 
    }
});

Note: The above example is simplistic. See the SO post linked below for a complete solution to the selection problem.

Demo (also on jsFiddle):

$('div').keydown(function(e) {
    if (document.selection)
        alert(document.selection.createRange().parentElement().tagName); // IE
    else
        alert(window.getSelection().anchorNode.parentNode.tagName); // everyone else
});
div { border:2px solid red; padding:10px; margin:10px; }
span { background-color:yellow; }
<div contenteditable>
    BEFORE
    <span>SPAN</span>
    AFTER
</div>

<p>
    Click on the yellow SPAN element (to place the caret inside it), and then press a character key (to change the text-content of the SPAN element). The alert-box shows that the event-target is the DIV element, not the SPAN element...
</p>
<div id="stuff"/>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

References:

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Wayne
  • 59,728
  • 15
  • 131
  • 126
  • @Šime - Updated with an IE solution. I found the linked post while researching this. There are more complete answers there. – Wayne Jul 19 '11 at 20:11
  • One point: `anchorNode` isn't guaranteed to be a text node in all browsers and all situations. Best to check its node type to see if it's an element to be on the safe side. – Tim Down Jul 19 '11 at 23:29
  • @Tim - Yes, definitely. Anyone using my answer really needs to read the other linked SO question, which gets into the specifics. The only reason I'd say this isn't a dupe is because it's in the context of `contenteditable` specifically. – Wayne Jul 19 '11 at 23:43
  • @Tim - By the way, glad you reinforced this. Most range code I've seen in the wild assumes that start and end nodes are always text nodes, even though the spec clearly states that they aren't. – Wayne Jul 19 '11 at 23:51
0

Making the whole div editable means that <span> tag is nothing but text content. If you just want the span to be editable, set contentEditable on the span itself.

Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • I need the whole DIV to be editable. I use the SPAN elements to give certain words specific styling and behavior... – Šime Vidas Jul 19 '11 at 19:49
  • This is incorrect. The child elements are still there, and can still be accessed and manipulated. Example: http://jsfiddle.net/o90Lm8jr/ – T.J. Crowder Jul 08 '18 at 10:42