Решение: window.getSelection().getRangeAt(0).cloneContents()
Источник: чей-то удаленный комментарий @ https://stackoverflow.com/questions/43542742/find-text-on-page-and-select-it
Базовый пример
window.getSelection().addRange(new Range());
var dispray = document.querySelectorAll("[id^=dispray]");
var Go = () => {
var fragm = window.getSelection().getRangeAt(0).cloneContents();
dispray[0].innerHTML = "";
dispray[0].appendChild(fragm);
dispray[1].innerText = dispray[0].innerHTML;
}
#sample {color: red;}
#sample > span {color: green;}
#panel {height: 5em; border: 3px solid #ccc; resize: vertical; overflow-y: scroll;}
#panel > table {width: 100%; height: 100%; /* border-collapse: collapse; */}
#panel > table td {vertical-align: top; padding: 0.5em;}
#panel > table #disprayA {border-right: 1px solid #ccc;}
<p id="sample" onMouseUp="Go()"><span>Lorem ipsum <b>dolor sit</b> amet.⇥</span
> Text node <span>⇤Maecenas <b>porttitor a felis</b> in pharetra.⇥</span><span
>⇤Nulla accumsan auctor est sit amet finibus.</span></p>
<div id="panel"><table><tr>
<td id="disprayA">Copied selection goes here...</td>
<td><code id="disprayB">Source code of copied selection goes here...</code></td>
</tr></table></div>
Полный пример - нет открытых текстовых узлов
Ваше «маленькое» требование, чтобы копия выделения содержала нет пустых текстовых узлов значительно усложняет код.
window.getSelection().addRange(new Range());
var dispray = document.querySelectorAll("[id^=dispray]");
var Go = () => {
dispray[0].innerHTML = "";
var r = window.getSelection().getRangeAt(0);
var fragm = r.cloneContents();
if ([...fragm.childNodes].some(child => child.nodeType === Node.TEXT_NODE)) {
/* if selection contains some bare Text nodes... */
var ancestorElement = r.commonAncestorContainer;
if (ancestorElement.nodeType === Node.TEXT_NODE)
ancestorElement = ancestorElement.parentElement;
var ancestorElement2 = ancestorElement.cloneNode(false);
ancestorElement2.appendChild(fragm);
dispray[0].appendChild(ancestorElement2);
}
else dispray[0].appendChild(fragm);
dispray[1].innerText = dispray[0].innerHTML;
}
#sample {color: red;}
#sample > span {color: green;}
#panel {height: 5em; border: 3px solid #ccc; resize: vertical; overflow-y: scroll;}
#panel > table {width: 100%; height: 100%; /* border-collapse: collapse; */}
#panel > table td {vertical-align: top; padding: 0.5em;}
#panel > table #disprayA {border-right: 1px solid #ccc;}
<p id="sample" onMouseUp="Go()"><span>Lorem ipsum <b>dolor sit</b> amet.⇥</span
> Text node <span>⇤Maecenas <b>porttitor a felis</b> in pharetra.⇥</span><span
>⇤Nulla accumsan auctor est sit amet finibus.</span></p>
<div id="panel"><table><tr>
<td id="disprayA">Copied selection goes here...</td>
<td><code id="disprayB">Source code of copied selection goes here...</code></td>
</tr></table></div>