Get and set cursor position with contenteditable div

前端 未结 4 1845
星月不相逢
星月不相逢 2020-12-25 13:58

I have a contenteditable div which I would like to be able to have users insert things such as links, images or YouTube videos. At the moment this is what I have:

相关标签:
4条回答
  • 2020-12-25 14:02

    There's a ton of related info onsite. This one works for me and my clients.

    DEMO

    https://stackoverflow.com/a/6249440/2813224

    function setCaret(line, col) {
      var ele = document.getElementById("editable");
      var rng = document.createRange();
      var sel = window.getSelection();
      rng.setStart(ele.childNodes[line], col);
      rng.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
      ele.focus();
    }
    
    //https://stackoverflow.com/a/6249440/2813224
    
    var line = document.getElementById('ln').value;
    var col = document.getElementById('cl').value;
    var btn = document.getElementById('btn');
    btn.addEventListener('click', function(event) {
      var lineSet = parseInt(line, 10);
      var colSet = parseInt(col, 10);
      setCaret(lineSet, colSet);
    }, true);
    <div id="editable" contenteditable="true">
      <br/>text text text text text text
      <br/>text text text text text text
      <br/>text text text text text text
      <br/>
      <br/>
    </div>
    <fieldset>
      <button id="btn">focus</button>
      <input type="button" class="fontStyle" onclick="document.execCommand('italic',false,null);" value="I" title="Italicize Highlighted Text">
      <input type="button" class="fontStyle" onclick="document.execCommand('bold',false,null);" value="B" title="Bold Highlighted Text">
      <input id="ln" placeholder="Line#" />
      <input id="cl" placeholder="Column#" />
    </fieldset>

    0 讨论(0)
  • 2020-12-25 14:07

    I have tried to find a solution,

    With a little help it can be perfected. It is a combination of answers I've found on SO, and my exp.

    Its tricky, its messy... but if you must, you can use it but it requires a bit of work to support inner links (if you cursor is on an anchor it will create anchor inside anchor)

    Here's the JS:

    var lastPos;
    var curNode = 0;
    function setCaret() {
      curNode=0;
      var el = document.getElementById("editor");
      var range = document.createRange();
      var sel = window.getSelection();
    
      console.log(el.childNodes);
      if (el.childNodes.length > 0) {
          while (lastPos > el.childNodes[curNode].childNodes[0].textContent.length) {
          lastPos = lastPos - el.childNodes[curNode].childNodes[0].textContent.length;
          curNode++;
    
          }
          range.setStart(el.childNodes[curNode].childNodes[0], lastPos);
          range.collapse(true);
          sel.removeAllRanges();
          sel.addRange(range);
      }
      el.focus();
    };
    
    
    function savePos() {
      lastPos = getCaretCharacterOffsetWithin(document.getElementById('editor'));
    }
    
    function addLink() {
      console.log(lastPos);
    
      setCaret();
      console.log(getCaretCharacterOffsetWithin(document.getElementById('editor')));
    
      console.log('focus');
    
      // $("#editor").focus();
      var link = $('#url').val();
      document.execCommand('createLink', false, link);
    
    }
    
    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;
    }
    

    fiddle

    0 讨论(0)
  • 2020-12-25 14:09

    This is what you asked for, in your bounty: on the following example you can see how to detect the exact number of characters of the actual point where you clicked the mouse on:

       <!-- Text Editor -->
       <div id="editor" class="divClass" contenteditable="true">type here some text</div>
    
    
        <script>
    
    
    
       document.getElementById("editor").addEventListener("mouseup", function(key) {
    
    alert(getCaretCharacterOffsetWithin(document.getElementById("editor")));
    
    }, false);
    
    
     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;
    }
     </script>
    
    0 讨论(0)
  • 2020-12-25 14:26

    A good rich-text editor is one of the harder things to do currently, and is pretty much a project by itself (unfriendly API, huge number of corner cases, cross-browser differences, the list goes on). I would strongly advise you to try and find an existing solution.

    Some libraries that can be used include:

    • Quill (http://quilljs.com)
    • WYSGIHTML (http://wysihtml.com)
    • CodeMirror library (http://codemirror.net)
    0 讨论(0)
提交回复
热议问题