SimpleTableOfContents

Note: The recipes here are for PmWiki versions 0.6 and 1.0 only. For PmWiki 2.0 recipes, see Cookbook.


Goal

Automatically generate a Table of Contents for pages with many headings.

PmWiki (1.0.13) doesn't come with a TOC feature, as PITS/00027 said, there feature request suspended for there already a Cookbook PageTableOfContents. But the cookbook TOC module seems a little complicated for me. All I want is a autogenerated TOC from all levels of headings in a page, just like the WikiPedia style.

Solution

Add some script to pmwiki.php to generate a list of all levels of headings. Feature:

  • auto generate TOC list for all level headings
  • use heading text as the target name
  • do not need to modify exist wiki text

First, add a function named ProcessTOC in pmwiki.php to insert Wiki text for TOC before print text begin.

function ProcessTOC($text) {

  $tocText = '';
  $bodyText = '';
  $lines = explode("\n",$text);
  $lineNo = 0;

  $minLevel = 9;
  foreach($lines as $x) {
    $lineNo += 1;
    if (preg_match("/^(!{1,6})/",$x,$match)) {
      $level = strlen($match[1]);
      if ($level < $minLevel ) $minLevel = $level;     # record the min heading level

      # get the heading text, rid leading ! and white space
      $strAnchor = preg_replace("/^(!{1,6}\s*)/","",$x); 

      # 'T_' for target, encode the heading text
      $strAnchor = 'T_'.preg_replace("/[+|%]/","_",urlencode($strAnchor));

      # add a line of toc text
      $toc = strlen($match[1])."","";
      $tocText .= $toc."\n";

      # add a target before heading text
      $x = "\n".$x;
    }
    $bodyText .= $x."\n";   # add a line of body text
  }

  $toc = "";
  if ($tocText != "") {
    # use substr to rid the tailing '\n'
    $lines = explode("\n",substr($tocText,0, strlen($tocText)-1) );    

    foreach($lines as $x) {
      $level = $x[0];

      # set a correct number of '*'
      $toc .= str_repeat('*', $level - $minLevel +1 ).substr($x,1)."\n";   
    }
    # add table border for TOC
    $tocText = "(:table border=1 cellpadding=10:)

\n(:cell:) \n".$toc."(:tableend:) \n\n";

  }
  return $tocText.$bodyText;

}

Then, at the beginning lines of PrintText function, change

  if ($text=="") $text=$Text;

to

  if ($text=="") $text = ProcessTOC($Text);

That's OK

For Example, these headings

  !! North America
  !!! New York
  !!! Washington
  !! Asia
  !!! China
  !!!! Shanghai
  !!! Japan

will turn to a TOC section of :

Discussion

I've only used PmWiki for a week, and am a PHP newhand (ProcessTOC is the first fuction code I write in PHP), so the solution here a very simple one but seems convenient for myself.

Consider a better solution:

  • Is it possible to write a module script for this and do not modify pmwiki.php ?
  • If targets defined in the heading text line, the result is error. the line of heading should not contain other targets, if need a special target name, define it in the line before heading line. (This happens to PmWiki.TextFormattingRules)
  • Compare to WikiPedia, the TOC need these features :
    • define __notoc__ for pages
    • toc section show/hide
    • do not show TOC when headings less than two lines
    • add outline style number before toc heading text. (e.g. 1.2.2)

See Also

Cookbook PageTableOfContents

History

2004.11.22 - Initial idea by LiuPing -> mailto:lp_ [snail] 163 [period] net

Comments & Bugs

Contributors

  • LiuPing -> mailto:lp_ [snail] 163 [period] net

pmwiki-2.3.38 -- Last modified by {{}}?

from IP: 85.171.160.186 ip should be disabled by default for security reasons