Creating a Dynamic Table of Contents for PHPKB

We use phpkb at work for an internal knowledge base and overall I'm pretty happy with it, it does pretty much everything that I wanted in a KB except for one or two things. One of those was to allow for a dynamic table of contents based on use of heading tags in your article, something that most wiki software does out of the box, as does MS Word, which is where much of the content we are migrating into phpkb lived before.
So I wrote a little bit of JavaScript to enable a dymanic TOC myself. It is easy to implement if you are using phpkb, here is how it looks and how to turn this on for article pages.
The TOC is inserted at the top of your article and indented based on heading use
You can cheat and just get the jscript file and my modded article.php in this zipped copy.
Step 1 - Modify article.php (back it up first..)
Paste these lines in that page right before the '$include_files' insertion.
<script type=\"text/javascript\" src=\"$path_kb/thesaurus/js/jquery1-7-1.js\"></script>
<script type=\"text/javascript\" src=\"$path_kb/include/toc.js\"></script>
Step 2 - Create a custom field called 'Show TOC' and make it a non-required checkbox with Yes,No options.
Step 3 - Drop the toc.js file into the include folder for your installation. Here is the source for that file so you can see what is going on.
$(document).ready(function(){ $('.customfields').find('li').each(function(i) { // Looks at custom fields on page to see if enabled var current = $(this); if(current.text() == 'Show TOC: Yes') { // Enabled, show table of contents $("#ARTICLECONTENT").prepend('<div id="toc"><b>Table of Contents</b></div>'); $("#toc").css('border','1px solid #eccf59'); $("#toc").css('background','#f1eddf'); $("#toc").css('margin','5px 0 0 0'); $("#toc").css('padding','5px 5px 15px 5px'); $("#toc").append("<ul>"); var iToc = 0; // to track if we find any headings $('article').children("h1, h2, h3, h4, h5").each(function(i) { iToc ++; var current = $(this); current.attr("id", "title" + i); var sp = ''; switch(current.prop("tagName")){ case 'H1': sp = '10px'; break; case 'H2': sp = '20px'; break; case 'H3': sp = '30px'; break; case 'H4': sp = '40px'; break; case 'H5': sp = '50px'; break; } if(current.html().trim()){ $("#toc").append("<li style='padding-left:" + sp + ";'><a id='link" + i + "' href='#title" + i + "' title='" + current.attr("tagName") + "'>" + current.html() + "</a></li>"); } }); $("#toc").append("</ul>"); if(iToc == 0) { $("#toc").hide(); } // if no content for TOC we just hide it } }); });
As you can see, with some very little changes you can repurpose this for other applications that use the same 'H tag' heading hierarchy that you commonly run into.






Reader Comments (2)
How did you achive this in newer versions? I trid this however the article.php looks verry different on my version to yours.
are you using a MYSQL version?
Good question... I am using version 7.5 with a MSFT SQL server behind it. Ideally the SQL back-end should not impact how this works but the article.php could have changed with newer versions to invalidate this approach. If the parent container referenced in line 12 above has changed in the underlying page structure then it would not be crawling the right container to look for heading tags. Does it throw a javascript error for you or just do nothing?