/*
 * Richmond Pharmacology
 * Script: utils.js
 * Utility functions
 *
 * By Andy Smith, Preview Graphics
 * www.preview.co.uk
 */


/*
 * Functional programming utilities
 * --------------------------------------------------------------------------
 */
 
function filter(pred, list)
{
  var result = [];
  var rescount = 0;
  for (var i = 0; i < list.length; i++)
    {
      if ((typeof list[i] != 'undefined') && pred(list[i]))
        {
          result[rescount] = list[i];  // push not supported in IE5
	  rescount++;
        }
    }
  return result;
}
 
function map(fn, list)
{
  var result = [];
  for (var i = 0; i < list.length; i++)
    {
      if (typeof list[i] != 'undefined')
        {
          result[i] = fn(list[i]);
        }
    }
  return result;
}


/*
 * String processing utilities
 * --------------------------------------------------------------------------
 */

/*
 * Determine whether an item is present in a space-separated list (such
 * as an HTML class attribute).
 */
 
function getSpaceListItem(list, item)
{
  var itemre = new RegExp('\\b' + item + '\\b');
  return itemre.test(list);
}

/*
 * Add or remove an item from a space-separated list (such as an HTML
 * class attribute). If present is true, the returned string will
 * include the item; if it is false, the returned string will not
 * include it.
 */
 
function setSpaceListItem(list, item, present)
{
  var itemre = new RegExp('\\b' + item + '\\b');
  if (present)
    {
      // See if the item is already in the list, and if not add it.
      if (itemre.test(list))
          return list;
      else
          return list + ' ' + item;
    }
  else
    {
      // Remove the item from the list if it exists.
      return list.replace(itemre, '');
    }
}


/*
 * DOM node utilities
 * --------------------------------------------------------------------------
 */

/*
 * Get a list of all the child elements of a node - like node.children[]
 * but that doesn't work in Mozilla.
 */

function childElements(node)
{
  return filter(function (nd) { return (nd.nodeType == 1); },
                node.childNodes);
}


/*
 * DOM event utilities
 * --------------------------------------------------------------------------
 */

/*
 * Cross-browser event handler registration
 * By Scott Andrew - http://www.scottandrew.com/weblog/articles/cbs-events
 */

function addEvent(obj, evType, fn)
{
  if (obj.addEventListener)
    {
      obj.addEventListener(evType, fn, true);
      return true;
    }
  else if (obj.attachEvent)
    {
      var r = obj.attachEvent("on"+evType, fn);
      return r;
    }
  else
    {
      return false;
    }
}

/*
 * Cross-browser event target
 */
 
function getEventTarget(ev)
{
  var target;
  if (ev.target)                 /* W3C/Mozilla */
    target = ev.target;
  else if (ev.srcElement)        /* Internet Explorer */
    target = ev.srcElement;
  else                           /* No support */
    target = null;
  if (target.nodeType && (target.nodeType == 3))
    target = target.parentNode;  /* Safari bug fix */
  return target;
}

/*
 * Get the link containing an event target. When a link is clicked, the
 * event may be fired on a child element of the link rather than the
 * link itself. To use event handlers that need link properties, we need
 * to find the link. If the event target is a link, return it; otherwise
 * check its parent node, and its parent and so on, until a link is found,
 * or return null if the event target is not inside a link.
 */

function getEventLinkTarget(ev)
{
  var el = getEventTarget(ev);
  while (el)
    {
      if (el.nodeName == 'A') return el;
      el = el.parentNode;
    }
  return null;
}

/*
 * Cross-browser method to stop an event's default action. Designed to
 * be called from an event handler like this:
 *
 *    return stopEvent(e);
 *
 * In browsers that support the preventDefault method, this is used;
 * Mozilla carries out the default method without this, even if the
 * event handler returns false, if the handler was added with
 * addEventListener(). (I'm not sure if this is the correct behaviour).
 * Other browsers use the return value from the event handler.
 */
 
function stopEventDefault(ev)
{
  if (ev.preventDefault) ev.preventDefault();
  return false;
}


/*
 * HTML utilities
 * --------------------------------------------------------------------------
 */

/*
 * Check whether an element has a particular class in its list of classes.
 */
 
function checkClass(el, cls)
{
  return getSpaceListItem(el.className, cls);
}

/*
 * Add or remove a class from an element's list of classes. If present
 * is true, the class list will include the specified class; if false,
 * the class list will not include it.
 */
 
function setClass(el, cls, present)
{
  el.className = setSpaceListItem(el.className, cls, present);
}


