Improvements to HTML table of contents

Topics: Developer Forum
Jan 31, 2012 at 12:03 AM


I would like to suggest a few improvements for the web (HTML) help format :

  1. Synchronize the TOC automatically when the location changes in the IFRAME
  2. Provide an easy way to copy the direct link to a topic (using "?topic=...")
  3. Generate a PHP version of the index to make search available on non-Windows servers

I managed to implement features 1 and 2 in TOC.js :

  • add these two functions:
function AppendDirectLink()
    var a = document.createElement("A");
    a.href = "#";
    a.title = "Click to obtain a direct link to this topic";
    var text = document.createTextNode("Direct link...");
    a.setAttribute("style", "float: right");
    a.onclick = ShowDirectLink;

function ShowDirectLink()
    var url = GetCurrentUrl();
    var base = window.location.href;
    if (base.indexOf("?") > 0)
        base = base.substr(0, base.indexOf("?") + 1);
    base = base.substr(0, base.lastIndexOf("/") + 1);
    var relative = url.substr(base.length);
    prompt("Direct link", base + "?topic=" + relative);
  • add these lines after the call to SyncTOC in the Initialize function:
    topicContent.onload = SyncTOC;

These changes work in Firefox 9, Chrome 16 and IE 9 (you can test them here)

Obviously, this is just a proof of concept, and there is room for improvement:

  • the link could be added directly in the HTML rather than in JS (I did it this way so I didn't have to edit the generated HTML file manually after each build)
  • the prompt box is an quick and dirty way to provide a copyable link, it needs to be replaced with something nicer
  • the link text and tooltip need to be localizable


Do you think these changes could be included in a future release?

Jan 31, 2012 at 12:16 AM


Thanks for the updates.  I will merge them into a future version of SHFB.  With regard to a PHP version, I know nothing about PHP so unless somebody else tackles it, that unfortunately won't happen.  I do have some Perl scripts somebody sent me but I haven't had time to merge them in yet or test them.  Again, Perl isn't something I know so it's been low on the list of things to do.  If you know anything about Perl, I can send them to you if you like.



Jan 31, 2012 at 7:57 AM

I'm not a PHP expert either, but the ASP.NET code seems fairly simple... I guess it shouldn't be too hard to translate it to PHP. I'll give it a try when I find some time for it and let you know if I manage to make it work.

Feb 15, 2012 at 2:59 PM

Hi Eric,

I tried to translate the index pages to PHP, and managed to do it for Index.aspx, FillNode.aspx and LoadIndexKeywords.aspx. But when I tried to translate SearchHelp.aspx, I realized that the full text index files where generated by .NET binary serialization, which makes it almost impossible to use them in PHP... So search in PHP is a no-go, unless SHFB can generate the full text index in another format.


Feb 15, 2012 at 7:33 PM

I guess it's a question of what format PHP can handle.  I suppose I could dump it out in some sort of raw binary format and bypass serialization for code that reads it in manually to construct the dictionaries, etc.  XML is an option but I think the files would be significantly larger as a result.



Feb 15, 2012 at 8:11 PM
Edited Feb 15, 2012 at 8:33 PM

PHP should be able to handle most text formats, and probably some binary formats, but not this one... I think JSON would be a good candidate ; it's easy to parse (with json_decode), and more compact than XML (but less than binary of course). In .NET, you can easily serialize a list or dictionary to JSON with JavaScriptSerializer. I need to do a few tests to see if it's really feasible ; I'll keep you posted.

Meanwhile, I can submit a patch with the files I have already translated to PHP. I think it's a significant improvement over the static HTML version, because fetching the nodes on demand makes the page load much faster. You can see it live here (static HTML here for comparison)


EDIT: I just tried to convert the FTIs to JSON and got a surprising result : it's actually more compact than binary ! (average ratio is about 0.66)

Feb 18, 2012 at 8:59 PM

Thanks for the reference.  I didn't know about the JavaScript serializer.  It's hard to keep up with all the changes to the framework.  I've implemented it and checked the changes into source control.  I also implemented the Direct Link option.  Thanks for the suggestions.



Feb 18, 2012 at 11:41 PM


Great news! It should now be fairly easy to implement search in PHP, I'll do it as soon as possible.


Feb 19, 2012 at 2:17 PM
Edited Feb 19, 2012 at 2:46 PM

Hi Eric,

I implemented the search in PHP, it works great (you can see it live here). I uploaded the files as patch 11526.

Notes about this patch:

  • it only contains the web files, not the changes in SHFB to include them in the build output (EDIT: apparently you just need to modify BuildProcess.GenerateWebSite to apply TransformTemplate on PHP files as well)
  • there is a specific version of TOC.js (named TOC.php.js) that makes AJAX requests to the PHP scripts instead of the ASPX ones. There's probably a more elegant way to handle this, but I didn't bother too much...


Feb 19, 2012 at 7:23 PM

Thanks.  I'll merge them in.  What's your name?  I'll give you credit in the files and the release notes for creating them.  Regarding the modified script file,  I think we could probably put a variable in the index pages to set an extension to use in the script (".aspx" or ".php").  That would probably work and then there'd be only the one script file to manage.



Feb 19, 2012 at 8:11 PM

Hi Eric,

My name is Thomas Levesque.

The solution you propose seems good, let me know if you need me to update the PHP code.


May 9, 2012 at 7:27 PM


I've noticed when you use a direct link to a page of content (e.g., the TOC is not sync'd and the SyncTOC button doesn't work either - is there any way to get this to work?



May 9, 2012 at 7:41 PM

There isn't currently a way to sync the TOC as the nodes are loaded on demand.  So, unless the node containing the topic has already been loaded, the button won't do anything.  The Sync to TOC button will work on the Index.html page as it loads the entire TOC when first loaded.  The downside to using that is the initial load time, especially on a large project.  So far, I haven't looked into preloading the related node for a topic accessed via a direct link.



May 9, 2012 at 8:05 PM

Thanks Eric,

I noticed it worked for index.html, our project isn't large enough yet for load times to be a problem, the main downside I saw was the lack of search and index.  I don't suppose there is a simple way to force the aspx version to pre-load all TOC nodes?


Aug 16, 2012 at 10:53 AM

Hi Dave,

I'd been having similar problems in getting the ToC to sync when loading via a direct link to the aspx page. After a lot of frustration I managed to get it working by changing the TOC.js, first changing the line:

    topicContent.onload = SyncTOC;

 to be:

   topicContent.onload = LoadTOC;

 Then adding another function to the top of the Navigation section:

// Navigation and expand/collaps code

// Force the TOC to expand, then collapse and sync
function LoadTOC() {
    setTimeout(function () { ExpandOrCollapseAll(false); }, 100);
    setTimeout(function () { SyncTOC(); }, 200);

The reason that there's a delay on the second two calls is when calling the functions together, it seems IE doesn't finish processing the expand method before calling the others so it doesn't work. Hope this works for you. 

Aug 16, 2012 at 11:14 AM

Edit: it seems the downside of this is that it expands and collapses the ToC every time you change topic.

Back to the drawing board.

Feb 2, 2013 at 3:39 PM
Hi inexorous,

It's been a while but I've recently returned to looking at this problem; as I'm increasing our guide content, I'm sending out direct links in e-mails - but it's really unfortunate you have no 'reference point' as to where the page you're looking at 'sits' within the TOC.

That was a good try (above) and it did sort of work when I compiled only our additional content but see what you mean about everything expanding and collapsing every time you change topic. Our build solution API reference is getting quite large now (currently 23 documentation sources spanning 15 namespaces producing over 12,000 html pages in the web output!) - it's just not practical to load the whole TOC - in fact the "Expand All" button just melts the browser when I press it :-) [on a pretty good quad core i7 machine with 8gb of ram].

However... I've done it (quite happy with myself considering I've only ever dabbled with javascript years ago) - by making changes just to TOC.js - I've managed to make it recursively lazy load just the TOC nodes it needs to, in order to be able to sync :)

I need to test it a bit more but it appears to be working fantasticly even with our large API reference compiled in. I was going to run it past a colleague on Monday (as I'm sure my script could be tidied up and made more effecient) - but will gladly share with anyone interested!

I'm also thinking that the "SyncTOC" button is no longer required (as it always keeps in sync now, whether navigating through pages or navigating via the TOC). I'm also wondering about trying to make the "Expand All" button ONLY expand all nodes UNDER the currently selected one - I don't believe anyone would ever want to expand absolutely everything and in our case it won't let them anyway.

Feb 2, 2013 at 6:14 PM
Improving the syncing and expansion has been on the To Do list for a while but I'm no expert on JavaScript and web stuff in general and don't do enough development in it to stay current so it always gets put off until later. If you send me your changes once you're satisfied with them, I can merge them into a future release of SHFB. My e-mail address is in the About box in the standalone GUI and in the footer of the pages in the help file.

Feb 2, 2013 at 7:02 PM
Thanks Eric - that would be fantastic.

I'm only a novice with JavaScript myself but a guy I work with knows his stuff - he pointed me in the right direction (I didn't know about IE's developer tools). I figured out how the TOC was built (I used to do ASP development years ago) and we tried to implement changes using JQuery (something else I didn't know about) - but we couldn't easily get it working.

I persevered and got it working without referencing any other libraries, however I think it'll need modifying a bit for general use as I have used a few string.substring methods to extract a guid from a url (for example), as we use guids as the topic id's (but I think SHFB lets you use other naming strategies)... I'm sure with a few tweaks from yourself or others in the community it'll be good :)

