Set caret position right after the inserted element in a contentEditable div

前端 未结 3 567
再見小時候
再見小時候 2020-11-29 01:51

I\'m inserting an element into a contentEditable div but the browser sets the position of the cursor before the inserted element. Is it possible to set the cursor right afte

相关标签:
3条回答
  • 2020-11-29 02:02

    Here's what worked for me, using Rangy, in a VueJS context.

    // When the user clicks the button to open the popup to enter
    // the URL, run this function to save the location of the user's
    // selection and the selected text.
    newSaveSel: function() {
      if (this.savedSel) {
        rangy.removeMarkers(this.savedSel);
      }
      // Save the location of the selected text
      this.savedSel = rangy.saveSelection();
      // Save the selected text
      this.savedSelText = rangy.getSelection().toString();
      this.showLinkPopup = true;
      console.log('newSavedSel', this.savedSel);
    },
    surroundRange: function() {
      // Restore the user's selected text. This is necessary since
      // the selection is lost when the user stars entering text.
      if (this.savedSel) {
        rangy.restoreSelection(this.savedSel, true);
        this.savedSel = null;
      }
      // Surround the selected text with the anchor element
      var sel = rangy.getSelection();
    
      var range = sel.rangeCount ? sel.getRangeAt(0) : null;
      if (range) {
        // Create the new anchor element
        var el = document.createElement("a");
        el.style.backgroundColor = "pink";
        el.href = this.anchorHref;
        el.innerHTML = this.savedSelText;
        if (this.checked) {
          el.target = "_blank";
        }
        // Delete the originally selected text
        range.deleteContents();
        // Insert the anchor tag
        range.insertNode(el);
        // Ensure that the caret appears at the end
        sel.removeAllRanges();
        range = range.cloneRange();
        range.selectNode(el);
        range.collapse(false);
        sel.addRange(range);
        this.showLinkPopup = false; 
      }
    },
    
    0 讨论(0)
  • 2020-11-29 02:03

    If you're inserting an empty div, p or span, I believe there needs to be "something" inside the newly created element for the range to grab onto -- and in order to put the caret inside there.

    Here's my hack that seems to work OK in Chrome. The idea is simply to put a temporary string inside the element, then remove it once the caret is in there.

    // Get the selection and range
    var idoc = document; // (In my case it's an iframe document)
    var sel = idoc.getSelection();
    var range = sel.getRangeAt(0);
    
    // Create a node to insert
    var p = idoc.createElement("p"); // Could be a div, span or whatever
    
    // Add "something" to the node.
    var temp = idoc.createTextNode("anything");
    p.appendChild(temp);
    // -- or --
    //p.innerHTML = "anything";
    
    // Do the magic (what rangy showed above)
    range.collapse(false);
    range.insertNode( p );
    range = range.cloneRange();
    range.selectNodeContents(p);
    range.collapse(false);
    sel.removeAllRanges();
    sel.addRange(range);
    
    // Clear the non
    p.removeChild(p.firstChild);
    // -- or --
    //p.innerHTML = "";
    
    0 讨论(0)
  • 2020-11-29 02:22

    The following function will do it. DOM Level 2 Range objects make this easy in most browsers. In IE, you need to insert a marker element after the node you're inserting, move the selection to it and then remove it.

    Live example: http://jsfiddle.net/timdown/4N4ZD/

    Code:

    function insertNodeAtCaret(node) {
        if (typeof window.getSelection != "undefined") {
            var sel = window.getSelection();
            if (sel.rangeCount) {
                var range = sel.getRangeAt(0);
                range.collapse(false);
                range.insertNode(node);
                range = range.cloneRange();
                range.selectNodeContents(node);
                range.collapse(false);
                sel.removeAllRanges();
                sel.addRange(range);
            }
        } else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
            var html = (node.nodeType == 1) ? node.outerHTML : node.data;
            var id = "marker_" + ("" + Math.random()).slice(2);
            html += '<span id="' + id + '"></span>';
            var textRange = document.selection.createRange();
            textRange.collapse(false);
            textRange.pasteHTML(html);
            var markerSpan = document.getElementById(id);
            textRange.moveToElementText(markerSpan);
            textRange.select();
            markerSpan.parentNode.removeChild(markerSpan);
        }
    }
    

    Alternatively, you could use my Rangy library. The equivalent code there would be

    function insertNodeAtCaret(node) {
        var sel = rangy.getSelection();
        if (sel.rangeCount) {
            var range = sel.getRangeAt(0);
            range.collapse(false);
            range.insertNode(node);
            range.collapseAfter(node);
            sel.setSingleRange(range);
        }
    }
    
    0 讨论(0)
提交回复
热议问题