简体   繁体   中英

Get ID of selected contenteditable element's child where cursor caret is located

I'm currently trying to make an editor using contenteditable divs, but I'm having an issue where clicking backspace in say child-2 at the start will result in merging child-1 and child-2 together, which defeats its own purpose.

I'm finding the current caret position using the function:

caret: function() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt) return sel.getRangeAt(0).startOffset;
    }
    return null;
}

Which has been working perfectly, but to fix the merging issue I need to find out which element is currently selected and use that data with the caret location to use event.preventDefault() and stop a potential merge.

This is frame that I'm using and talking about:

<div id="parent" contenteditable="true">
  <div id="child-1">
    One
  </div>
  <div id="child-2">
    Two
  </div>
  <div id="child-3">
    Three
  </div>
</div>

To find the selected element I've tried this:

console.log(document.activeElement);

To see if this prints out the ID of the child selected, though this outputs the entire parent element into the console instead of just the ID.

Use Event Delegation to easily find the clicked node. Other events such as key and mouse can be added as well.

Details are commented in demo

Demo

 // Refernce the parent of all of the target nodes var parent = document.getElementById('parent'); // Register the click event to #parent parent.addEventListener('click', idNode); // This is the callback that is invoked on each click function idNode(e) { /* If the node clicked (e.target) is not the || the registered event listener || (e.currentTarget = #parent) */ if (e.target !== e.currentTarget) { // Get the #id of clicked node var ID = e.target.id; // Reference e.target by its #id var child = document.getElementById(ID); } // Log the #id of each e.target at every click console.log('The caret is located at ' + ID); // Return the e.target as a DOM node when needed return child; } 
 <div id="parent" contenteditable="true"> <div id="child-1"> One </div> <div id="child-2"> Two </div> <div id="child-3"> Three </div> </div> 

You can apply tabindex="0" to the child elements, which makes them focusable, which will select the children when using document.activeElement (otherwise it's always the parent which has the focus):

 console.log(document.activeElement); 
 <div id="parent" contenteditable="true"> <div id="child-1" tabindex="0"> One </div> <div id="child-2" tabindex="0"> Two </div> <div id="child-3" tabindex="0"> Three </div> </div> 

After comment: I am adding a screenshot of this very snippet: I clicked into the word "Two": You can see the dotted border around that line indicating the focus status:

在此处输入图片说明

By using document.getSelection().getRangeAt(0).commonAncestorContainer.parentNode.parentNode.parentNode.id you can get the id of the parent element of the caret.

Example

 function getParentId() { var caret = document.getSelection().getRangeAt(0); var caretParent = caret.commonAncestorContainer.parentNode; console.log(caretParent.id); }
 <div id="parent" contenteditable="true"> <div id="child-1" tabindex="0"> One </div> <div id="child-2" tabindex="0"> Two </div> <div id="child-3" tabindex="0"> Three </div> </div> <button onclick="getParentId()">Get Id</button>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM