Table of Content for SharePoint Pages - using Javascript and Jquery - Fabian Neve

About SharePoint, Javascript, PowerShell, and other technical stuff

Thursday, October 5, 2017

Table of Content for SharePoint Pages - using Javascript and Jquery

Note: We are not talking about the Table Of Contents Web Part here. We are talking about a table of page content, a table which get's all the headings of a single page and generates a Table of Content.

Generally we use Javascript and Jquery for this approach.

Part 1: A simple Table of Content for Article Pages


You can use following code for Article Pages, Publishing Pages, etc. 

1. Create a HTML file with this content

Paste this code into a file named TableOfContent.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<script type="text/javascript" src="//code.jquery.com/jquery-1.11.0.min.js"></script>

<script type="text/javascript">
 function hideTOC() {
  document.getElementById("theTOC").style.display = 'none';
  document.getElementById("show").style.display = 'block';
  document.getElementById("hide").style.display = 'none';
 }

 function showTOC() {
   document.getElementById("theTOC").style.display = 'block';
   document.getElementById("show").style.display = 'none';
   document.getElementById("hide").style.display = 'block';

 }
</script>

<div id="wikiTOC">
 <table style="padding: 5px;">
  <tr>
   <td><div class="TOCheader">Table of Content</div></td>
   <td>
    <div class="closehide" id='hide'>[<a href='#' title='Click to hide' onClick="hideTOC()">Hide</a>]</div>
    <div class="closehide" id='show'>[<a href='#' title='Click to show' onClick="showTOC()">Show</a>]</div>
   </td>
  </tr>
 </table>

 <div id='theTOC'>

  <script type="text/javascript"> 

   $(document).ready(function(){
    var L1=0, L2=0, L3=0, L4=0;
    $(".ms-rtestate-field > h1, .ms-wikicontent h1, .ms-rtestate-field > h2, .ms-wikicontent h2, .ms-rtestate-field > h3, .ms-wikicontent h3, .ms-rtestate-field > h4, .ms-wikicontent h4").each(function(i){
     theLevel=$(this).get(0).tagName;
     if (theLevel=="H1") {
        L1=L1+1;
        L2=0;
        L3=0;
        L4=0;
        theLevelString=""+L1;
     }
     else if (theLevel=="H2") {
      L2=L2+1;
      L3=0;
      L4=0;
      theLevelString=""+L1+"."+L2;
     }
     else if (theLevel=="H3") {
      L3=L3+1;
      L4=0;
      theLevelString=""+L1+"."+L2+"."+L3;
     }
     else {
      L4=L4+1;
      theLevelString=""+L1+"."+L2+"."+L3+"."+L4;
     }

     $encAnchor = $(this).text().trim();
     $encAnchor = $encAnchor.replace(/\s/g, "_");
     $encAnchor = encodeURIComponent($encAnchor);
     $encAnchor = $encAnchor.replace(/%/g, "");


     $(this).attr("id", $encAnchor );
     $("#theTOC").append("<a href='#" + $encAnchor + "' class='wikiTOC-" + theLevel + "'>" + theLevelString + " " + $(this).text() + "</a><br />");
    });
   });

   showTOC();
  </script>
 </div>
</div>


<style type="text/css">
 #wikiTOC {border: 1px black solid; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
 #wikiTOC .TOCheader {font-size: 14px; font-weight: bold; text-align: center; padding: 5px;}
 #wikiTOC .closehide {font-size: 11px; font-weight: normal;}
 #wikiTOC a.wikiTOC-H1 {font-size:14px; font-weight: normal; }
 #wikiTOC a.wikiTOC-H2 {font-size:14px; font-weight: normal; margin-left:10px; }
 #wikiTOC a.wikiTOC-H3  {font-size:14px; font-weight: normal; margin-left: 20px; margin-bottom:3px;}
 #wikiTOC a.wikiTOC-H4  {font-size:14px; font-weight: normal; margin-left: 28px; margin-bottom:3px;}
</style>

2. Copy this file to the Site Assets Library

3. Create your article page and insert the code

Herefore, insert a Content Editor Webpart and point the "Content Link" to your newly created html code file.
Set "Chrome Type" to None.

Save the page - Done!

Found at http://blog.orbit.de/2014/08/19/dynamisches-inhaltsverzeichnis-fuer-sharepoint-2013-wiki-seiten/ (German Site)

Part 2: Table of Content in your Enterprise Wiki Page

This is a more complicated approach. In Enterprise Wiki Pages you have this Basic Page Layout with a sidebar which shows you page rating and categories. With following solution, you'll be able to place a Table of Content inside this sidebar.


This solution makes use of 4 files (+ Jquery).

1. CSS File "sp.tableOfContents.css"

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.tocMain {
 border-bottom: 1px #333 dashed;
}
.tocMain a:active {
}
.tocMain a:hover {
}
.tocMain a:visited {
 color: #0072c6; 
}
.tocMain.no-bullets {
 padding: 0px;
 padding-bottom: 1em;
 list-style-type: none; 
}
.tocMain.no-bullets ul {
 padding-left: 20px; 
}
.tocMain.no-bullets li {
 list-style-type: none;
 padding: 0.25em 0em; 
}

