Check the default behavior when setting innerHtml in https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
Deletes all children, parses the content string, and assigns the resulting nodes as children of the element
Bookmarks in CKEDITOR are hidden span elements, and setting innerHtml will remove all these elements.
In any case, the solution is very simple.
Change the storeCursorLocation function to
var storeCursorLocation = function(editor) { bookmark = editor.getSelection().createBookmarks(true); };
When you pass true as parameters, it will use identifiers as a reference instead of storing DOM elements so that you can restore them after changing innerHtml.
{Edit}
Reading Solution 2 of @Reinmar says
If you can avoid uncontrolled innerHtml changes and instead add / remove / move some nodes, then just remember that you need to save these elements and this method will work just fine. You can also move bookmark items if your changes also need to change the selection.
So you will do this if you cannot replace the contents of the innerHtml element.
This solution is less efficient, but may work in some scenarios.
Change the validateText function to this.
var validateText = function(editor) { storeCursorLocation(editor); var parent = editor.document.getBody().$.firstChild, nodes = parent.childNodes, nodeText, words, index = 0, current, newElement; while (index < nodes.length) { current = nodes[index]; nodeText = current.nodeValue; if (current.nodeType === Node.TEXT_NODE && nodeText.indexOf('Lorem') !== -1) { words = nodeText.split('Lorem'); newElement = document.createTextNode(words[0]); parent.insertBefore(newElement, current); newElement = document.createTextNode(words[1]); parent.insertBefore(newElement, current.nextSibling); newElement = document.createElement('span') newElement.className = 'err-item'; newElement.innerHTML = 'Lorem'; parent.replaceChild(newElement, current); break; } index++; } restoreCursorLocation(editor); };
Basically, I cross the nodes of the first p in the chkeditor body and replace only the text node with a text of type that contains Lorem with a range and adds the remaining text before and after as text elements. If you replace all the text as you did, it will remove the bookmarks from the DOM, so when you try to restore them, they do not exist.