JQuery/JavaScript plugin for highlighting text

后端 未结 1 2011
予麋鹿
予麋鹿 2021-02-08 18:11

I am looking for a jquery plugin for multiple highlighted text in an element. I found a very popular plugin for exactly that: http://bartaz.github.com/sandbox.js/jquery.highligh

相关标签:
1条回答
  • 2021-02-08 18:46

    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 <span class="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 <span class="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 <span class="highlight">brown</span> <span class="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 node
                    this.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));
                }
                else if (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 <span class="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 <span class="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.

        function overlap(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)));
                } else if (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:

    1. Unhighlight everything that is currently highlighted (anything that was highlighted will be in the selected1 array).
    2. Our new string or array of strings goes into the words array
    3. Append selected1 to words
    4. Combine all partially overlapping pairs of strings in words and add the new combined strings to words (using the overlap function and its wrapper that iterates through the whole array - overdiag in the fiddle example)
    5. Sort words by string length, so the longest strings will come first
    6. Highlight all the strings in words
    7. Merge all neighboring highlighted strings (using the mergenode function)
    8. 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.

    0 讨论(0)
提交回复
热议问题