|
2 | 2 | class ExpandingList extends HTMLUListElement {
|
3 | 3 | constructor() {
|
4 | 4 | // Always call super first in constructor
|
5 |
| - super(); |
6 |
| - |
7 |
| - window.onload = function() { |
8 |
| - const uls = Array.from(document.querySelectorAll(':root ul')); |
9 |
| - const lis = Array.from(document.querySelectorAll(':root li')); |
10 |
| - |
11 |
| - uls.slice(1).forEach(ul => { |
12 |
| - ul.style.display = 'none'; |
13 |
| - }); |
14 |
| - |
15 |
| - lis.forEach(li => { |
| 5 | + // Return value from super() is a reference to this element |
| 6 | + self = super(); |
| 7 | + |
| 8 | + // Get ul and li elements that are a child of this custom ul element |
| 9 | + // li elements can be containers if they have uls within them |
| 10 | + const uls = Array.from(self.querySelectorAll('ul')); |
| 11 | + const lis = Array.from(self.querySelectorAll('li')); |
| 12 | + |
| 13 | + // Hide all child uls |
| 14 | + // These lists will be shown when the user clicks a higher level container |
| 15 | + uls.forEach(ul => { |
| 16 | + ul.style.display = 'none'; |
| 17 | + }); |
| 18 | + |
| 19 | + // Look through each li element in the ul |
| 20 | + lis.forEach(li => { |
| 21 | + // If this li has a ul as a child, decorate it and add a click handler |
| 22 | + if (li.querySelectorAll('ul').length > 0) { |
| 23 | + // Add an attribute which can be used by the style |
| 24 | + // to show an open or closed icon |
| 25 | + li.setAttribute('class', 'closed'); |
| 26 | + |
| 27 | + // Wrap the li element's text in a new span element |
| 28 | + // so we can assign style and event handlers to the span |
16 | 29 | const childText = li.childNodes[0];
|
17 | 30 | const newSpan = document.createElement('span');
|
18 | 31 |
|
| 32 | + // Copy text from li to span, set cursor style |
19 | 33 | newSpan.textContent = childText.textContent;
|
| 34 | + newSpan.style.cursor = 'pointer'; |
| 35 | + |
| 36 | + // Add click handler to this span |
| 37 | + newSpan.onclick = self.showul; |
| 38 | + |
| 39 | + // Add the span and remove the bare text node from the li |
20 | 40 | childText.parentNode.insertBefore(newSpan, childText);
|
21 | 41 | childText.parentNode.removeChild(childText);
|
22 |
| - }); |
23 |
| - |
24 |
| - const spans = Array.from(document.querySelectorAll(':root span')); |
25 |
| - |
26 |
| - spans.forEach(span => { |
27 |
| - if (span.nextElementSibling) { |
28 |
| - span.style.cursor = 'pointer'; |
29 |
| - span.parentNode.setAttribute('class', 'closed'); |
30 |
| - span.onclick = showul; |
31 |
| - } |
32 |
| - }); |
33 |
| - |
34 |
| - function showul(e) { |
35 |
| - const nextul = e.target.nextElementSibling; |
36 |
| - |
37 |
| - if (nextul.style.display == 'block') { |
38 |
| - nextul.style.display = 'none'; |
39 |
| - nextul.parentNode.setAttribute('class', 'closed'); |
40 |
| - } else { |
41 |
| - nextul.style.display = 'block'; |
42 |
| - nextul.parentNode.setAttribute('class', 'open'); |
43 |
| - } |
44 | 42 | }
|
45 |
| - }; |
| 43 | + }); |
46 | 44 | }
|
| 45 | + |
| 46 | + // li click handler |
| 47 | + showul = function (e) { |
| 48 | + // next sibling to the span should be the ul |
| 49 | + const nextul = e.target.nextElementSibling; |
| 50 | + |
| 51 | + // Toggle visible state and update class attribute on ul |
| 52 | + if (nextul.style.display == 'block') { |
| 53 | + nextul.style.display = 'none'; |
| 54 | + nextul.parentNode.setAttribute('class', 'closed'); |
| 55 | + } else { |
| 56 | + nextul.style.display = 'block'; |
| 57 | + nextul.parentNode.setAttribute('class', 'open'); |
| 58 | + } |
| 59 | + }; |
47 | 60 | }
|
48 | 61 |
|
49 | 62 | // Define the new element
|
|
0 commit comments