Alright, so I need an "input" that allows highlighting parts that are "invalid".
Since I cannot do that with an actual input, I am using a div
with contenteditable=true
. The algorithm is fairly simple in concept:
- on
keyup
- validate input
- replace innerHtml of
div
withspan
s that have the correct class - use CSS to style errors
- restore cursor position s.t. the user can just keep typing
And it's that last part that's giving me some issues.
I've found https://stackoverflow.com/a/4812022/3322533 , which is working great to get the offset, however, my attempt at restoring it,
function setCursorPositionWithin(element, pos) {
const doc = element.ownerDocument || element.document;
const win = doc.defaultView || doc.parentWindow;
let sel;
const newPosition = document.createRange()
newPosition.setStart(element, 0)
newPosition.setEnd(element, 0)
element.focus();
if (typeof win.getSelection != "undefined") {
sel = win.getSelection();
if (sel.rangeCount > 0) {
sel.removeAllRanges();
}
newPosition.selectNodeContents(element);
newPosition.setStart(newPosition.startContainer, pos)
newPosition.setEnd(newPosition.endContainer, pos);
sel.addRange(newPosition)
} else if ((sel = doc.selection) && sel.type != "Control") {
throw Error('IE not supported')
}
}
is failing because
Uncaught DOMException: Failed to execute 'setStart' on 'Range': There is no child at offset 11.
at setCursorPositionWithin
How do I construct this range correctly?