Enhance Wiki Page Layout by adding a navgational Table of Contents

The content of wiki pages can get sometimes longer than it should be. The normal content length of publishing page or wiki pages should have a length that shouldn’t be longer than one or two screen. In this case a table of content can be useful to enhance the navigation on a single wiki page and give a brief overview about the content.

Released a new version of this table of content as a jquery plugin take a look at : Revised: Table of Contents for Wiki Pages

Adding Table of Content to the wiki page layout

The addition of a table of content to a wiki page layout is easy and can be accomplished by some little modification the wiki page layout. In this case I copied the default enterprise wiki page layout and added a placeholder div to the page layout.

[code lang="html"]
<div class="ms-descriptiontext ewiki-margin">
<SharePoint:FormattedString FormatText="<%$Resources:wss,wikidiff_lastmodifiedby%>" runat="server">
                               <SharePoint:FormField id="modifiedFieldCtrl" ControlMode="Display" FieldName="Modified" runat="server"/>
                               <SharePoint:UserField id="editorFieldCtrl" ControlMode="Display" FieldName="Editor" runat="server"/>
                 </SharePoint:FormattedString>
                 <PublishingWebControls:EditPageHyperLink id="editPageLink" Text="<%$Resources:cms,enterwiki_editpage%>" runat="server"/>
</div>
<!-- Table of Contents -->
<div id="wiki-index">
                <div class="toc">Table of Contents</div>
</div>
<!-- Table of Contents -->
<PublishingWebControls:EditModePanel runat="server">
                <div class="ms-descriptiontext">
                               <b class="ewiki-pagename-align"><SharePoint:FieldLabel FieldName="FileLeafRef" runat="server"/></b>
                               <SharePoint:FileField id="PageNameInEditMode" CssClass="ewiki-pagename-align" FieldName="FileLeafRef" DisableInputFieldLabel="true" runat="server"/>
                </div>
</PublishingWebControls:EditModePanel>
<pre>[/code]

The div with the id ‘wiki-index’ in the code above will be used to display the table of contents. What now is need some little bit of JQuery magic and a style definition for the table of contents box. The JQuery script will now parse the page content for all <h2> headlines and adds a hyperlink to the wiki-index box. In a second step the bookmarks will be added to the headings. The code and the style sheet will look like this and needs to be added on the page layout to the content placeholder with the ID PlaceHolderAdditionalPageHead:
The script:

[code lang="javascript"]
$(document).ready(function(){
$(".ms-bodyareacell h2").each(function(){
            $("#wiki-index").append("<a href='#"+$(this).text()+"'>"+$(this).text()+"</a><br />");
            $(this).prepend("<a name='"+$(this).text()+"'></a>");
            })
        });
[/code]

The style for the table of contents:

[code lang="css"]
#wiki-index{
width: 250px;
border: 1px black dashed;
background-color: whitesmoke;
float: right;
margin-top: 60px;
margin-left: 10px;
padding: 10px;
padding-top: 0px;
}
#wiki-index .toc{
     font-size: 1.1em;
     font-weight: bold;
     text-align: center;
     padding: 5px;
}
[/code]

That’s all that needs to be done and the wiki page is enhanced with a nice table of content as seen below.

Table of Contents

Conclusion

Creating a table of contents for wiki pages can be accomplished easily with a simple JavaScript. This can enhance a lot of the usability of wiki pages. The author of a wiki page needs to do nothing than format the headlines the right way. Currently the script only covers a single level of headlines, but with some additional coding this can be accomplished too.

Download Enhanced Enterprise WIKI

