/*
   IE Hover Fix
   =====================
   Original by mmmbeer
   http://webpages.charter.net/mmmbeer/code/arbitrary-hover/
   (Page now gone).

   Edited by Robert Mark Bram, 27/02/2005 4:33PM
    - made this an OO script so that classes and HTML element types can be
      parametrized.


   Introduction.
   =====================
   This style information should be all we need to implement a hover effect
   for any element with a class name of "tableCell" in any recent browser:
         .tableCell {
            background-color: #33CCCC;
         }
         .tableCell:hover {
            background-color: #CC0000;
         }
   IE only supports the hover pseudo class for anchor tags though. Nice job
   Billy, thanks.

   This whole script is designed to fix that flaw when a page is loaded in IE.
   Essentially it adds onmouseover and onmouseout handlers to elements
   of particular types with particular class name attributes - changing the
   class names for that element in order to apply the hover css style as
   appropriate: "tableCell" on mouse out, "tableCellIeHoverFix" on mouse over.

   This script allows you to create an object that gives you complete control
   over exactly what elements you want to give the hover effect to by specifying
   what element types to search for (with the hoverElementTypes array) and what
   class name attribute values to search for (with the classNames array).

   To use this script.
   =====================

   1) Import this library and create an IeHoverFix object with the following
      code:

      <!--[if gte IE 5]>
      <script type="text/javascript" src="ieHoverFix.js"></script>
      <script type="text/javascript">
         classNames = new Array ("tableCell");
         hoverElementTypes = new Array ("TD", "p");
         var hoverFix = new IeHoverFix(classNames, hoverElementTypes);
      </script>
      <![endif]-->

      The classNames array contains all the class names that you wish to add the
      hover effect to - if the element is of a type given in the
      hoverElementTypes array.

      The hoverElementTypes array contains all the element types you wish to add
      the hover effect to - if the element has a class name given in the
      classNames array.

      Do it this way in order to prevent any browser other than IE 5 or later
      evaluating this script. Why? Because, especially in large documents, this
      script can produce noticeable lag - Netscape and Opera's native hover
      support is much for suitable!
      Source: http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/overview/ccomment_ovw.asp

   2) Make sure that you include style information for the element class
      you wish to give a hover effect to. For example, let's say you want a
      hover effect for any element with a class name of "tableCell". Include
      the following CSS style sheets:

         .tableCell {
            background-color: #33CCCC;
         }
         .tableCell:hover, .tableCellIeHoverFix {
            background-color: #CC0000;
         }

      Note that you must specify both a "hover off" style ("tableCell") and a
      "hover on" style ("tableCell:hover"/"tableCellIeHoverFix").

      This gives any element with a class value "tableCell" an initial
      background colour of 33CCCC. For recent Netscape and Opera browsers,
      ".tableCell:hover" takes care of the hover effect automatically - mouse
      over any element with a class value "tableCell" and the background colour
      will change to CC0000.

      ".tableCellIeHoverFix" is used by this script if the browser is IE to
      implement the effect by adding onmouseover and onmouseout handlers to
      change the class name as appropriate.
*/


/*
   Suffix used to turn the "hover off" class into the "hover on" class and
   removed to change it back from a "hover on" class to a "hover off" class.
*/
suffix = "IeHoverFix";

/*
   Constructor for an IeHoverFix object.
   Param:   classNames an array of strings - names of the all the
            style classes that should have a hover effect added to them.
   Param:   hoverElementTypes an array of strings - names of the all HTML
            elements to which you wish to ad a hover effect to (if the element
            has a class name found in classNameMatches).
*/
function IeHoverFix(classNames, hoverElementTypes) {
   // Parameters.
   this.classNames = classNames;
   this.hoverElementTypes = hoverElementTypes;
   // Functions.
   this.eventHover = eventHover;
   this.eventUnHover = eventUnHover;
   this.getElementFromEvent = getElementFromEvent;
   this.addEventHandler = addEventHandler;
   this.arbitraryHoverHandlers = arbitraryHoverHandlers;
   this.classNameMatches = classNameMatches;
   this.addLoadEvent = addLoadEvent;
   // Add the hovering onload
   this.addLoadEvent (arbitraryHoverHandlers);
}

