I am writing a search engine and ran into a problem. I use document.createRange
to select the matches and I used the AND
operator.
I have the following text, it is Hungarian colors where half of it is already hightlighted:
<div id="x"><span class="highlight-occurrence">fehér</span>, fekete, vörös, kék, zöld, sárga, narancs, rózsaszín, barna, lila, türkízkék, szürke </div>
and I have to highlighting code for “sárga” something like this which gives out of range sort of error:
const x = document.getElementById("x");
const startOffset = 33;
const endOffset = 38;
const range = document.createRange();
range.setStart(x, startOffset);
range.setEnd(x, endOffset);
My search pattern is something like the following:
{"and": [
{"contains": "fehér"},
{"contains": "sárga"}
]}
The main problem here that the previous surroundContents
added some HTML to the text, so the setStart(x, 33)
will be somewhere in the HTML attribute "highlight-occurrence"
which gives an out of range obviously. This happens because when I highlight with the AND
operator I highlight the results separately. So first I highlight the occurrences of “fehér”, next I highlight the occurrences of “sárga”. It would be nice to keep it this way instead of completely overriding my code to mix the results for both words and always highlight from the end to the beginning of the text.
My real code looks like this, it is funny to have this many loops nested:
function highlightMatches(pattern, evidence){
for (var match of evidence)
for (var perMatcherTypeResults of match.evidence)
for (var locations of perMatcherTypeResults)
if (locations instanceof Array)
for (var location of locations){
var sectionIndexes = location.slice(0, location.length-1);
var positionRanges = location[location.length-1];
for (var i=positionRanges.length-1; i>=0; --i)
highlight(match.term.checksum, sectionIndexes, positionRanges[i]);
}
}
function highlight(id, sectionIndexes, positionRange){
var selector = `#results-${id}-${sectionIndexes.join("-")}`;
var element = selectOne(selector);
element.classList.add("highlight-sentence");
var range = new Range();
range.setStart(element.firstChild, positionRange[0]);
range.setEnd(element.firstChild, positionRange[1]);
var highlightOccurrence = document.createElement("span");
highlightOccurrence.className = "highlight-occurrence";
range.surroundContents(highlightOccurrence);
}
I was wondering is there a solution where the order of text highlighting does not matter so I would need to override only the highlight
function instead of the highlightMatches
or the match generator?