So I have a scenario where the user when they select text in a page get that selection replaced with some markup as part of a larger annotation solution.
They need to be able to select across lots of different type of markup. All that works fine enough, the problem is that if you select a new bit of text but have not yet turned the previously selected text into a real annotation and you start to remove that selected bit of text you can run into side effects. Part of the reason for this way of doing it is because of need to support various screen readers, and as such will just have to leave it as that is the way we are doing it (putting markup in to represent the selection before registering it as an actual annotation)
I need to avoid these side effects.
The problem here can be seen in this codepen
https://codepen.io/bryanrasmussen/pen/PoKzMZL
The example html
<div>
<h1>something</h1>
<p>extra <b>text</b></p>
<p>some more</p>
</div>
<button onClick="selectRange()">Select</button>
The example JavaScript
let currentSelectionMark = 0;
const removeTemporarySelection = () => {
const els = document.getElementsByClassName("temporaryHighlight");
const len = els.length;
if (!len) {
return;
}
let el = els[0];
const inner = el.innerHTML;
el.outerHTML = inner;
}
const selectRange = () => {
const range = window.getSelection().getRangeAt(0);
const selectedContent = range.extractContents();
removeTemporarySelection();
const newParent = document.createElement('mark');
newParent.setAttribute('class', 'temporaryHighlight');
newParent.setAttribute('data-currentselection', currentSelectionMark);
newParent.appendChild(selectedContent);
range.insertNode(newParent);
currentSelectionMark = currentSelectionMark + 1;
}
Obviously the real application has lots of other stuff than this, but I think this summarizes the problem well enough.
If you select the text Some in Something (which is in an h1), the selection works fine.
If you select the o in Something you might end up with o smething - with smething in the h1.
Results look worse the more you try to select across lines, especially if you are selecting text you already selected.
In case anyone is confused as to what I actually want here - I want to be able to select across multiple ranges of elements, wrap the selection and finally take any previously wrapped selections and return them to their non wrapped state.
I based my original wrapping solution on the first answer in this How To Wrap / Surround Highlighted Text With An Element but now I think it probably has to be more like the second. But then I still need to be able to handle the situation of how to remove the wrapping mark on any previous selection without messing up any current selection if they actually intersect.
All of this is actually made harder because in the real solution there is an eventlistener for selectionchange with a debounce on the selectrange function but I figure that if it can be fixed with the button click doing the selection then it can be fixed on other solutions.