/*
   Add our arbitraryHoverHandlers function to the onLoad function of the page
   that loads this script.
   Source: http://simon.incutio.com/archive/2004/05/26/addLoadEvent
   Param:   new function to add to the body element's onLoad event handler
*/
function addLoadEvent(func) {
   var oldonload = window.onload;
   if (typeof window.onload != 'function') {
      window.onload = func;
   } else {
      window.onload = function() {
         oldonload();
         func();
      }
   }
}

/*
   This method is called onmouseover. Copes elements that have multiple class
   names.

   Get the element which initiated this event call, go through each class name
   for that element and whenever you find one that matches one of those in the
   classNames array, append the ieHoverFix suffix to it.
   Param:   the even object generated by a mouseOver on a given HTML element
*/
function eventHover(event) {
   hoverElement = this.getElementFromEvent(event);
   var classes = hoverElement.className.split(" ");
   var newClassString = "";
   for (var index = 0; index < classes.length; index++) {
      if (this.classNameMatches(classes[index])) {
         if (index == 0) {
            newClassString += (classes[index] + suffix);
         }
         else {
            newClassString += (" " + classes[index] + suffix);
         }
      } else {
         if (index == 0) {
            newClassString += classes[index];
         }
         else {
            newClassString += (" " + classes[index]);
         }
      }
   }
   hoverElement.className = newClassString;
}

/*
   This method is called onmouseout to remove suffix from all hover classes in
   the element.
   Param:   the even object generated by a mouseOut on a given HTML element
*/
function eventUnHover(event) {
   // get the element which initiated this event call
   hoverElement = this.getElementFromEvent(event);
   // remove any reference to the "hover" class
   var regularExpression = new RegExp(suffix, "gi");
   hoverElement.className =
         hoverElement.className.replace(regularExpression, '');
}

/*
   Retrieve the element that triggered a given event.
   Param:   event that was triggered from the element we want to retrieve
   Return:  element that triggered the event
*/
function getElementFromEvent(event) {
   if (event.srcElement) {
      return event.srcElement;
   }
   return null;
}

/*
   Generic event add method element,  [string],  [function name]
   Param:   element  HTML element to which we shall ad an even handler
   Param:   evenNamt name of the event, such as "mouseOut" or "mouseOver"
   Param:   functionName name of the function that will be added as the handler
*/
function addEventHandler(element, eventName, functionName) {
   if (element.attachEvent) {
      element.attachEvent('on' + eventName, functionName);
   }
}

/*
   Add handlers for onMouseout and onMouseover to all elements in
   hoverElementTypes that have a class named in classNames.
*/
function arbitraryHoverHandlers() {
   var bodyElements;
   // Do nothing if getElementsByTagName is not supported.
   if (!document.body.getElementsByTagName) return;
   for (var i = 0; i < this.hoverElementTypes.length; i ++) {
      bodyElements =
            document.body.getElementsByTagName(this.hoverElementTypes[i]);
      for(j = 0; j < bodyElements.length; j++) {
         if (this.classNameMatches (bodyElements[j].className)) {
            this.addEventHandler(bodyElements[j], "mouseover", this.eventHover);
            this.addEventHandler(bodyElements[j], "mouseout", this.eventUnHover);
         }
      }
   }
}

/*
   Return true if the given class name is one of the class names you want
   to add the hover effect to. This class name will be searched for among
   those element types specified by the hoverElementTypeMatches function.
   Param: className that may or may not appears in the classNames array
   Return: true className does appear in the classNames array, false otherwise
*/
function classNameMatches (className) {
   for (var index = 0; index < this.classNames.length; index ++) {
      if (className.indexOf(this.classNames [index]) >= 0) return true;
   }
   return false;     // No match!
}
