Create a Table of Contents automatically



Data ultimo post: 18 ago 2016

Much like the author of this article, our company needs a way to automatically generate a table of contents for large articles. After finding out we can use jQuery, I put together a script that will automagically create a tiered table of contents based on the Header tags used in the article.

All you need to do is paste the Javascript in this page into the Javascript section of your Articles:

 

Click on the JS tab, then paste in the code at the end:

 

That should do it.. as long as you've used proper heading tags (H1, H2, etc), a Table of Contents will be created any time you load the article.

You can see a live example here: http://codepen.io/ngalluzzo/pen/kXqyVQ?editors=1010


3

55

55 commenti

@Michael H

 

You want to put it in the article_page.hbs file, not script.js

0


Am I missing something with implementing this code?

Reading the thread, and taking the last post from @Tim, I understand the totality of the implementation path being this:

  1. In Guide, go to /theming/workbench
  2. Select your theme, and press view theme.
  3. press Edit code.
  4. Edit script.js, and add the code to the end of the file. Save changes.

And that's it - it should display right?

Having followed these steps on my Guide instance, running the Copenhagen theme, I don't get anything let alone the change i'm expected.

Here's a page from my Guide instance which I would hope gets this auto TOC:
https://help.wafresh.com.au/hc/en-au/articles/360007488692-What-happens-if-an-item-is-out-of-stock-or-unavailable-

Appreciate any help or feedback to understand where I'm going wrong.

0


Hey all,

 

Just an FYI this line:

var $anchorname = $heading[0].outerText.replace (/\s/g,'');

should be changed to:

var $anchorname = $heading[0].innerText.replace (/\s/g,'');

This will make it work on Firefox browsers.

 

<script>
/* ============================================================================================== */
/* ============================== Custom Article Table of Contents ============================== */
/* ============================================================================================== */

var $headers = $('.article-body:first h1');

if ($headers.length == 0) $headers = $('.article-body:first h2');

if ($headers.length > 0) {
var $toc = $('<div class="toc" style="margin-bottom: 25px">');
var $firstUl = $('<ul>');
var $currentUl = $firstUl;
var previous_level = 1;
var $arrayUl = [];


$firstUl.appendTo($toc);
$('#table-of-contents').length > 0 ? $toc.appendTo('#table-of-contents') : $toc.prependTo('.article-body:first');

// start with first H1
insertHeading($headers[0]);
}

function insertHeading(heading) {
var $heading = $(heading);
// what level heading are we on?
var current_level = headingLevel(heading);


// if it's an H1, add it to the original list
if (current_level === 1) {
newLi($heading, $firstUl);
$currentUl = $firstUl;
$arrayUl = [];
$arrayUl.push($firstUl);
}

// if it's the same as the one before it, add it to the current list
else if (current_level === previous_level) {
newLi($heading, $currentUl);
}

// if it's one level higher than the one before it... time to make a new nested list
else if (current_level > previous_level) {
nestUl();
$arrayUl.push($currentUl);
newLi($heading, $currentUl);
}

else if (current_level<previous_level){
for (i = 0; i < (previous_level-current_level); i++) {
$arrayUl.pop();
}
$currentUl = $arrayUl[$arrayUl.length-1];
newLi($heading, $currentUl);
}

previous_level = current_level;

var $nextHeading = $heading.nextAll("h1, h2, h3, h4, h5, h6").first()[0];
// if there's any headings left... run this again
if ($nextHeading) insertHeading($nextHeading);
}

// adds a new UL to the current UL
function nestUl() {
var $newUl = $('<ul>');
$newUl.appendTo($currentUl);
$currentUl = $newUl;
}

// returns a numerical value for each heading
function headingLevel(heading) {
switch (heading.nodeName) {
case 'H1':
return 1;
break;
case 'H2':
return 2;
break;
case 'H3':
return 3;
break;
case 'H4':
return 4;
break;
case 'H5':
return 5;
break;
case 'H6':
return 6;
break;
default:
return 0;
}
}

// inserts a new line to the current list
function newLi(heading, $list) {
var $heading = $(heading);
if ($heading.text().replace(/\s/g, '') == '') return null;
var $wrapper = $('<li></li>');
//var $link = $('<a>').prop('href', '#' + $heading.prop('id'));
var $anchorname = $heading[0].innerText.replace (/\s/g,'');
var $link = $('<a>').prop('href', '#' + $anchorname);

$link.html($heading.text());
$link.appendTo($wrapper);

$wrapper.appendTo($list);

var place_in_parent = $list.children('li').length;

$heading.html("<a name=\"" + $anchorname + "\"></a>" + $link.find('.index').text() + ' ' + $heading.text());
}
</script>

