Pure js + CSS expand collapse menu

by epinapala

HTML

<div class="panel" data-id="apiOverviewGuidelines">
  <button class="panel-header" onClick='handleMenuButtonClick(this)'>API Overview &amp; Guidelines</button>
  <div class="panelcontent" style="display: block; height: 0px;">
    <div class="collapsed" data-id="introduction"><a class="link" href="#">Introduction</a></div>
    <div class="collapsed" data-id="designSummary"><a class="link" href="#">Design Summary</a></div>
    <div class="collapsed" data-id="businessUseCases"><a class="link" href="#">Business Use cases</a></div>
    <div class="collapsed" data-id="restrictionsLimitations"><a class="link" href="#">Restrictions &amp; limitations</a></div>
  </div>
</div>
<div class="panel" data-id="apiReference">
  <button class="panel-header" onClick='handleMenuButtonClick(this)'>API Reference</button>
  <div class="panelcontent" style="display: block; height: 0px;">
    <div class="collapsed" data-id="marketing-resourceTypes"><a class="link" href="/api-docs/sell/marketing/resources/methods">Resource Types</a></div>
    <div class="collapsed" data-id="ad_report">
      <button class="panel-header" onClick='handleMenuButtonClick(this)'>AD REPORT</button>
      <div class="panelcontent">
        <div class="collapsed" data-id="marketing-ad_report-getReport"><a class="link" href="/api-docs/sell/marketing/resources/ad_report/methods/getReport">Get Specific Report</a></div>
      </div>
    </div>
    <div class="panel" data-id="ad_report_metadata">
      <button class="panel-header" onClick='handleMenuButtonClick(this)'>AD REPORT METADATA</button>
      <div class="panelcontent">
        <div class="collapsed" data-id="marketing-ad_report_metadata-getReportMetadata"><a class="link selected" href="/api-docs/sell/marketing/resources/ad_report_metadata/methods/getReportMetadata">Get Metadata For All Reports</a></div>
        <div class="collapsed" data-id="marketing-ad_report_metadata-getReportMetadataForReportType"><a class="link"...

CSS

/* panel */

.panel,
.panelcollapsed {
  margin: 5px;
  padding: 0px 0px 5px;
  width: 300px;
}


/* panel heading */

.panel h2,
.panelcollapsed h2 {
  font-size: 18px;
  font-weight: normal;
  margin: 0px;
  padding: 4px;
  background: #CCC url(arrow-up.gif) no-repeat 280px;
  border-bottom: 1px solid #999;
  -moz-border-radius: 3px;
  -webkit-border-radius: 3px;
  border-top: 1px solid #FFF;
  border-right: 1px solid #FFF;
  border-left: 1px solid #FFF;
}


/* panel heading on rollover */

.panel h2:hover,
.panelcollapsed h2:hover {
  background-color: #A9BCEF;
}


/* heading of a collapsed panel */

.panelcollapsed h2 {
  background: #CCC url(arrow-dn.gif) no-repeat 280px;
  border-color: #CCC;
}


/* collapsed panel content */

.panelcollapsed .panelcontent {
  display: none;
}

button {
  background-color: Transparent;
  background-repeat: no-repeat;
  border: none;
  cursor: pointer;
  overflow: hidden;
  outline: none;
}

JavaScript

var PANEL_NORMAL_CLASS = "panel";
var PANEL_COLLAPSED_CLASS = "panelcollapsed";
var PANEL_HEADING_TAG = "button";
var PANEL_CONTENT_CLASS = "panelcontent";
var PANEL_COOKIE_NAME = "panels";
var PANEL_ANIMATION_DELAY = 20; /*ms*/
var PANEL_ANIMATION_STEPS = 10;

function setUpPanels() {
	var panelsStatus = {};
  // get all headings
  var headingTags = document.getElementsByTagName(PANEL_HEADING_TAG);

  // go through all tags
  for (var i = 0; i < headingTags.length; i++) {
    var el = headingTags[i];

    // make sure it's the heading inside a panel
    if (el.parentNode.className != PANEL_NORMAL_CLASS && el.parentNode.className != PANEL_COLLAPSED_CLASS)
      continue;

    // get the text value of the tag
    var name = el.firstChild.nodeValue;

    panelsStatus[name] = (el.parentNode.className == PANEL_NORMAL_CLASS) ? "true" : "false";

    // add the click behavor to headings
    el.onclick = function() {
      var target = this.parentNode;
      var name = this.firstChild.nodeValue;
      var collapsed = (target.className == PANEL_COLLAPSED_CLASS);
      animateTogglePanel(target, collapsed);
    };
  }
}

/**
 * Start the expand/collapse animation of the panel
 * @param panel reference to the panel div
 */
function animateTogglePanel(panel, expanding) {
  // find the .panelcontent div
  var elements = panel.getElementsByTagName("div");
  var panelContent = null;
  for (var i = 0; i < elements.length; i++) {
    if (elements[i].className == PANEL_CONTENT_CLASS) {
      panelContent = elements[i];
      break;
    }
  }

  // make sure the content is visible before getting its height
  panelContent.style.display = "block";

  // get the height of the content
  var contentHeight = panelContent.offsetHeight;

  // if panel is collapsed and expanding, we must start with 0 height
  if (expanding)
    panelContent.style.height = "0px";

  var stepHeight = contentHeight / PANEL_ANIMATION_STEPS;
  var direction = (!expanding ? -1 : 1);

  setTimeout(function() {
  ...