-1

In a contenteditable element in which a list has been inserted with document.execCommand, is it possible to create next paragraph at the root of the editable element and not within the container of the list?

I tried to hijack "enter" keydown and play with the selection / range but did not manage to achieve such goal. The browser seems to always add the next paragraph within the container of the list.

For example:

<div contenteditable="true">
   <div>
     <ol>
       <li>1</li>
       <li>focus -> user click enter here twice</li>

results in

<div contenteditable="true">
   <div>
     <ol>
       <li>1</li>
       <li></li>
    </ol>
     <div>after clicking twice enter, focus is here and newly created div is a sibling of ol</div>

but I would like to get

<div contenteditable="true">
   <div>
     <ol>
       <li>1</li>
       <li></li>
    </ol>
  </div>
  <div>after clicking twice enter, focus is here and newly created div finds place at the root</div>

note that I aim to use document.execCommand because my feature needs to support undo / redo (and I am not that motived to implement once again my own custom undo / redo stack).

David Dal Busco
  • 7,975
  • 15
  • 55
  • 96

2 Answers2

0

Use appendChild.

const mainDiv = document.querySelector('[contenteditable]');

const newDiv = document.createElement('div');
newDiv.textContent = 'foo';

mainDiv.appendChild(newDiv);
<div contenteditable="true">
  <div>
    <ol>
      <li>1</li>
      <li>focus -> user click enter here twice</li>
    </ol>
  </div>
</div>
mstephen19
  • 1,733
  • 1
  • 5
  • 20
0

My answer was based on a solution found here: How to set the caret (cursor) position in a contenteditable element (div)?

Not sure if this exactly what you're looking for. Pressing enter twice in a row will place the cursor at the end of "focus here" text and put you outside of the OL element.

var lastKey = null;

document.querySelector('[contenteditable="true"]').addEventListener('keyup', e => {
    e.target.children[1];
  
    if (e.key === 'Enter' && e.key === lastKey){
        
    var range = document.createRange();
    var sel = window.getSelection();
    
    var el = e.target.children[1];
    
    range.setStart(el.childNodes[0],el.childNodes[0].textContent.length);
    range.collapse(true);
    
    sel.removeAllRanges();
    sel.addRange(range);
    
  }
  
  lastKey = e.key;

});
<div contenteditable="true">
   <div>
     <ol>
       <li>1</li>
       <li></li>
    </ol>
  </div>
  <div>focus here</div>
</div>
Phaelax z
  • 1,814
  • 1
  • 7
  • 19
  • Thank you but, doesn't actually seem to work. Here your code in a [Codepen](https://codepen.io/peterpeterparker/pen/wvqyMJZ). I also tried `collapse` start and end while selecting the range on the all parent node, did not help. – David Dal Busco Nov 04 '21 at 14:45
  • Your codepen changed the structure of the elements from what I see above in your question. "Focus here" was in a DIV, now you put it in LI. Where exactly do you want to put focus after the user hits enter? – Phaelax z Nov 04 '21 at 15:59
  • You are right that was confusing, sorry for that. I edited above question, hope it is more clear now. What I meant is that when user clicks enter twice to escape / close the list, the newly created div is created as a sibling of the list (ol/ul) instead of becoming a new paragraph at the root. – David Dal Busco Nov 04 '21 at 16:13