JavaScript - Highlight Keywords Like Google Does

By Robbe D. Morris

Printer Friendly Version

Robbe Morris
Robbe & Melisa Morris
  Download JavaScript Source Code
If you have ever experienced visiting a web page from google search results with a ton of summary style links on it, you begin to appreciate the ugliness of Google's keyword highlighting scheme in their cached pages.  Sometimes, web pages just have far too much information for a visitor to scroll through comfortably.
The code snippet below demonstrates how to use Internet Explorer's support for the .createTextRange() method to enable us to duplicate Google's keyword highlighting functionality client side in JavaScript.  All we need to do is parse the querystring of the document.referrer looking for known querystring variables from the most popular search engines.  Then, turn the desired querystring variable into an array of keywords for processing against the .createTextRange() method.  If the .createTextRange() method finds a match, we'll paste in a FONT tag with the alternative color of our choice.  All of this without messing up existing anchor tags.


The KeyWordIncludeUrl() method is a convenient way for you to manage which pages and/or sections of your site should be included in the keyword processing.  The KeyWordExcludePhrase() method allows us to prevent certain parsed keywords from the querystring from being included in the keyword processing.
In order to test this code out yourself, the zip file above includes some sample code that simulates the page test2.asp having been navigated to from test1.asp.  Just unzip the files to the root folder of your web site and click this link: test highlight article .  When the test1.asp page is shown, click the link labeled Run Demo.
So far, I've only included Google and Yahoo as valid search engines.  If your site tends to get traffic other search engines, you'll want to review their querystring values and modify this script accordingly.
Notice that I've commented out the alert() methods in KeyWordProcessError() so we don't show errors to any visitors that might be using a browser that isn't compatible.  You'll want to inject a call to your existing browser compatibility methods prior to beginning the process.  I hope you found this little snippet helpful.
 
JavaScript Sample Code
var SearchEngineVariable = 'q';

function KeyWordIncludeReferrer()
{
   try
   {
      var ref = document.referrer.toUpperCase();
      if (ref.indexOf('GOOGLE.COM') > 0) { SearchEngineVariable = 'q'; return true; }
      if (ref.indexOf('YAHOO.COM') > 0) { SearchEngineVariable = 'p'; return true; }
      if (ref.indexOf('LOCALHOST') > 0) { SearchEngineVariable = 'q'; return true; }
   }
   catch (exception) { KeyWordProcessError('KeyWordIncludeReferrer',exception); }
   return false;
}


function KeyWordIncludeUrl()
{
    var Href = document.location.href.toUpperCase();
 
    try
    {
      if (Href.indexOf('/MYFOLDERTOPROCESS/') > -1 ) { return true; }
      if (Href.indexOf('LOCALHOST') > -1 ) { return true; }	
    }
    catch (exception) { KeyWordProcessError('KeyWordIncludeUrl',exception); }
    return false;
}



function KeyWordGetColor(idx)
{
    var color = '#CCCCCC';

    switch (idx)
    {
       case 0:
               color='#99FF99'; break;
       case 1:
               color='yellow'; break;
       case 2:
               color='#FFCCFF'; break;
       case 3:
               color='#CC99FF'; break;
       case 4:
               color='#99CCFF'; break;
       case 5:
               color='#FFCC99'; break;
       case 6:
               color='#CCCCFF'; break;
       case 7:
               color='#66CCFF'; break;
       default:
               break;
    }
    return color;
}


 function KeyWordExcludePhrase(keyword)
 {

    var ret = false;

    switch (keyword.toUpperCase())
    {
      case 'AND' :                         return true;
      case 'OR' :                          return true;
      case 'SITE:EGGHEADCAFE.COM' :        return true;
      case 'SITE:WWW.EGGHEADCAFE.COM' :    return true;
      case '' :                            return true;
    }
	     
    return false;
 }

  

function KeyWordGetKeyWordsFromQueryString()
{

   if (KeyWordIncludeReferrer() == false) { return true; }

   var keywords = new Array();
   var ref = document.referrer;
   var pair;
   var qIndex = 0;
   var qs;
   var prm;

   try
   {

    
     qIndex = ref.indexOf('?');

     if (qIndex < 1) { return keywords; }
     
     ref = KeyWordReplace(ref,'%22','');

     qs = ref.substring(qIndex + 1,ref.length);

     prm = qs.split('&');

     for (i=0;i<prm.length;i++)
     {

       pair = prm[i].split('=');

       temp = unescape(pair[0]).split('+');
       name = temp.join(' ');

       if (name != SearchEngineVariable) { continue; }

       temp = unescape(pair[1]).split('+');
         
       for(k=0;k<temp.length;k++)
       {
         if (KeyWordExcludePhrase(temp[k]) == true) { continue; }
         keywords.push(temp[k]);
       }
		
     }

   }
   catch (exception) { KeyWordProcessError('KeyWordGetKeyWordsFromQueryString',exception); }
   return keywords;
}




function KeyWordHiLite()
{ 
 
  if (KeyWordIncludeUrl() == false) { return true; }
 
  var Links;
  var rng;
  var before = ' <font style="color: #000000;text-decoration:none;background-color: ';
  var after = '</b> </font> ';

  try
  {
     
    keywords = KeyWordGetKeyWordsFromQueryString();

    if (keywords.length < 1) { return true; }
 
    Links = KeyWordGetLinks();

    for(k=0;k<keywords.length;k++)
    {

      rng = document.body.createTextRange();  
  
      for (i=0;rng.findText(keywords[k])!=false; i++)
      { 
 
        try       { rng.pasteHTML(before + KeyWordGetColor(k) + ';"> <b>' +  rng.text + after);   }
        catch (e) { KeyWordProcessError('KeyWordHiLite Text Range',e);    }	
        finally   { rng.collapse(false); }
      
      }

      rng.collapse(true);
    }

    KeyWordCleanLinks(Links);
        
  }
  catch (exception) { KeyWordProcessError('KeyWordHiLite',exception); }
  
}



function KeyWordGetLinks()
{

   var Links = new Array();
   
   for (i=0;i<document.body.getElementsByTagName('A').length;i++)
   {
     Links[i] = new Array (document.body.getElementsByTagName('A')[i].href, document.body.getElementsByTagName('A')[i].innerHTML); 
   }

   return Links;
}



function KeyWordCleanLinks(Links)
{
  for (i=0;i<document.body.getElementsByTagName('A').length;i++)
  { 
    document.body.getElementsByTagName('A')[i].href = Links[i][0]; 
    document.body.getElementsByTagName('A')[i].innerHTML = Links[i][1];
  }
}


function KeyWordProcessError(functionName,e)
{
  if (e.description == null)
  {
    // alert(functionName + ' ' + e.message); 
  }
  else
  { 
    // alert(functionName + ' ' + e.description);
  }
}

function KeyWordReplace(OrgVal,SearchVal,ReplaceVal)
{
  var Val;
  var RegExp = eval("/" + SearchVal + "/g");
  if (OrgVal.indexOf(SearchVal) <1) {  return OrgVal; }
  Val = OrgVal.replace(RegExp,ReplaceVal);
  return Val;
} 
   


Robbe has been a Microsoft MVP in C# since 2004.  He is also the co-founder of NullSkull.com which provides .NET articles, book reviews, software reviews, and software download and purchase advice.