MINDSACK.toggle = function() {
 
   // private bucket for scope-sensitive variables -- thanks, Dustin
   var $ = {};
   
   return {   
      init : function(selfObj, toggleClass, toggleOpen, toggleClosed) {
         // first, a brute-force hack to decode the calling function's
         // name and store it upstairs, safe from scope creep
         $.selfName = this.getSelfName(selfObj);
         
         // we're going to hang all variables that might be confused
         // by scope changes later onto MINDSACK.variables, which is
aliased to $. 
         // In this case it's three class names, fed in from the init
call:
 
         $.toggleClass = toggleClass;
         $.toggleOpen = toggleOpen;
         $.toggleClosed = toggleClosed;
         
         // crawl through the document, look for toggled elements
         this.crawl(document.body);
      },
      crawl : function(el) {
         // get this element's next sibling
         var nextSib = this.getNextSibling(el);
 
         // if it has a class name, the class name matches our toggle
class, and there's something there to toggle:
         if (el.className && el.className.match($.toggleClass) &&
nextSib)
         {
            // to avoid scope loss, attach onmouseup to the toggle
function with eval and $.selfName
            el.onclick = function () {
               eval($.selfName + '.toggleState(this)');
               return false;
            };
           
            // if the next sib ought to be hidden and it isn't already,
hide it
            if (el.className.match($.toggleClosed) && nextSib)
       {
              nextSib.style.display = "none";
       }
      else if (el.className.match($.toggleOpen) && nextSib)
       {
       nextSib.style.display = "block";
       }
         }
 
         // is there more to do? Do it, if so:
         if (el.firstChild) {
            this.crawl(el.firstChild);
         }
         
         if (nextSib)
     {
     this.crawl(nextSib);
     }
      },
     
      toggleState : function(el)
    {
        var nextSib = this.getNextSibling(el);
       
    // change the style of the triggering element
    if(el.className.match($.toggleClosed))
     {
     el.className = el.className.replace($.toggleClosed, $.toggleOpen);
     
     if(nextSib)
       nextSib.style.display = "block";
     }
    else if (el.className.match($.toggleOpen))
     {
     el.className = el.className.replace($.toggleOpen, $.toggleClosed);
     if(nextSib)
      nextSib.style.display = "none";
     
     }
    else
     {
     el.className += " " + $.toggleClosed;
 
     if(nextSib)
      nextSib.style.display = "none";
     }
    },
   
      getNextSibling : function(el) {
         var nextSib = el.nextSibling;
         // hack for Gecko browsers
         if (nextSib && nextSib.nodeType != 1) {
            nextSib = nextSib.nextSibling;
         }
         return nextSib;
    },
   
      getSelfName : function(selfObj) {
         // icky hack to get contents of selfObj into a string
         // suggestions will be gratefully appreciated
         var s = document.createElement('SPAN');
         s.innerHTML = selfObj;
         // cut the fat, split the meat to namespace array
         var nameSpace =
s.innerHTML.split('{')[1].split('(')[0].replace(/^\s+/, '').split('.');
         var selfName = '';
         // here we assume that the main function is up one level from
the init function
         for (var i = 0; i < nameSpace.length - 1; i++) {
            if (selfName) {
               selfName += '.';
            }
            selfName += nameSpace[i];
         }
         return selfName;
      }
   };
}();
 
// feed it the CSS class names of your choice
window.onload = function() {
   MINDSACK.toggle.init(arguments.callee, 'toggle', 'open', 'closed');
};
 