Bugs with content editable

Lightweight Opensource Richcontent Editor

by Imabot

HTML

<h2>Editor</h2>
<div id="editor" contenteditable="true">Press enter just here 👇<span class="non-editable">&#65279;<span contenteditable='false'><b>contenteditable=false</b></span>&#65279;</span> [end of the line]</div>

<h2>HTML output</h2>
<pre id="output"></pre>

<h2>Selection</h2>
From <input id="from" disabled> – To <input id="to" disabled><br>


<small>More details on <a href="https://lucidar.me/en/rich-content-editor/non-editable-span-in-contenteditable/" target="_blank">my blog</a>.</small>

CSS

#editor {
    min-height:30vh; 
    max-height:80vh; 
    overflow-y:auto;
/*    white-space: pre-wrap; */
	background-color: #eaeaff;
}

#editor p { 
    margin: 0;
}

.editor br {
    display: none;
}
#output {
	background-color: #ffeaea;
}

span[contenteditable=false] {
	background-color:#faa;
}

JavaScript

document.execCommand('defaultParagraphSeparator', false, "p");

let editor = document.getElementById('editor');
let output = document.getElementById('output');

// Set focus to the editor when page is loaded
document.addEventListener("DOMContentLoaded", () => {
	editor.focus();
});

function updateHtmlAndSelection()
{
	output.textContent = editor.innerHTML;
	let {anchorNode, anchorOffset, focusNode, focusOffset} = document.getSelection();
	from.value = `${anchorNode && anchorNode.data}:${anchorOffset}`;
	to.value = `${focusNode && focusNode.data}:${focusOffset}`;
}

// Update the output when the editor is updated
document.onselectionchange = (e) => {
	// Check if the editor is focussed
	if (editor === document.activeElement)
	{
		console.log ('selection changed');
		updateHtmlAndSelection()
		
		// Get current selection
		let selection = document.getSelection();		
			
		// Check the selection starts in non editable div
		if (selection.anchorNode.parentNode.classList.contains("non-editable"))
		{
			let anchorPrevious = selection.anchorNode.parentNode.previousSibling;
			if (anchorPrevious===null) anchorPrevious = selection.anchorNode.parentNode;
			let anchorNext = selection.anchorNode.parentNode.nextSibling; //&& selection.anchorNode.parentNode;			
			if (selection.anchorNode.previousSibling == null)
				selection.setBaseAndExtent(anchorNext, 0, selection.focusNode, selection.focusOffset);
			else
				selection.setBaseAndExtent(anchorPrevious, anchorPrevious.length, selection.focusNode, selection.focusOffset);
		}
		
		// Check the selection ends in non editable div
		if (selection.focusNode.parentNode.classList.contains("non-editable"))
		{
			let focusPrevious = selection.focusNode.parentNode.previousSibling;
			if (focusPrevious===null) focusPrevious = selection.anchorNode.parentNode;
			let focusNext = selection.focusNode.parentNode.nextSibling; //&& selection.anchorNode.parentNode;			
			if (selection.focusNode.previousSibling ==...