Search code examples
javascriptjqueryhtmlcontenteditablerich-text-editor

setting caret (cursor) inside bold element present inside contenteditable paragraph


I have been trying to build a web based text editor. And as part of the process, I am trying to dynamically create and modify elements based and keystroke events for font editing. In this particular jsfiddle example I'm trying to create a strong element upon hitting CTRL+b and setting the focus/caret inside the strong element so that subsequent text entered will be part of the bold element and hence will have bold text. But my code is just creating a strong element but not transferring the focus hence no text is getting bolder.

In the below code I'm creating event listener to capture keystroke events

p=document.getElementsByTagName("p")[0];

//console.log(p)

// adding eventlistener for keydown
p.addEventListener("keydown",listener);

// eventlistenerr callback function
function listener(){
  e=window.event;
  if(e.ctrlKey && e.keyCode==66)
    {
      console.log("CTRL+B");

      // creating bold element
      belm=document.createElement("strong");
      belm.setAttribute("contenteditable","true")
      p.appendChild(belm);

      //bug below
      // setting focus inside bold element
      setfocus(belm,0);
      e.preventDefault();
    }
}

Here is the function for setting the focus.

function setfocus(context, position){
    var range = document.createRange();
    position =position || 0;
    var sel = window.getSelection();
    range.setStart(context, position);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
    context.focus();
}

However, I have not doubt that the function which sets focus is faulty, because in the fiddle if you observe, I have created a separate setup just to test this out. Click on the button "Click Here" and the focus dynamically shifts to paragraph element without any hassle. I am unable to figure out what is going wrong.


Solution

  • It's pretty much impossible to move the cursor into an empty element in a contenteditable div. However, as shay levi suggested in another post, you can insert the zero-width character &#200B into your empty element to give it an index value.

    Here's an example*:

    function insertNode(nodeName) {
      var sel = window.getSelection(),
        range;
      range = sel.getRangeAt(0);
      range.deleteContents();
    
      var child = document.createElement(nodeName);
      child.innerHTML = '​';
      range.insertNode(child);
    }
    
    var div = document.querySelector('div'),
      btn = document.querySelector('button');
    
    btn.addEventListener('click', function() {
      insertNode('strong');
      div.focus();
    });
    
    div.focus();
    <div contenteditable></div><button><strong>B</strong></button>

    *For the sake of simplicity, this script doesn't toggle bold text, it only sets it.