Advertisement
robertmarkbram

Javascript Table of Contents

Jul 5th, 2015
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.    Create a Table of Contents
  3.    --------------------------
  4.    Author: Robert Mark Bram
  5.       robertmarkbram@gmail.com
  6.    Created: Sunday, 5th of July 2015, 11:05:22 PM
  7.  
  8.    How to use
  9.    --------------------------
  10.    1. Write HTML!
  11.       Documents should only ever have one H1, but as many H2, H3, H4 etc as you need.
  12.          <h1>Heading 1 - there should only be one</h1>
  13.          <h2>Give me fish sniff tail flick stuck</h2>
  14.          <p>Text.</p>
  15.          <h3>Judging you toss the mousie run</h3>
  16.          <p>Text.</p>
  17.          <h4>Stumptown sartorial vinyl four dollar toast</h4>
  18.          <p>Text.</p>
  19.  
  20.    2. Import jQuery and this API.
  21.          <script type="text/javascript" src="/js/jquery-1.11.3.min.js"></script>
  22.          <script type="text/javascript" src="/js/tableOfContents.js"></script>
  23.  
  24.    3. Create a script to create the TOC.
  25.          <script type="text/javascript">
  26.             $(function() {
  27.                new TableOfContents().create();
  28.             });
  29.          </script>
  30.  
  31.    4. Style the "to the top" links [optional].
  32.          <style>
  33.             .toTop{
  34.                background-color: #CAFFCA;
  35.                text-align: right;
  36.             }
  37.             .toTopSub{
  38.                background-color: #FFAAAA;
  39.                text-align: right;
  40.             }
  41.          </style>
  42.  
  43.    Options you can control
  44.    --------------------------
  45.    Options can can be specified by including an object overriding selected
  46.    properties. For example:
  47.          new TableOfContents({
  48.             style2: 'A',
  49.             style3: 'I',
  50.             style4: '1',
  51.          }).create();
  52.  
  53.    List of all options is below.
  54.          containerId = "main";
  55.             Only look for headers contained within the element with this ID.
  56.  
  57.          style2: '1',  // h2
  58.          style3: 'a',  // h3
  59.          style4: 'i',  // h4
  60.             Control what kind of marker to use in the numbered list for the
  61.             corresponding header level. In the example above, all H2 elements
  62.             will be a in a list numbered 1, 2, 3 etc. and H3 elements will be in
  63.             a list of a, b, c etc. Example:
  64.                1 first header for h2
  65.                   a first header for h3
  66.                   b first header for h3
  67.                   c first header for h3
  68.                2 second header for h2
  69.                3 third header for h2
  70.             Styles for H1 are not included, because the H1 is a header for the
  71.             whole page and will not be included in the TOC. To see more about
  72.             what types you can use, see:
  73.                http://www.w3schools.com/tags/att_ol_type.asp
  74.             You can keep adding style2, style3 etc to cover whatever headings
  75.             you need.
  76.  
  77.          outputTopLink: true,
  78.             True/false: whether or not to output "to top" links above each
  79.             heading and add "top" ID to H1.
  80.  
  81.          topId: "top",
  82.             ID of the element that all "to top" links should go to. By default,
  83.             this will be added to the first H1 (there should only be one).
  84.  
  85.          bottomId: "bottom",
  86.             ID of the element that the final "to top" link should be added
  87.             BEFORE.
  88.  
  89.          toTopClass2: "toTop",
  90.          toTopClass3: "toTopSub",
  91.             Class that will be added to the P element that contains a "to top"
  92.             link under the menu and each heading. Styles correspond to the
  93.             heading level so that we can have sub-headings. Empty or null means
  94.             not to output "to top" links at this level.
  95.  
  96.    Examples
  97.    --------------------------
  98.    1. Example showing how to override all of the options.
  99.          http://jsfiddle.net/robertmarkbram/29wb1v3p/
  100.          http://www.chihuahuarescuevictoria.org/tech-examples/toc/toc_1.html
  101.  
  102.    2. Simplest example not overriding any options.
  103.          http://jsfiddle.net/robertmarkbram/gjxrvbjy/
  104.          http://www.chihuahuarescuevictoria.org/tech-examples/toc/toc_2.html
  105.  
  106. */
  107. function TableOfContents(properties) {
  108.  
  109.    // Reference to this in current scope.
  110.    var self = this;
  111.  
  112.    // Only look for headers contained in this ID.
  113.    this.containerId = "";
  114.  
  115.    // Styles for ordered lists corresponding to header level.
  116.    // Should only be one H1, and not included in TOC.
  117.    this.style2 = '1';  // 2
  118.    this.style3 = 'a';  // 3
  119.    this.style4 = 'i';  // 4
  120.  
  121.    // True/false: output "to top" link and add "top" ID to H1.
  122.    this.outputTopLink = true;
  123.  
  124.    // ID of the element that all "to top" links should go to.
  125.    this.topId = "top";
  126.  
  127.    // ID of the element that the final "to top" link should go BEFORE.
  128.    this.bottomId = "bottom";
  129.  
  130.    // Class of the P element that contains a "to top" link under the menu.
  131.    // Styles correspond to the heading level so that we can have sub-headings.
  132.    // Empty or null means not to output "to top" links at this level.
  133.    this.toTopClass2 = "toTop";
  134.    this.toTopClass3 = "toTopSub";
  135.  
  136.    /* Create table of contents. */
  137.    this.create = function() {
  138.       // Work out container of all headings.
  139.       var $container = null;
  140.       if (self.containerId) {
  141.          $container = $("#" + self.containerId);
  142.       } else {
  143.          $container = $("body");
  144.       }
  145.  
  146.       // Add id to first H1 and put menu after it (or after menuPre if present).
  147.       var $pageTitle = $($container.find("h1")[0]);
  148.       var $menuPre = $("#menuPre");
  149.       var $menu = $('<ol id="menu" type="' + self.style2 + '"></ol>');
  150.       if ($menuPre.length > 0) {
  151.          $menuPre.after($menu);
  152.       } else if ($pageTitle.length > 0) {
  153.          $pageTitle.after($menu);
  154.       } else {
  155.          $container.prepend($menu);
  156.       }
  157.  
  158.       // Add top ID and links to it.
  159.       if (self.outputTopLink) {
  160.          // Add "top" ID to H1.
  161.          $pageTitle.attr('id', self.topId);
  162.       }
  163.  
  164.       // We need to track set of sub-menus by heading level.
  165.       var menus = new Array();
  166.       menus[2] = $menu;
  167.       var $subMenu = $menu;
  168.       var headingLevel = 2;
  169.       var headingLevelPrevious = 2;
  170.  
  171.       // Populate menu with all header elements. But skip first.
  172.       $container.find("h2, h3, h4, h5").each(function( index ) {
  173.          var $heading = $(this);
  174.          headingLevelPrevious = headingLevel;
  175.          headingLevel = $heading.prop("tagName").substring(1);
  176.  
  177.          // If the heading doesn't have an ID, give it one.
  178.          if (!$heading.attr('id')) {
  179.             $heading.attr('id', $heading.text().replace(/[^0-9a-zA-Z]/g, ""));
  180.          }
  181.          // Create and store new sub-menu if current header is deeper than previous.
  182.          var listType = null;
  183.          if (headingLevel > headingLevelPrevious) {
  184.             $subMenu = $('<ol type="'
  185.                   + $(self).prop("style" + headingLevel) + '"></ol>');
  186.             menus[headingLevel] = $subMenu;
  187.             menus[headingLevelPrevious].append($subMenu);
  188.          }
  189.          // But if we are going back up the chain, get the correct submenu.
  190.          if (headingLevel < headingLevelPrevious) {
  191.             $subMenu = menus[headingLevel];
  192.          }
  193.  
  194.          // And menu element pointing to the heading.
  195.          $subMenu.append('<li><a href="#' + $(this).attr('id') + '">'
  196.                + $(this).text() + '</a></li>');
  197.  
  198.          // If we output to top links and if class is set for that level.
  199.          if (self.outputTopLink) {
  200.             var className = $(self).prop("toTopClass" + headingLevel);
  201.  
  202.             // Add "to top" link above every heading.
  203.             if (className) {
  204.                $heading.before('<p class="' + className + '"><a href="#'
  205.                      + self.topId + '">Top</a></p>');
  206.             }
  207.          }
  208.       });
  209.       // If we output to top links and if class is set for that level.
  210.       if (self.outputTopLink) {
  211.          var className = $(self).prop("toTopClass2");
  212.  
  213.          // Add final "to top" link.
  214.          if (className) {
  215.             var $bottom = $("#" + self.bottomId);
  216.             if ($bottom.length > 0) {
  217.                $("#" + self.bottomId).before('<p class="' + className + '"><a href="#'
  218.                         + self.topId + '">Top</a></p>');
  219.             } else {
  220.                $("body").append('<p class="' + className + '"><a href="#'
  221.                         + self.topId + '">Top</a></p>');
  222.             }
  223.          }
  224.       }
  225.  
  226.    };
  227.  
  228.    // Override properties of this object with supplied properties.
  229.    $.extend(this, properties);
  230.  
  231. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement