CollapsibleLists.src.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. CollapsibleLists.js
  3. An object allowing lists to dynamically expand and collapse
  4. Created by Kate Morley - http://code.iamkate.com/ - and released under the terms
  5. of the CC0 1.0 Universal legal code:
  6. http://creativecommons.org/publicdomain/zero/1.0/legalcode
  7. */
  8. const CollapsibleLists = (function(){
  9. // Makes all lists with the class 'collapsibleList' collapsible. The
  10. // parameter is:
  11. //
  12. // doNotRecurse - true if sub-lists should not be made collapsible
  13. function apply(doNotRecurse){
  14. [].forEach.call(document.getElementsByTagName('ul'), node => {
  15. if (node.classList.contains('collapsibleList')){
  16. applyTo(node, true);
  17. if (!doNotRecurse){
  18. [].forEach.call(node.getElementsByTagName('ul'), subnode => {
  19. subnode.classList.add('collapsibleList')
  20. });
  21. }
  22. }
  23. })
  24. }
  25. // Makes the specified list collapsible. The parameters are:
  26. //
  27. // node - the list element
  28. // doNotRecurse - true if sub-lists should not be made collapsible
  29. function applyTo(node, doNotRecurse){
  30. [].forEach.call(node.getElementsByTagName('li'), li => {
  31. if (!doNotRecurse || node === li.parentNode){
  32. li.style.userSelect = 'none';
  33. li.style.MozUserSelect = 'none';
  34. li.style.msUserSelect = 'none';
  35. li.style.WebkitUserSelect = 'none';
  36. li.addEventListener('click', handleClick.bind(null, li));
  37. toggle(li);
  38. }
  39. });
  40. }
  41. // Handles a click. The parameter is:
  42. //
  43. // node - the node for which clicks are being handled
  44. function handleClick(node, e){
  45. let li = e.target;
  46. while (li.nodeName !== 'LI'){
  47. li = li.parentNode;
  48. }
  49. if (li === node){
  50. toggle(node);
  51. }
  52. }
  53. // Opens or closes the unordered list elements directly within the
  54. // specified node. The parameter is:
  55. //
  56. // node - the node containing the unordered list elements
  57. function toggle(node){
  58. const open = node.classList.contains('collapsibleListClosed');
  59. const uls = node.getElementsByTagName('ul');
  60. [].forEach.call(uls, ul => {
  61. let li = ul;
  62. while (li.nodeName !== 'LI'){
  63. li = li.parentNode;
  64. }
  65. if (li === node){
  66. ul.style.display = (open ? 'block' : 'none');
  67. }
  68. });
  69. node.classList.remove('collapsibleListOpen');
  70. node.classList.remove('collapsibleListClosed');
  71. if (uls.length > 0){
  72. node.classList.add('collapsibleList' + (open ? 'Open' : 'Closed'));
  73. }
  74. }
  75. return {apply, applyTo};
  76. })();