Исходя из этого предыдущего ответа SO , я пытаюсь заставить подсветку текста работать для нескольких элементов. По какой-то причине средний элемент не выделяется, и я не могу понять, почему.
Вот код:
function getSafeRanges(dangerous) {
// a for ancestor
const a = dangerous.commonAncestorContainer;
// Starts -- Work inward from the start, selecting the largest safe range
const s = [];
const rs = [];
// if highlight doesn't start and end in the same container…
if (dangerous.startContainer != a) {
for (let i = dangerous.startContainer; i != a; i = i.parentNode) {
// put the starting text and all its parents (except
// common ancestor of start and end) into array `s`
/* debugger */
s.push(i);
}
}
// if highlight didn't start and end in the same container,
// then create a new range for each item in `s`
if (s.length > 0) {
for (let i = 0; i < s.length; i++) {
const xs = document.createRange();
console.log(i, xs)
/* debugger */
// if at the parents of starting node
if (i) {
xs.setStartAfter(s[i - 1]);
xs.setEndAfter(s[i].lastChild);
}
// if at the starting node (text node)
else {
xs.setStart(s[i], dangerous.startOffset);
/* if (s[i].nodeType != Node.TEXT_NODE) debugger */
xs.setEndAfter(
(s[i].nodeType == Node.TEXT_NODE) ?
s[i] :
s[i].lastChild
);
}
console.log(i)
rs.push(xs);
console.log("rs", rs)
/* debugger */
}
}
// Ends -- basically the same code reversed
const e = [];
const re = [];
// if highlight doesn't start and end in the same container…
if (dangerous.endContainer != a) {
for (let i = dangerous.endContainer; i != a; i = i.parentNode) {
// put the ending text and all its parents (except
// common ancestor of start and end) into array `e`
e.push(i);
}
}
// if highlight didn't start and end in the same container,
// then create a new range for each item in `e`
if (e.length > 0) {
for (let i = 0; i < e.length; i++) {
const xe = document.createRange();
// if at the parents of ending node
if (i) {
xe.setStartBefore(e[i].firstChild);
xe.setEndBefore(e[i - 1]);
}
// if at the ending node (text node)
else {
xe.setEnd(e[i], dangerous.endOffset);
/* if (e[i].nodeType != Node.TEXT_NODE) debugger */
xe.setStartBefore(
(e[i].nodeType == Node.TEXT_NODE) ?
e[i] :
e[i].firstChild
);
}
re.unshift(xe);
}
}
// Middle -- the uncaptured middle
if ((s.length > 0) && (e.length > 0)) {
/* debugger */
const xm = document.createRange();
xm.setStartAfter(s[s.length - 1]);
xm.setEndBefore(e[e.length - 1]);
// Concat
rs.push(xm);
} else {
console.log("no middle?")
return [dangerous];
}
response = rs.concat(re);
/* debugger */
// Send to Console
console.log(response)
return response;
}
function highlightSelection() {
const userSelection = window.getSelection().getRangeAt(0);
if (userSelection.collapsed) return;
const safeRanges = getSafeRanges(userSelection);
for (let i = 0; i < safeRanges.length; i++) {
highlightRange(safeRanges[i]);
}
document.getSelection().removeAllRanges();
}
function highlightRange(range) {
const newNode = document.createElement("span");
newNode.setAttribute(
"style",
"background-color: yellow; display: inline;"
);
newNode.addEventListener("click", function(el) {
/* debugger */
el.target.outerHTML = el.target.innerHTML;
})
range.surroundContents(newNode);
}
window.addEventListener("mouseup", highlightSelection);
<div>
<p>
line1
</p>
<p>
line2
</p>
<span>line3</span>
<p>
line4
</p>
<span>line5</span>
<p>
line6
</p>
<span>line7</span>
<table style="width:100%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
</table>
</div>
<span>awoifja woiefj awf</span>
Если вы выделите весь текст, начиная с " line1 " вплоть до " line7 ", можете кто-нибудь, пожалуйста, скажите мне, почему средний элемент не выделяется? Кроме того, здесь - рабочая скрипка , поскольку кажется, что демонстрационная версия фрагмента SO содержит кучу странных ошибок (ничего общего с моим сценарием).