#s4-workspace.scroll .right-wp-zone-col {
  position: fixed;
  top: 70px;
  margin-right: 17px;
}

.right-wp-zone-col
{
float:right;
width:215px;
border-left:1px dashed;
position: absolute;
right:0;
padding-right: 25px;
}

2. JavaScript File with additional configurations (scroll then stick on top)


// Author: Fabian Neve / http://fneve.blogspot.ch/
// Date: 18.09.2017
// With input from https://blog.sharepointexperience.com/2014/10/sticky-stuff-in-sharepoint/
// 
// Top alignment of ToC has to be defined in sp.tableOfContents.css under #s4-workspace.scroll .right-wp-zone-col

var wrap = $("#s4-workspace");

wrap.on("scroll", function(e) {

if (this.scrollTop > 116 ) {
 wrap.addClass("scroll");
 } else {
 wrap.removeClass("scroll");
 } 
});

3. Javascript File "sp.tableOfContents.js" which contains the magic

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
"use strict";

(function($){
 $.fn.tocMenu = function(options)
 {
  // Helpder Methodes
  String.prototype.repeat = function( num )
  {
   return new Array( num + 1 ).join( this );
  };

  // Default settings
  var defaults = {
   orderedlist : true,
   customStyle : "no-bullets",
   attachTo : ".ewiki-slink",
   prepend : true,
   headlineText : "Table of Content",
   maxLevel : 6
  };
  
  // check if settings exist
  var settings = $.extend( {}, defaults, options );

  var tocElements = "";
  this.filter(
   function(){
    
    var listTag = "ol";
    if($("#MSOLayout_InDesignMode") !== null && $("#MSOLayout_InDesignMode").val()){
     return;
    }
    if(!settings.orderedlist){
    
     listTag = "ul";
    
    }
    // Search for filter
    var headers = $(":header", $(this));

    // Just in case no headers have been found
    if(headers.length === 0){
     return;
    }

    // define previous tag name used for loop and indention
    var prevTagName = null;

    // check if header should be set
    if(settings.headlineText !== null){
     tocElements += "<b>"+settings.headlineText+"</b>";
    }

    // initalize element of toc
    if(settings.customStyle !== null){
     tocElements += "<"+listTag+" class='tocMain "+settings.customStyle+"'>";
    } else {
     tocElements += "<"+listTag+" class='tocMain'>";
    }

    // Defiend level of indention to create perfect unorder list
    var lvlCounter = 0;

    // Loop through headline
    for(var i = 0; i < headers.length; i++){

     var nameLink = "<a name='chapter"+i+"' />";
     var tmpHeader = $(headers[i]).prepend(nameLink);
     
     if(prevTagName !== null && tmpHeader.prop('tagName') < prevTagName){
      tocElements += ("</"+listTag+">").repeat(lvlCounter);
      lvlCounter -= 1;
     } else if(prevTagName !== null && tmpHeader.prop('tagName') > prevTagName){
      tocElements += "<"+listTag+">";
      lvlCounter += 1;
     }

     tocElements += "<li><a href='#chapter"+i+"'>"+tmpHeader.text()+"</a></li>\n";
     
     prevTagName = tmpHeader.prop('tagName');
    }
   }
  );
  if(settings.prepend){
   $(settings.attachTo).prepend(tocElements);
  } else {
   $(settings.attachTo).append(tocElements);
  }
 };
})(jQuery);


    var wrap = $("#s4-workspace");
 
    wrap.on("scroll", function(e) {
 
      if (this.scrollTop > 130 ) {
        wrap.addClass("scroll");
      } else {
        wrap.removeClass("scroll");
      }
 
    });

4. Javascript File "TableOfContents.conf.js" with some additional configurations

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$(document).ready(function() {
    // Change this options to your need
    var options = {
        orderedlist: false,
        customStyle : "no-bullets",
        prepend : true
    };
    
    // Initialize table of contents for the rich text editor
    $(".ms-rtestate-field").tocMenu(options);
});


5. References to those files

Now you have two possibilities.

A) You save those files in the Site Asset Library and insert following references with a code snippet/script editor into your Enterprise Wiki Page:


<link href="/Style Library/TableOfContents/sp.tableOfContents.css" type="text/css" rel="stylesheet">
<script src="/Style Library/TableOfContents/jquery.min.js" type="text/javascript"></script>
<script src="/Style Library/TableOfContents/sp.tableOfContents.js" type="text/javascript"></script>
<script src="/Style Library/TableOfContents/TableOfContents.conf.js" type="text/javascript"></script>

or:

B) You create a new Page Layout which contains those references.

For more instructions regarding this method, please refer to the original blog post written by Stefan Bauer some years ago: Table of Contents for SharePoint Wiki Pages

Many thanks to him for this great solution! --> www.n8d.at

I zipped all files, you can get it here: Download TableOfContent.zip