I didn't want to break anything already working so the only change I made to TOC.js was a single call to a new function from within the SyncTOC method. The rest was done by just adding new functions (but bits of them have code borrowed and tweaked from other functions in there).

If it can't Sync the TOC it essentially uses JavaScript to read the WebTOC.xml to find the target page you're Navigating to, builds a list of parent TOC id's and loads the first 'unloaded' TOC item it finds - it goes round in circles loading the parent TOC nodes until the sync works.

I think it's probably going to be best to load the WebTOC.xml and store it in a module level variable (I'm re-reading it every time at present) - but I'll run that past my friend at work and hopefully be ready to share with you next week.

Mar 15, 2013 at 7:44 AM
Hello, I too have a requirement to host the reference documentation generated by SHFB either as a set of static files on the server, or with use of PHP, but no ASPX.
I have read the posts here but it is not completely whether the support for PHP has made into SHFB in full. If we switch to latest SHFB version, will hosting the doc with PHP work out of the box, with some extra steps (what steps?), or not at all?

Many thanks
Zbynek Zahradnik
Mar 15, 2013 at 3:06 PM
It will work out of the box without any extra steps. Just build the project using the Website output format. All of the necessary files are included in the output folder. You can set the appropriate Index.??? page as the default for the site (Index.aspx, Index.html, or Index.php). For an example, see the SHFB documentation using the PHP index page (

Mar 16, 2013 at 3:27 PM
Confirming - I have upgraded to SHFB, and it has generated PHP-based reference doc. Great job!
May 28, 2013 at 11:57 PM
Edited May 29, 2013 at 3:30 AM
Has anyone made any progress with menu synchronization? I have just updated some online docs to reopen individual pages found using a search engine in a frame (for example reopening an orphan page like as the framed, but as this is based on the direct linking system, the menu system is out of sync in the new frame.

DavidDansey, is there any way you could share your changes (even if preliminary); or anyone else who has found a workaround?
Jun 4, 2013 at 8:56 AM
Hi Adbnz \ All,

Sure - really sorry, I meant to e-mail Eric with the changes I made but things got really busy at work and must admit it slipped my mind.

We've been using my new TOC.js for several months now and it works really good for us - you can email a link to a specific page and when they open it, the TOC always syncs :).

I'll email it to Eric right now but it'll need a few tweaks I imagine - we use GUID's as the unique ID's for our content pages and as these are a fixed length, I'm using the following to extract the page ID from the URL:
    // Extract the target id from the url
    var target = url.substring(url.length-40,url.length-4);
If anyone uses non fixed-length ID's, this will obviously need to be tweaked.

I won't attempt to post the code here as there's quite a bit of it but hopefully can be incorporated for everyone :)