views:

42

answers:

2

My problem is bit complex, I will try my best to explain it.

What I am trying to do?
I want to provide users with a script that they can add to their webpage/blog which will highlight cretain text on their web pages and put a menu/box their which displays on hover. Something like kontera.

To do this, I am doing the following:
1. Parse the HTML of the page where the script is loaded by the following method:
http://stackoverflow.com/questions/3460004/regexp-to-search-replace-only-text-not-in-html-attribute
(see the first answer)
2. If its a text node than check the value of the text node for any keywords present in it. (I have around 1000 keywords) and if a keyword is found, replace it with highlighted text and the needed things.

When I apply this to my blog on blogger.com is hangs the browser as the parser function call itself recursively.
I tried to confirm this by limiting my keywords to only 5 from 100's.
Than to solve it I limited that if the nodes are of type DIV or P or BODY than only call the function recursively, still it hangs.
When I remove DIV and leave only P and BODY, than it works.
Can you help me? Thanks in advance! :)

A: 

I'm not convinced you need a recursive function for this. Is there any reason something like this wouldn't work?:

var searchTerms = [ ... your list of words ... ];
for (var i = 0; i < searchTerms.length; i++) {
    var regex = new RegExp(">([^<]*)?("+searchTerms[i]+")([^>]*)?<","ig");
    var tempinnerHTML = element.innerHTML;
    element.innerHTML = tempinnerHTML.replace(regex,'>$1<span style="background-color:#DDF">$2</span>$3<');
}
Eric Wendelin
In the link that I have mentioned in the question, there is a comment by Chad. Can you confirm that it is the best way of doing it? at least safe way of doing it?
hardik.device
I can't *guarantee* that this is the best or even a safe way to do this because HTML is not a subset of XML. It depends on your expected input. However, I have been using a similar script myself for some time.
Eric Wendelin
A: 

Maybe you can try a different way to wrap Keyword terms within the markup. I use this code for searching within a document (created a Search Bookmarklet for iPad so I could search within MobileSafari).

Maybe you could repurpose it for you needs if its effective:

var SearchFor = {
    run: function(defaultText){
      if (!defaultText) {
        defaultText = "";
      }
      var searchText = prompt("Search for:", defaultText);
      if (!searchText)  {
        return false;
      }
      return this.highlightKeyword(searchText);
    },

    highlightKeyword: function(searchText) {

      var searchArray = [searchText];

      if (!document.body || typeof(document.body.innerHTML) == "undefined") {
        return false;
      }

      var bodyText = document.body.innerHTML;
      for (var i = 0; i < searchArray.length; i++) {
        bodyText = this.highlight(bodyText, searchArray[i]);
      }

      document.body.innerHTML = bodyText;
      return true;
    },

    highlight: function(bodyText, searchTerm) {

     var highlightStartTag = "<span style='color:#CCCCCC; background-color:#FAF9DC;'>";
     var highlightEndTag   = "</span>";

      var newText = "";
      var i = -1;
      var lcSearchTerm = searchTerm.toLowerCase();
      var lcBodyText   = bodyText.toLowerCase();

      while (bodyText.length > 0) {
        i = lcBodyText.indexOf(lcSearchTerm, i+1);
        if (i < 0) {
          newText += bodyText;
          bodyText = "";
        } else {
          // skip anything inside an HTML tag
          if (bodyText.lastIndexOf(">", i) >= bodyText.lastIndexOf("<", i)) {
            // skip anything inside a <script> block
            if (lcBodyText.lastIndexOf("/script>", i) >= lcBodyText.lastIndexOf("<script", i)) {
              newText += bodyText.substring(0, i) + highlightStartTag + bodyText.substr(i, searchTerm.length) + highlightEndTag;
              bodyText = bodyText.substr(i + searchTerm.length);
              lcBodyText = bodyText.toLowerCase();
              i = -1;
            }
          }
        }
      }
      return newText;
    }
};

SearchFor.run('KeywordExample');
michael