Jquery/javascript Plugin For Highlighting Text
Solution 1:
You can do everything with the highlighter plugin that you found if you add a couple little tweaks. As an illustration I posted to fiddle a working example that I quickly put together this afternoon: http://jsfiddle.net/4bwgA/
Here I will go first step by step through all the things the plugin (the OP refers to) already does and at the end give the solution to the overlapping highlighted areas.
What the highlighter does, is put a tag around the word you apply it for. So if you have
<p>Who is the quick brown fox?</p>
and you highlighted the word "brown" with
$("p").highlight("brown");
you get
<p>Who is the quick <spanclass="highlight">brown</span> fox?</p>
and an additional command
$("p").highlight("brown fox");
will not find anything, cause the string does not have this substring anymore, as it now has tags around brown.
So if it is just about the overlap ... the solution is easy. The package offers an unhighlighting function, that you can apply before the new highlighting
$("p").unhighlight().highlight("brown fox");
and get
<p>Who is the quick <spanclass="highlight">brown fox</span>?</p>
Now this is nothing exciting so far. But what if we have highlighted "brown" in one go and then "fox" in the next one. We get this
<p>Who is the quick <spanclass="highlight">brown</span><spanclass="highlight">fox</span>?</p>
Then we want to join the neighboring highlighted areas. This can be done with an additional function, that does something like this:
function mergenode(node) {
var parent1 = node.contents();
parent1.each(function (i) {
if (i > 0 && this.nodeType !== 1 && //if text nodethis.data.search(/^\s*$/g) === 0 && //consisting only of hyphens or blanks
parent1[i - 1].nodeName === "SPAN" && //bordering to SPAN elements
parent1[i + 1].nodeName === "SPAN" &&
parent1[i - 1].className === "highlight" && //of class highlight
parent1[i + 1].className === "highlight") {
selected1.push(parent1[i - 1]
.textContent.concat(this.data, parent1[i + 1].textContent));
}
elseif (this.nodeType === 1 &&
this.nodeName === "SPAN" &&
parent1[i + 1].nodeName === "SPAN" &&
this.className === "highlight" &&
parent1[i + 1].className === "highlight") {
selected1.push(this.textContent.concat(parent1[i + 1].textContent));
}
});
$(node).unhighlight().highlight(selected1);
}
This will merge all neighboring spans with class highlight (this is just written for the general highlighter tag, but could easily be extended with two extra arguments for nodeName and className, for custom tags). The result will look like this
<p>Who is the quick <spanclass="highlight">brown fox</span>?</p>
All good so far. But what if our search strings overlap?!!!
First ... the best thing to do with overlaps is to deselect the old selection before checking for overlapped strings on the cleared text. For this we need to remember the previous selection, which can for example be saved in an array (I called it selected1
) that gets a value added to it at each additional select.
At every run the final selection (all merged) is saved into the selected1
array, so that it can be used for future merging and overlapping.
Now, how does highlighter deal with an array of strings? It applies the highlight function to each of them in the order they have been passed to the function. So, if two strings overlap completely, we can deal with that just by sorting the array of selection strings and first highlighting the longer ones. For example
$("p").highlight(["brown fox","brown"]);
will just highlight
<p>Who is the quick <spanclass="highlight">brown fox</span>?</p>
The array can be sorted by length with something like this
words = words.sort(function(str1, str2) {
return (str1.length < str2.length) ? 1 : 0;
});
The completely overlapping and neighboring highlights are now dealt with. Now we have to make sure we get the partially overlapping strings. Here I wrote a function that compares two strings for overlap ... there are other ways to do this, but what I want to show in this answer is mostly just the sequence of steps that you need to do to get the highlighting the way you want =)
This function takes two strings, checks if they overlap, and if so, combines them and saves the new combined string into an array, toselect
, that at the end gets appended to the original words
array. There might be some useless combinations, but it wont hurt - they won't show at the end.
functionoverlap(a, b) {
var l = b.length,
m = a.length;
for (var j = 1; j < l; j++) {
if (a.indexOf(b.substr(l - j)) === 0) {
toselect.push(b.concat(a.substr(j)));
} elseif (a.substr(m - j).indexOf(b.substr(0, j)) === 0) {
toselect.push(a.concat(b.substr(j)));
}
}
}
Now we want to apply this function to all possible pairs of elements in the words
array. We could iterate this with a loop, but I got a little excited and did this
$.each(arr, function (i) {
$.each(arr.slice(i + 1), function (i, v) {
overlap(arr[i], v);
});
});
Now we just have to append the new toselect
array, in which with all possible overlapping strings have been concatenated, to the original words
array.
So now we have all the parts we need and we can put them together. Every time we want to highlight a new string or array of strings, we do the following steps:
- Unhighlight everything that is currently highlighted (anything that was highlighted will be in the
selected1
array). - Our new string or array of strings goes into the
words
array - Append
selected1
towords
- Combine all partially overlapping pairs of strings in
words
and add the new combined strings towords
(using theoverlap
function and its wrapper that iterates through the whole array -overdiag
in the fiddle example) - Sort
words
by string length, so the longest strings will come first - Highlight all the strings in
words
- Merge all neighboring highlighted strings (using the
mergenode
function) - The final set of highlighted strings is saved into
selected1
I put this together quickly this afternoon, so it's not a perfect implementation of the idea, but it works =) I added my code into the highlighter script and added them to a simple example on jsfiddle for you to play with http://jsfiddle.net/4bwgA/. There are buttons so you can press through all the different steps and see what they do.
Post a Comment for "Jquery/javascript Plugin For Highlighting Text"