Sorting TOCs in an Output with JavaScript

Having discussed sorting TOCs in a project before a build, let’s look at sorting a TOC in an HTML5 target output with JavaScript.

I’m using Google Chrome to test the JavaScript on the online help files for MadCap Flare version 8. Please note that I am using Flare online help because it is a recognizable, high quality HTML5 output. I don’t work for MadCap Software or have any involvement with that help file.

In the screen shot, notice the unordered list for the TOC is being inspected with the developer tools in Chrome. To bring up these tools, right-click somewhere on a page displayed in Chrome and select Inspect element.

TOC tree in Google Chrome
TOC tree in Google Chrome

The unordered list has a class value of “tree” (ul.tree). The children are list items (li) and the class varies depending on the state of the node and the position in the tree. For example, the skin changes the class value when the node is selected. In the next image, the Welcome topic is selected. Notice the value is:

tree-node tree-node-leaf tree-node-selected

TOC tree node in Google Chrome
TOC tree node in Google Chrome

For this post, only the top nodes will be sorted. To test getting those, JavaScript can be executed from the Console which is the option on the far right of the developer tools. This will retrieve the child nodes of the first ul.tree element on the page:

document.getElementsByClassName("tree")[0].childNodes

In the next screen shot, this has been executed.

child nodes of TOC tree retrieved with JavaScript
Child nodes of TOC tree retrieved with JavaScript

The result can be assigned to an array and sorted. Once sorted, the content of the list items can be replaced with the sorted content. But the class for the li elements must also be changed. Not only does that class change dynamically when you select the entry but the class varies depending on placement in the tree. To be safe, the class name should also convey.

Rather than multidimensional arrays, JavaScript allows for arrays of objects or arrays of arrays. To keep the class value and the inner HTML together, an array of objects can be used. The sort will be performed on the text of the label. The label text appears as the third descendant of the list item. But there is no other text so it can be taken from the list item itself. Here is a good discussion on Stack Overflow: http://stackoverflow.com/questions/2808926/javascript-multidimensional-arrays.

For basics about JavaScript arrays: w3schools.com JavaScript Array Object tutorial

Since the sort is to be performed on an array of objects, a sort function must be specified. This is a good explanation: http://www.javascriptkit.com/javatutors/arraysort2.shtml. In addition to placing the inner HTML and the class for the node in an array, the label text from the inner HTML is pulled as as a separate piece. The sort is based on the label text. This makes it easier to identify. Otherwise the script would have to drill in to the inner HTML for each node during the sort.

Here is the the code:

var topNodes = document.getElementsByClassName("tree")[0].childNodes;
var nodeHtmlAndClasses = [];

for (var i = 0, l = topNodes.length; i < l; i++) {
    var nodeHtmlAndClass = { iH: topNodes[i].innerHTML, cN: topNodes[i].className, lbl: topNodes[i].textContent };
    nodeHtmlAndClasses.push(nodeHtmlAndClass);
}

nodeHtmlAndClasses.sort(function (a, b) {
    var labelA = a.lbl.toLowerCase(), labelB = b.lbl.toLowerCase()
    if (labelA < labelB)
        return -1
    if (labelA > labelB)
        return 1
    return 0
});

for (var i = 0, l = topNodes.length; i < l; i++) {
    topNodes[i].innerHTML = nodeHtmlAndClasses[i]["iH"];
    topNodes[i].className = nodeHtmlAndClasses[i]["cN"];
}

To test, you can open an HTML5 output and execute the copied code from the developer tools in a browser. Here is the TOC before:

TOC before sorting with a JavaScript
TOC before sorting with a JavaScript

And here is the TOC in alphabetical order after executing the JavaScript:

TOC after sorting with a JavaScript
TOC after sorting with a JavaScript

What next?

You can add this script to a function and configure a toolbar button to execute it when clicked. MadCap Software has recently posted instructions about how to do that:

Adding Custom Buttons to HTML5 (and WebHelp) Outputs

It would also be nice to script the return to the original order or to script flattening or sorting at each level as was described in the previous post. But I’ll end this post with an appeal for comments about what kinds of sorting would be useful in Flare HTML5 outputs. The spam system on this blog has been changed. If you don’t see you comment published, please email info@tregner.com so I can track your comment down.

1 comment

  1. Hi
    I have a html output made up of several topics.
    If I ‘print’ from the output, it only prints the current topic.
    Is there a way to add either in the header/menu OR in the content itself (in the masterpage) a print button that will print the entire contents (ie all the topics in the TOC)….

Leave a comment

Your email address will not be published.

HTML tags are not allowed.

251,142 Spambots Blocked by Simple Comments