/*

CollapsibleLists.js

An object allowing lists to dynamically expand and collapse

Created by Kate Morley - http://code.iamkate.com/ - and released under the terms
of the CC0 1.0 Universal legal code:

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

*/

const CollapsibleLists = (function(){

  // Makes all lists with the class 'collapsibleList' collapsible. The
  // parameter is:
  //
  // doNotRecurse - true if sub-lists should not be made collapsible
  function apply(doNotRecurse){

    [].forEach.call(document.getElementsByTagName('ul'), node => {

      if (node.classList.contains('collapsibleList')){

        applyTo(node, true);

        if (!doNotRecurse){

          [].forEach.call(node.getElementsByTagName('ul'), subnode => {
            subnode.classList.add('collapsibleList')
          });

        }

      }

    })

  }

  // Makes the specified list collapsible. The parameters are:
  //
  // node         - the list element
  // doNotRecurse - true if sub-lists should not be made collapsible
  function applyTo(node, doNotRecurse){

    [].forEach.call(node.getElementsByTagName('li'), li => {

      if (!doNotRecurse || node === li.parentNode){

        li.style.userSelect       = 'none';
        li.style.MozUserSelect    = 'none';
        li.style.msUserSelect     = 'none';
        li.style.WebkitUserSelect = 'none';

        li.addEventListener('click', handleClick.bind(null, li));

        toggle(li);

      }

    });

  }

  // Handles a click. The parameter is:
  //
  // node - the node for which clicks are being handled
  function handleClick(node, e){

    let li = e.target;
    while (li.nodeName !== 'LI'){
      li = li.parentNode;
    }

    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){

    const open = node.classList.contains('collapsibleListClosed');
    const uls  = node.getElementsByTagName('ul');

    [].forEach.call(uls, ul => {

      let li = ul;
      while (li.nodeName !== 'LI'){
        li = li.parentNode;
      }

      if (li === node){
        ul.style.display = (open ? 'block' : 'none');
      }

    });

    node.classList.remove('collapsibleListOpen');
    node.classList.remove('collapsibleListClosed');

    if (uls.length > 0){
      node.classList.add('collapsibleList' + (open ? 'Open' : 'Closed'));
    }

  }

  return {apply, applyTo};

})();
