Ответ 1
Сделайте нормализацию для начала/окончания позиций, чтобы избежать перекрытия.
- Объединить начальные и конечные позиции в один список с противоположными значениями (например, -1 и 1)
- Сортировка списка по положению, а затем - по значению маркера (и на основе сортировки второго уровня вы можете либо различать последовательные диапазоны, либо объединять их)
- пройдите список позиций и добавьте маркер текущей позиции в текущую сумму; как только он "0" - это означает, что вы только что нашли окончание для некоторых наборов вложенных/пересекающихся разделов;
Таким образом вы получите позиции для выделения без вложенных/перекрывающихся диапазонов.
Чтобы заменить текстовый узел на сочетание текстовых узлов и элементов HTML (например, <span>
), documentFragment
и .replaceChild()
помогут:
let starts = [
5, 44, 0, 50, 6, 100, 99, 50, 51, 52
];
let ends = [
20, 62, 4, 70, 10, 100, 101, 54, 53, 53
];
let positions = [];
let normalizedPositions = [];
starts.forEach(function(position) {
positions.push({position, value: 1});
});
ends.forEach(function(position) {
positions.push({position, value: -1});
});
positions = positions.sort(function(a, b) {
return a.position - b.position ||
b.value - a.value
});
var currentSection = {from: 0, counter: 0};
for(position of positions) {
if (!currentSection.counter) {
if (position.value === -1) {
throw 'inconsistent boundaries: closing before opening ${position.position}';
}
currentSection.from = position.position;
}
currentSection.counter += position.value;
if (!currentSection.counter) {
normalizedPositions.push({
from: currentSection.from,
to: position.position
});
}
}
if (currentSection.counter) {
throw "last section has not been closed properly";
}
let parentNode = document.querySelector('p');
let textNodeToReplace = parentNode.childNodes[0];
let sourceText = textNodeToReplace.nodeValue;
let documentFragment = document.createDocumentFragment();
let withoutHighlightingStart = 0;
normalizedPositions.forEach(function (highlightRange) {
if (highlightRange.from> withoutHighlightingStart) {
let notHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart, highlightRange.from));
documentFragment.appendChild(notHighlighted);
}
let highlighted = createHighlighted(sourceText.slice(highlightRange.from, highlightRange.to));
documentFragment.appendChild(highlighted);
withoutHighlightingStart = highlightRange.to;
});
let lastNotHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart));
documentFragment.appendChild(lastNotHighlighted);
parentNode.replaceChild(documentFragment, textNodeToReplace);
function createTextNode(str) {
return document.createTextNode(str);
}
function createHighlighted(str) {
let span = document.createElement('span');
span.classList.add('highlight');
span.appendChild(createTextNode(str));
return span;
}
.highlight {
background-color: yellow;
color: dark-blue;
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>