Team:Paris Bettencourt/js/CollapsibleLists.js

From 2012.igem.org

/*

CollapsibleLists.js

An object allowing lists to dynamically expand and collapse

Created by Stephen Morley - http://code.stephenmorley.org/ - and released under the terms of the CC0 1.0 Universal legal code:

http://creativecommons.org/publicdomain/zero/1.0/legalcode

  • /

// create the CollapsibleLists object var CollapsibleLists =

   new function(){
     /* Makes all lists with the class 'collapsibleList' collapsible. The
      * parameter is:
      *
      * doNotRecurse - true if sub-lists should not be made collapsible
      */
     this.apply = function(doNotRecurse){
       // loop over the unordered lists
       var uls = document.getElementsByTagName('ul');
       for (var index = 0; index < uls.length; index ++){
         // check whether this list should be made collapsible
         if (uls[index].className.match(/(^| )collapsibleList( |$)/)){
           // make this list collapsible
           this.applyTo(uls[index], true);
           // check whether sub-lists should also be made collapsible
           if (!doNotRecurse){
             // add the collapsibleList class to the sub-lists
             var subUls = uls[index].getElementsByTagName('ul');
             for (var subIndex = 0; subIndex < subUls.length; subIndex ++){
               subUls[subIndex].className += ' collapsibleList';
             }
           }
         }
       }
     };
     /* Makes the specified list collapsible. The parameters are:
      *
      * node         - the list element
      * doNotRecurse - true if sub-lists should not be made collapsible
      */
     this.applyTo = function(node, doNotRecurse){
       // loop over the list items within this node
       var lis = node.getElementsByTagName('li');
       for (var index = 0; index < lis.length; index ++){
         // check whether this list item should be collapsible
         if (!doNotRecurse || node == lis[index].parentNode){
           // prevent text from being selected unintentionally
           if (lis[index].addEventListener){
             lis[index].addEventListener(
                 'mousedown', function (e){ e.preventDefault(); }, false);
           }else{
             lis[index].attachEvent(
                 'onselectstart', function(){ event.returnValue = false; });
           }
           // add the click listener
           if (lis[index].addEventListener){
             lis[index].addEventListener(
                 'click', createClickListener(lis[index]), false);
           }else{
             lis[index].attachEvent(
                 'onclick', createClickListener(lis[index]));
           }
           // close the unordered lists within this list item
           toggle(lis[index]);
         }
       }
     };
     /* Returns a function that toggles the display status of any unordered
      * list elements within the specified node. The parameter is:
      *
      * node - the node containing the unordered list elements
      */
     function createClickListener(node){
       // return the function
       return function(e){
         // ensure the event object is defined
         if (!e) e = window.event;
         // find the list item containing the target of the event
         var li = (e.target ? e.target : e.srcElement);
         while (li.nodeName != 'LI') li = li.parentNode;
         // toggle the state of the node if it was the target of the event
         if (li == node) toggle(node);
       };
     }
     /* Opens or closes the unordered list elements directly within the
      * specified node. The parameter is:
      *
      * node - the node containing the unordered list elements
      */
     function toggle(node){
       // determine whether to open or close the unordered lists
       var open = node.className.match(/(^| )collapsibleListClosed( |$)/);
       // loop over the unordered list elements with the node
       var uls = node.getElementsByTagName('ul');
       for (var index = 0; index < uls.length; index ++){
         // find the parent list item of this unordered list
         var li = uls[index];
         while (li.nodeName != 'LI') li = li.parentNode;
         // style the unordered list if it is directly within this node
         if (li == node) uls[index].style.display = (open ? 'block' : 'none');
       }
       // remove the current class from the node
       node.className =
           node.className.replace(
               /(^| )collapsibleList(Open|Closed)( |$)/, );
       // if the node contains unordered lists, set its class
       if (uls.length > 0){
         node.className += ' collapsibleList' + (open ? 'Open' : 'Closed');
       }
     }
   }();