Here was my attempt: it almost works, except that it now puts the cursor before or after the first span in the editable container, rather than the one your cursor was in.
var div = document.querySelector('div');
div.onkeydown = fixCursor;
div.onclick = fixCursor;
function fixCursor () {
//get current selection and the node it's in
var selection = window.getSelection();
var container = selection.anchorNode;
//if it's a text node, get it's parent instead
if (selection.anchorNode.nodeType == 3)
container = selection.anchorNode.parentElement;
//if the container shouldn't be edited
if (container.classList.contains('noediting')) {
console.log('no editing', selection.anchorOffset)
//get element position
var position = Array.from(div.childNodes).indexOf(container);
//set new position to either before or after current element
var newPosition = position;
if (selection.anchorOffset > 0)
newPosition = position+1;
console.log(position,newPosition)
//create/set a new selection (cursor)
var cursor = document.createRange();
cursor.setStart(container.parentElement, newPosition);
cursor.collapse(true);
selection.removeAllRanges();
selection.addRange(cursor);
}
}
div span {
color: #888
}
<div contenteditable>
I am normal text <span class="noediting">no one should edit me</span> but you can edit me
<span class="noediting">but not me</span>
</div>
Does anyone have a better solution?
edit: I think I may have found a solution by getting the position of the container with indexOf, please tell if there's anything wrong with doing it that way