0


Vladan, thank you very much for sharing. I've incorporated the code into the article_page.hbs template of our HC and it works great. I had played around a bit with the JS version but couldn't get it to run properly (could be due to a highly customized HC with category accordians, etc). 

Thanks again for a fantastic ToC solution!

0


Hey Iris, glad to hear it works!

Yes, it is doable to have it on the right or left side but that requires some design/CSS changes in the layout.

If you have someone in your team familiar with CSS he/she can do that for sure.

0


Thank you Vladan for the code! 

This is the first TOC code I found on the platform that actually worked! Quick question, is it possible to have it appear on the right side of the article?  

 

Thanks!

0


This script hyperlinks to the header name, which means that if I cross-link from article A to a subsection in article B, if that header name is ever updated the cross-link breaks.

Is it possible to hyperlink to the header ID instead? For example:

Header Name hyperlink:

...hc/en-us/articles/360000297868#ConfigureTrustedSender

Header ID hyperlink:

...hc/en-us/articles/360000297868#h_97516510121537301054444

FWIW, you can find the header ID while editing an article - in Article A, select text, insert link, choose a header in the dropdown, then look at the URL. I was using this method to manually create Tables of Content, which I could then refer to when creating a cross-link from another article to the subsection (just copy the URL). 

0


Thanks for the feedback! Let us know if any further help needed ;)

0


Hi Vladan,

This worked! Thank you for your help :-)

0


Thanks for the quick reply! I see an error in your JS file.

Could you please try to add the following code at the end of your Article page template? This will create a TOC like on this screenshot https://cl.ly/syw3

<script>
/* ============================================================================================== */ /* ============================== Custom Article Table of Contents ============================== */ /* ============================================================================================== */ var $headers = $('.article-body:first h1'); if ($headers.length == 0) $headers = $('.article-body:first h2'); if ($headers.length > 0) { var $toc = $('<div class="toc" style="margin-bottom: 25px">'); var $firstUl = $('<ul>'); var $currentUl = $firstUl; var previous_level = 1; var $arrayUl = []; $firstUl.appendTo($toc); $('#table-of-contents').length > 0 ? $toc.appendTo('#table-of-contents') : $toc.prependTo('.article-body:first'); // start with first H1 insertHeading($headers[0]); } function insertHeading(heading) { var $heading = $(heading); // what level heading are we on? var current_level = headingLevel(heading); // if it's an H1, add it to the original list if (current_level === 1) { newLi($heading, $firstUl); $currentUl = $firstUl; $arrayUl = []; $arrayUl.push($firstUl); } // if it's the same as the one before it, add it to the current list else if (current_level === previous_level) { newLi($heading, $currentUl); } // if it's one level higher than the one before it... time to make a new nested list else if (current_level > previous_level) { nestUl(); $arrayUl.push($currentUl); newLi($heading, $currentUl); } else if (current_level<previous_level){ for (i = 0; i < (previous_level-current_level); i++) { $arrayUl.pop(); } $currentUl = $arrayUl[$arrayUl.length-1]; newLi($heading, $currentUl); } previous_level = current_level; var $nextHeading = $heading.nextAll("h1, h2, h3, h4, h5, h6").first()[0]; // if there's any headings left... run this again if ($nextHeading) insertHeading($nextHeading); } // adds a new UL to the current UL function nestUl() { var $newUl = $('<ul>'); $newUl.appendTo($currentUl); $currentUl = $newUl; } // returns a numerical value for each heading function headingLevel(heading) { switch (heading.nodeName) { case 'H1': return 1; break; case 'H2': return 2; break; case 'H3': return 3; break; case 'H4': return 4; break; case 'H5': return 5; break; case 'H6': return 6; break; default: return 0; } } // inserts a new line to the current list function newLi(heading, $list) { var $heading = $(heading); if ($heading.text().replace(/\s/g, '') == '') return null; var $wrapper = $('<li></li>'); //var $link = $('<a>').prop('href', '#' + $heading.prop('id')); var $anchorname = $heading[0].outerText.replace (/\s/g,''); var $link = $('<a>').prop('href', '#' + $anchorname); $link.html($heading.text()); $link.appendTo($wrapper); $wrapper.appendTo($list); var place_in_parent = $list.children('li').length; $heading.html("<a name=\"" + $anchorname + "\"></a>" + $link.find('.index').text() + ' ' + $heading.text()); }
</script>

0


Accedi per lasciare un commento.

CONTENUTI AGGIUNTIVI

Ulteriori informazioni

Non hai trovato quello che cerchi?

Nuovo post