17 comments

  1. Can i do an indented Table of content using this script? means that we an end user will mark a header with it will be indented in the table of content above.. ( just like in word)

    1. Yes you can but it requires a more advanced script than this. I first started to create an intended table of contents but the problem here was that in HTML you need first find the lowest level of headline, for example all “Heading 3″ and then find the parent “Heading 2″ and add the heading to the right node in the table of contents. This could be a little bit tricky. The reason why i choose only to support the “Heading 2″ is that the main headline should be formatted using “Heading 1″ and all sub headline will use “Heading 2″. This is common practice on web content management. In general most web pages will only need three level of headlines and by jumping between all “Heading 2″ is fairly a good start.

  2. Hello.

    I’ve downloaded and imported the template into master pages as a “Enterprise Wiki” content type.
    And changed the page layout of an existing Enterprise Wiki to the enhanced one.

    The TOC table comes up, but doesn’t parse the h1 headings.

    Would be awesome to get this to work, any ideas?

    1. Hi Tyb,
      in general it’s recommended to use the H1 Headlines only for the title of a page. If you which to get a table of content for the H1 instead of the H2 you simply need to edit the page template in notepad or any html editor you like.
      Then change the following code
      $(“.ms-bodyareacell h2″)
      to
      $(“.ms-bodyareacell h1″)

      You can use search and replace, save the file and upload it to SharePoint. Then the wiki page will render all H1 headlines instead of the H2 in the table of contents.
      Kind regards
      Stefan

  3. Oh, the text said h1, although the code uses h2.

    Anyhow, it still doesn’t parse the titles.

    Sorry for the noob question; but do I to fix something else other than ‘this’?

    What I’ve done at the moment is added your template as a page layout with Enterprise Wiki content type.

    Changed the page layout for an existing Enterprise Wiki, the TOC table comes up, empty though.

    Created a new Enterprise Wiki with the new page layout as default, same thing.

    Thanks in advance!

    1. Thanx for your hint on h1 and h2 confusion, i will change this in the content. Have you used the markup styles to define the headings?

      Do you have internet access if you try this on a server or have you tried it locally? Does your page run with SSL?
      I used JQuery from a CDN location on the internet.

      kind regards
      Stefan

  4. Hi I am having the same problem as the person above. I have added the page as a template and the ToC gets added but not populated, I used the markup styles for headers. HTML source of the content now looks like this
    h2 class=”ms-rteElement-H2″>​testetst
    nei dette går ikke bra
    vi prøver igjen
    test 

    I tried also to change the script to use $(“.ms-rteElement-H2″).each(function(){ instead of $(“.ms-bodyareacell h2″).each(function(){ but with no effect
    any ideas?

  5. Hello Stefan

    Based on a variation of your code I saw on another site, I re-wrote yours to make a version that can indent and scale the TOC entries.

    Here is the Script:
    [code language="css"]
    $(document).ready(function(){
    $(".ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4").each(function(i){
    $(this).attr("id", "title" + i);
    $("#wiki-index").append("<a href='#title" + i + "' title='" + $(this).attr("class") + "'>" + $(this).text() + "</a><br />");
    })
    });
    [/code]

    and here is the style:
    [code language="css"]
    #wiki-index {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
    #wiki-index .toc{font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wiki-index a[title=ms-rteElement-H2] {font-size:12px; font-weight: normal;}
    #wiki-index a[title=ms-rteElement-H3] {font-size:11px; font-weight: normal; margin-left: 5px;}
    #wiki-index a[title=ms-rteElement-H4] {font-size:10px; font-weight: normal; margin-left: 10px;}
    [/code]

  6. I need to have sub-headers in my table of contents, so for example in addition to selecting the “h2s” to populate in the TOC it will also get “h3s” and show those indented in order underneath each h2 (I think this is what Maor was asking for). This is a tricky problem but I have no idea how to script it yet, since nesting the h3 selection will loop around the entire page each time an h2 is found. Any idea how to workaround this puzzle?

  7. Hello Axel. The version I posted recently does indent the each of the headings like this:

    Heading 1
    Heading 2
    Heading 2
    Heading 3
    Heading 1

  8. Hello Axel and others.

    Here is an updated version of my code. It indents the headings based on the heading level and makes the text a little smaller for each level. I’ve also added a nice show / hide button to allow the user to collapse the TOC when needed (I made it look like the TOC of media wiki).

    [[code]]

    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';
    }

    Table of Contents
    [hide]
    [show]

    $(document).ready(function(){
    $(“.ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4″).each(function(i){
    $(this).attr(“id”, “title” + i);
    $(“#theTOC”).append(“” + $(this).text() + ““);
    })
    });
    showTOC();

    #wiki-TOC {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
    #wiki-TOC .TOCheader{font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wiki-TOC .closehide{font-size: 12px; font-weight: normal;}
    #wiki-TOC a[title=ms-rteElement-H2] {font-size:12px; font-weight: normal;}
    #wiki-TOC a[title=ms-rteElement-H3] {font-size:11px; font-weight: normal; margin-left: 5px;}
    #wiki-TOC a[title=ms-rteElement-H4] {font-size:10px; font-weight: normal; margin-left: 10px;}

    [[/code]]

  9. Hello Axel and others.

    Here is an updated version of my code. It indents the headings based on the heading level and makes the text a little smaller for each level. I’ve also added a nice show / hide button to allow the user to collapse the TOC when needed (I made it look like the TOC of media wiki).

    [code language="javascript"]
    <!-- Table of Contents -->
    <script type="text/javascript" src="/communities/cloud/SiteAssets/Scripts/jquery_172.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';
    }
    </script>
    <script type="text/javascript">
    function showTOC() {
    document.getElementById("theTOC").style.display = 'block';
    document.getElementById("show").style.display = 'none';
    document.getElementById("hide").style.display = 'block';
    }
    </script>

    <div id="wiki-TOC">
    <table style="padding: 5px;"><tr><td><div class="TOCheader">Table of Contents</div></td>
    <td><div class="closehide" id='hide'>[<a href='#' class='close_notification' title='Click to Close' onClick="hideTOC()">hide</a>]</div>
    <div class="closehide" id='show'>[<a href='#' class='close_notification' title='Click to Close' onClick="showTOC()">show</a>]</div>
    </td></tr></table>
    <div id='theTOC'>
    <script type="text/javascript">
    $(document).ready(function(){
    $(".ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4").each(function(i){
    $(this).attr("id", "title" + i);
    $("#theTOC").append("<a href='#title" + i + "' title='" + $(this).attr("class") + "'>" + $(this).text() + "</a><br />");
    })
    });
    showTOC();
    </script>
    </div>
    </div>

    <style>
    #wiki-TOC {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
    #wiki-TOC .TOCheader{font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wiki-TOC .closehide{font-size: 12px; font-weight: normal;}
    #wiki-TOC a[title=ms-rteElement-H2] {font-size:12px; font-weight: normal;}
    #wiki-TOC a[title=ms-rteElement-H3] {font-size:11px; font-weight: normal; margin-left: 5px;}
    #wiki-TOC a[title=ms-rteElement-H4] {font-size:10px; font-weight: normal; margin-left: 10px;}
    </style>
    [/code]

  10. Hello,

    has anyone tried this on Sharepoint 2013? The problem is that TOC displayed perfectly for all the users, except for the Visitor group users, the javascript is not called for these users. Any Idea?

    1. Since Internet Explorer 9.0 you can directly trace the traffic to a web site. If you press F12 the Developer Toolbar fires up and you will find a network tab. After you started the trace you should look for error in the network trace or in the console. You can also take a look if the code will be displayed for the visitors.

  11. Hi

    I am relatively new to sharepiont and I am trying to build a page onto a page I created in our Sharepoint website. i am unable to build a table of content though for that page.

    how can i incorporate the above onto my page??

    1. What version are you on? I created this solution for a SharePoint 2010 Enterprise WIKI. You can download the template from the link above and add it to your page layouts.
      You will find more about page layouts and master pages in the Microsoft MSDN Dokumentation.

      /Stefan

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">