1
\$\begingroup\$

The below produces the output I want. Namely, it initially displays the first item on the list and the first expander link. When an expander link is clicked, it hides that link, unhides one more item in the list, and unhides the next expander link.

I'm wondering if it can tightened up. JQuery is a definite no-no.

	window.onload = function() {
		var anchors = document.getElementsByTagName('a');
		for(var i = 0; i < anchors.length; i++) {
			var anchor = anchors[i];
			if(anchor.classList.contains('expander_link')) {
				anchor.onclick = function(e) {
					e.preventDefault();
					e.target.setAttribute('style', 'display:none');
					var href = e.target.getAttribute("href")
					var unhide = document.getElementById(href);
					unhide.setAttribute('style', '');
					var data = e.target.getAttribute("data");
					var link = "link_" + (parseInt(data)+1);
					var next = document.getElementById(link);
					next.setAttribute('style', '');
				}
			}
		}
	}
		body {
		  margin: 15pt 20pt 0pt 20pt;
		  padding: 0;
		}

		p {
		  margin: 8pt 0 8pt 0;
		  padding: 0;
		}

		.center {
		  margin: auto;
		  align-self: center;
		  text-align: center;
		}

		h4 {
		  color: #004080;
		  font-size: 120%;
		  margin: 100pt 0 0 0;
		}

		.nobullets {
		  list-style: none;
		}

		.hidden {
		  display: none;
		}`

		table {
		  border-spacing: 0;
		}

		th, td {
		  text-align: center;
		  padding: 3pt;
		  margin: 0;
		}

		ul {
			list-style-type: none;
			margin-left:0;
			padding-left:0;
		}

		ul ul {
		  list-style: disc;
		  margin-left: 20pt;
		}

		li[id]{
		  border-top: 1px solid #AAAAAA;
		}

		a#link_0 + [id] {
		  border-top: none;
		}

		.block {
		  display: block;
		 }

		.expander_link {
		  padding-top: 8pt;
		  padding-bottom: 30pt;
		  font-size: 120%;
		  font-weight: bold;
		  color: #004080;
		  text-align: center;
		  align-self: center;
		  text-decoration: none;
		  display: block;
		  border-top: 1px solid #AAAAAA;
		}
<h4 class="center">Expanding list</h4>
<ul>
<li class="export-chunk" id="4136">
<p>
  part one
  </p>
</li>
<a id="link_1" href="4137" data="1" class="expander_link">show part two</a>
<li class="export-chunk" style="display:none;" id="4137">
<p>
	part two
	</p>
</li>

<a id="link_2" href="4138" data="2" class="expander_link" style="display:none;">show the third part</a>
<li class="export-chunk" style="display:none;" id="4138">
	<p>
part 3
</p>
</li>

<a id="link_3" href="4139" data="3" class="expander_link" style="display:none;">show part 4</a>
<li class="export-chunk" style="display:none;" id="4139">

<p>
part 4
</p>
</li>
</ul>

\$\endgroup\$
1
\$\begingroup\$

My solution relies on the CSS rule which says, "hide all list items that come after the one with the active class."

li.active ~ li {
  display: none;
}

The JavaScript deals with getting the index of the list item containing the active class and re-assigning the active class to the next list item (if there is one).

window.addEventListener("load", init);

var btn, list_length, ul;

function init() {
  ul = document.getElementsByTagName("ul")[0];  
  btn = document.getElementsByTagName("button")[0];
  list_length = ul.children.length;
  
  btn.addEventListener("click", function() {
    if (getItemIndex(getActiveItem()) < (list_length -1)) {
      showNextItem();      
    }
  });
}

function getActiveItem() {
  return document.getElementsByClassName("active")[0];
}

function getItemIndex(active_item) {
  var nodeList = Array.prototype.slice.call(ul.children);
  
  return nodeList.indexOf(active_item);
}

function getListItem(index) {
  return document.getElementsByTagName("li")[index]; 
}

function showNextItem() {
  var active_item = getActiveItem(),
      next_index  = getItemIndex(active_item) + 1,
      next_item   = getListItem(next_index);
  
  active_item.classList.remove("active");
  next_item.classList.add("active");

  if ((next_index + 1) < list_length) {  
    btn.getElementsByTagName("span")[0].innerHTML = getListItem(next_index + 1).innerHTML;    
  } else {
    btn.classList.add("hide");
  }
}
h1 {
  font-size: 1.2em;
}

button {
  font-size: 1em;
}

button.hide {
  display: none;
}

ul {
  margin: 0 0 1em;
  padding: 0;
  border-bottom: 1px solid gray;
  width: 40em;
}

li {
  list-style: none;
  padding: 0.8em 0;
  border-top: 1px solid gray;  
}

li.active ~ li {
  display: none;
}
<h1>Expanding List</h1>

<ul>
  <li class="active">part one</li>
  <li>part two</li>
  <li>part three</li>
  <li>part four</li>
</ul>

<button>Show <span>part two</span>
</button>

\$\endgroup\$
  • \$\begingroup\$ My example was incomplete. That gets confused if there is a nested list inside one of the parts. Said list should act normally. \$\endgroup\$ – William Jockusch May 13 '16 at 6:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.