3

I am trying to implement a custom text-editor functionality inside shadow-dom. And I need to get the current cursor position inside the contenteditable div.

I have already tried a couple of methods. But none of them gave the desired output.

2 Answers2

0

Try out as,

/*
style="-webkit-user-select:text;" is needed for iPad

*/
function getCaretCharacterOffsetWithin(element) {
  var caretOffset = 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.endContainer, range.endOffset);
      caretOffset = 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("EndToEnd", textRange);
    caretOffset = preCaretTextRange.text.length;
  }
  return caretOffset;
}

function getCaretPosition() {
  if (window.getSelection && window.getSelection().getRangeAt) {
    var range = window.getSelection().getRangeAt(0);
    var selectedObj = window.getSelection();
    var rangeCount = 0;
    var childNodes = selectedObj.anchorNode.parentNode.childNodes;
    for (var i = 0; i < childNodes.length; i++) {
      if (childNodes[i] == selectedObj.anchorNode) {
        break;
      }
      if (childNodes[i].outerHTML)
        rangeCount += childNodes[i].outerHTML.length;
      else if (childNodes[i].nodeType == 3) {
        rangeCount += childNodes[i].textContent.length;
      }
    }
    return range.startOffset + rangeCount;
  }
  return -1;
}

function showCaretPos(event) { // event parameter added 
  // This is the position object of pointer
  var obj = {x : event.clientX,
                 y : event.clientY};
                 
  console.log(obj);
                 
  var el = document.getElementById("test");
  var caretPosEl = document.getElementById("caretPos");
  caretPosEl.innerHTML = "Caret position: " +
    getCaretPosition();
  getCaretCharacterOffsetWithin(el);
}

document.body.onkeyup = showCaretPos;
document.body.onmouseup = showCaretPos;
Non-editable text. Editable is below:
<div id="test" contenteditable="true" style="-webkit-user-select:text;">Hello, some <b>bold</b> and <i>italic and <b>bold</b></i> text</div>
<div id="caretPos"></div>
Manish Khedekar
  • 392
  • 3
  • 13
0

Instead of window.getSelection, use the shadowRoot element which you will need to pass in as an argument to getCaretPosition. Assuming you have getCaretPosition(shadowRoot), then the code changes to shadowRoot.getSelection.

See https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot for functionality available on the ShadowRoot.

nms
  • 11