feat: fix find-in-page highlighting to handle multiple matches per text node and prevent DOM corruption
This commit is contained in:
parent
7ccad9c589
commit
b1cee1a0ec
@ -5020,27 +5020,45 @@
|
||||
},
|
||||
|
||||
highlightMatches() {
|
||||
const matchesByNode = new Map();
|
||||
|
||||
this.matches.forEach((match, idx) => {
|
||||
const node = match.node;
|
||||
const text = node.textContent;
|
||||
const before = text.substring(0, match.index);
|
||||
const matchText = text.substring(match.index, match.index + match.length);
|
||||
const after = text.substring(match.index + match.length);
|
||||
if (!matchesByNode.has(match.node)) {
|
||||
matchesByNode.set(match.node, []);
|
||||
}
|
||||
matchesByNode.get(match.node).push({ match, idx });
|
||||
});
|
||||
|
||||
const mark = document.createElement('mark');
|
||||
mark.className = idx === this.currentIndex ? 'find-highlight find-highlight-active' : 'find-highlight';
|
||||
mark.textContent = matchText;
|
||||
mark.setAttribute('data-find-index', idx);
|
||||
matchesByNode.forEach((entries, node) => {
|
||||
if (!node || !node.parentNode) return;
|
||||
|
||||
const text = node.textContent || '';
|
||||
let cursor = 0;
|
||||
const fragment = document.createDocumentFragment();
|
||||
if (before) fragment.appendChild(document.createTextNode(before));
|
||||
fragment.appendChild(mark);
|
||||
if (after) fragment.appendChild(document.createTextNode(after));
|
||||
|
||||
entries.sort((a, b) => a.match.index - b.match.index);
|
||||
|
||||
entries.forEach(({ match, idx }) => {
|
||||
if (match.index > cursor) {
|
||||
fragment.appendChild(document.createTextNode(text.substring(cursor, match.index)));
|
||||
}
|
||||
|
||||
const matchText = text.substring(match.index, match.index + match.length);
|
||||
const mark = document.createElement('mark');
|
||||
mark.className = idx === this.currentIndex ? 'find-highlight find-highlight-active' : 'find-highlight';
|
||||
mark.textContent = matchText;
|
||||
mark.setAttribute('data-find-index', idx);
|
||||
fragment.appendChild(mark);
|
||||
|
||||
match.element = mark;
|
||||
cursor = match.index + match.length;
|
||||
});
|
||||
|
||||
if (cursor < text.length) {
|
||||
fragment.appendChild(document.createTextNode(text.substring(cursor)));
|
||||
}
|
||||
|
||||
node.parentNode.replaceChild(fragment, node);
|
||||
|
||||
// Update reference to the mark element
|
||||
match.element = mark;
|
||||
});
|
||||
},
|
||||
|
||||
@ -5050,6 +5068,7 @@
|
||||
|
||||
const marks = contentArea.querySelectorAll('mark.find-highlight');
|
||||
marks.forEach(mark => {
|
||||
if (!mark.parentNode) return;
|
||||
const text = mark.textContent;
|
||||
const textNode = document.createTextNode(text);
|
||||
mark.parentNode.replaceChild(textNode, mark);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user