DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

DHTML Tabs

05.13.2006
| 15196 views |
  • submit to reddit
        Reformats a structured HTML page with tabs for each section.

<html>
<head>
<script type="text/javascript">
  TAB_HEADINGS = 'h2';
  TAB_CLASS = 'tab';
  SECTION_CLASS = 'section';
  QUERY_SECTION_ARG = 'section';
  TAB_SELECTED_CLASS = 'selected';
  TAB_NOT_SELECTED_CLASS = 'not-selected';
  LOADING_ELM_ID = 'loading';
  CONTENT_HOLDER_ID = 'content-holder';

  lastSection = 0
  function checkHash() {
    var section = get_selected();
    if(section != lastSection) {
      show_section(section);
      lastSection = section;
    }
  }

  function get_elements() {
    var divs = document.getElementsByTagName("div");
    var htags = document.getElementsByTagName(TAB_HEADINGS);
    sections = [];
    tabs = [];
    headings = []
    for(var i=0; i<divs.length; i++) {
      if(divs[i].className == SECTION_CLASS) sections.push(divs[i]);
    }
    for(var i=0; i<htags.length; i++) {
      if(htags[i].className == TAB_CLASS) {
        var span = document.createElement("span");
        span.innerHTML = htags[i].innerHTML;
        tabs.push(span);
        headings.push(htags[i]);
      }
    }
  };

  function combine_tabs(){
    if(headings.length == 0)return;
    headings[0].innerHTML = '';
    for(var i=0; i<tabs.length; i++) {
  //    headings[i].removeChild(tabs[i]);
      headings[0].appendChild(tabs[i]);
      if(i > 0) headings[i].parentNode.removeChild(headings[i]);
    }
  };

  function hide_all(){
    for(var i=0; i<sections.length; i++) {
      sections[i].style.display = "none";
    }
    for(var i=0; i<tabs.length; i++) {
      tabs[i].className = TAB_NOT_SELECTED_CLASS
    }
  };

  function show_section(index){
    hide_all()
    if(sections.length == 0) return;
    var section = sections[index];
    if(!section) var section = sections[index=0];
    section.style.display = "block";
    tabs[index].className = TAB_SELECTED_CLASS;
    var id = headings[index].getAttribute('id') || sections[index].getAttribute('id');
    if(id && index != lastSection) {
      var y = typeof window.pageYOffset != 'undefined' ? window.pageYOffset : document.documentElement.scrollTop;
      if(!navigator.userAgent.match(/Safari/)) location.hash = '#' + id;
      window.scrollTo(0, y);
      if(typeof load_tab == 'function') load_tab(id);
    }
    lastSection = index;
  };

  function tab_click(e){
    var target = e && e.target || event.srcElement;
    for(var i=0; i<tabs.length; i++) {
      if(target == tabs[i] || target.parentNode == tabs[i]){
        show_section(i);
      }
    }
  };

  function set_handlers(){
    for(var i=0; i<tabs.length; i++) {
      tabs[i].onclick = tab_click;
    }
  };

  function get_selected(){
    var selected = 0;
    if(location.hash) {
      selected = location.hash.substring(1);
    } else if(location.search) {
      var args = location.search.substring(1).split('&');
      for(var i=0; i<args.length; i++) {
        var name = args[i].split('=')[0];
        var value = args[i].split('=')[1];
        if(name == QUERY_SECTION_ARG){
            selected = value;
            break;
        }
      }
    }
    if(isNaN(selected)){
      for(var i=0; i<sections.length; i++){
        if(sections[i].getAttribute('id') == selected || headings[i].getAttribute('id') == selected){
          selected = i;
          break;
        }
      }
    }
    return selected;
  };

  function set_up() {
    get_elements();
    combine_tabs();
    var loadingElm = document.getElementById(LOADING_ELM_ID);
    if(loadingElm){
      loadingElm.style.display = "none";
    }
    var contentHolderElm = document.getElementById(CONTENT_HOLDER_ID);
    if(contentHolderElm) {
      contentHolderElm.style.display = "block";
    }
    var selected = get_selected();
    show_section(selected);
    set_handlers();
    if(!navigator.userAgent.match(/Safari/)) setInterval(checkHash, 100);
  };

  onload = set_up
</script>
<style type="text/css">
  h2.tab span {
    margin-left: 9px;
    margin-right: 0px;
    padding: 1px 10px 0px 10px;
    border-left: 1px solid #ccc;
    border-top: 1px solid #ccc;
    border-right: 1px solid #ccc;
    cursor: pointer;
    /* Remove the following if you don't want rounded corners (Mozilla only). */
    -moz-border-radius: 7px 7px 0px 0px;
  }

  h2.tab span.not-selected {
    background-color: #eee;
    border-bottom: 1px solid #ccc;
    color: #999;
  }

  h2.tab span.selected {
    background-color: #fff;
    border-bottom: 1px solid #fff;
  }

  h2.tab {
    border-bottom: none;
    font-weight: bold;
    font-size: 100%;
    margin-bottom: 0px;
    font-style: normal;
  }

  div.section {
    border: 1px solid #ccc;
    padding: 15px 5px 5px 5px;
  }
</style>
</head>
<body>
  <h2 class="tab" id="tab1">Tab 1</h2>
  <div class="section">
    content for first tab
  </div>

  <h2 class="tab" id="tab2">Tab 2</h2>
  <div class="section">
    content for second tab
  </div>

  <!--
    You'll notice that each section heading has an "id" attribute.
    You'll also notice clicking on each tab changes part of the URL to
    the id of the tab you clicked. This allows the Back button to work
    in Mozilla-based browsers (an Internet Explorer bug prevents it
    from working), and for proper links directly to a specific tab.
    For example, #tab2 appended to the URL will cause the second
   tab to be selected when the page loads.
  -->
</body>
</html>