Search code examples
javascriptselectiondom-selection

document.getSelection with carriage return in selection


I've tried many different things and am at a loss. The code below illustrates the issue. I have an editable element.

If I select a paragraph of text, the Selection.anchorNode is a #text node.

If when selecting a paragraph I include a carriage return preceding the paragraph, Selection.anchorNode is instead the containing span element.

What I need to know is what the offset is from the start of the span element's innerText value. When a carriage return IS NOT included in the selection, I am able simply to analyze the sibling nodes of the anchorNode. But when a carriage return IS included in the selection, I don't seem to have the information to achieve this.

Any guidance as to what I am missing would be appreciated.

function showResult() {
  let sel = document.getSelection();
  document.getElementById("output").textContent ="document.getSelection().anchorNode.nodeName: " +  sel.anchorNode.nodeName;
}
document.getElementById("textContainer").innerText = "This is the first paragraph\n\nSelecting this paragraph with and without the preceding carriage return yields very different anchorNodes";
#textContainer {
  position: relative;
  display: inline-block;
  width: 400px;
  height: 100px;
  border: 1px solid steelblue;
  margin: 5px;
}

#output {
  position: relative;
  width: 400px;
  height: 100px;
  border: 1px solid steelblue;
  margin: 5px;
}
<div>
    <span id="textContainer" contenteditable="true"></span>
</div>
<input  type="button" onclick="showResult()" value="Write selection object to console" />
<div id="output">
</div>


Solution

  • It seems browser return parent node while selecting carriage return so you can use if condition for this situation:

    sel.anchorNode.hasChildNodes()?sel.anchorNode.childNodes[0].nodeName:sel.anchorNode.nodeName
    

    function showResult() {
      let sel = document.getSelection();
      document.getElementById("output").textContent ="document.getSelection().anchorNode.nodeName: " +  (sel.anchorNode.hasChildNodes()?sel.anchorNode.childNodes[0].nodeName:sel.anchorNode.nodeName);
    }
    document.getElementById("textContainer").innerText = "This is the first paragraph\n\nSelecting this paragraph with and without the preceding carriage return yields very different anchorNodes";
    #textContainer {
      position: relative;
      display: inline-block;
      width: 400px;
      height: 100px;
      border: 1px solid steelblue;
      margin: 5px;
    }
    
    #output {
      position: relative;
      width: 400px;
      height: 100px;
      border: 1px solid steelblue;
      margin: 5px;
    }
    <div>
        <span id="textContainer" contenteditable="true"></span>
    </div>
    <input  type="button" onclick="showResult()" value="Write selection object to console" />
    <div id="output">
    </div>