1

Based on Tony's answer to this question, I've built a jQuery script which locates instances of a predefined text string in our html:

jQuery(document).ready(function($) {
    $.expr[":"].contains = $.expr.createPseudo(function(arg) {
        return function( elem ) {
            return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
        };
    });
    $('*:contains("sometext")').each(function(){
        if($(this).children().length < 1) 
            $(this).html( 
               $(this).text().replace(
                    "sometext"
                    ,'<span style="color:red;">sometext"</span>' 
                   )  
               ); 
    });
});

I then highlight the text found using Slim's answer. However, text blocks containing for example a <strong> tag don't get highlighted.

I'm guessing it's because the length<1 if clause is preventing this from happening.

Can anyone suggest an improvement on Slim's code? Also perhaps explain why exactly the length<1 if clause is necessary to make the code work?

Thanks in advance for any help!

Community
  • 1
  • 1
Richard Tinkler
  • 1,635
  • 3
  • 21
  • 41
  • 1
    If you get rid of the length<1 clause you'll end up losing html elements and possibly event handlers/data. – Kevin B Nov 03 '16 at 15:29
  • Can you give an example of markup that the current code doesn't catch? Because I would think that if the "sometext" is within a `` tag it would get captured by the `:contains`... – Heretic Monkey Nov 03 '16 at 17:28
  • @MikeMcCaughan , it's about `.length < 1` which will not work in case of: `
    sometextsometext
    ` . The `` text content will be updated and the text node on the same level will be skipped.
    – Artur Filipiak Nov 03 '16 at 17:32
  • 1
    @ArturFilipiak Okay, that's great (and you should add that explanation to your answer rather than just a bunch of code), but I was asking to OP to add an example like that to the question. – Heretic Monkey Nov 03 '16 at 17:35
  • 1
    Just use [mark.js](https://markjs.io)? – dude Nov 03 '16 at 17:41

1 Answers1

1

Try this example. In short - you need to check not full DOM tree to find string, but use single level and move deeper. I just have changed 'contains' implementtaion as you asked.

jQuery.fn.reverse = [].reverse;

jQuery(document).ready(function($) {
    $.expr[":"].contains = $.expr.createPseudo(function(arg) {
      return function( elem ) {
        var cutElement = $(elem).clone().children().remove().end().text()
        return cutElement.toUpperCase().indexOf(arg.toUpperCase()) >= 0;
      };
    });
    $('*:contains("sometext")').reverse().each(function(){
        $(this).html( 
          $(this).html().replace(
            "sometext" 
            ,'<span style="color:red;">sometext</span>' 
          )  
        ); 
    });
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div>sometext and other text and inner <span>sometext</span></div>
VadimB
  • 5,533
  • 2
  • 34
  • 48
  • Thanks for the answer. Even though I don't understand why, it works well :) If you have time, a short explanation would be great! – Richard Tinkler Nov 04 '16 at 06:56
  • 1
    It was problem (maybe not problem, but not required behavior for this task), that 'contains' parse full DOM tree to find string occurence starting from root node. So if you have occurence on third level (as example: div.c1 > div.c2 > div.c3["occurence-here"]) - contains function will return array of 3 results: ["div.c1", "div.c2", "div.c3"] and that's correct, because each result contains tree of child nodes. So solution was escape all child tree and check occurence on single DOM level – VadimB Nov 04 '16 at 09:27
  • 1
    Also I add reverse to change order replacements from botttom to top and do not override result if we have several occurences on different levels – VadimB Nov 04 '16 at 09:31
  • 1
    It would be better to use `.replace(/(sometext)/gi , '$1') ` , because your code end up like tkis: https://jsfiddle.net/z6az4c1n/ – Artur Filipiak Nov 04 '16 at 13:42
  • Yes, it depend on requirenments - single or multiple selections – VadimB Nov 04 '16 at 16:23