Advertisement
robertmarkbram

Javascript Table of Contents

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