2 # Table Of Contents generator
3 package IkiWiki::Plugin::toc;
11 hook(type => "getsetup", id => "toc", call => \&getsetup);
12 hook(type => "preprocess", id => "toc", call => \&preprocess);
13 hook(type => "format", id => "toc", call => \&format);
30 if ($params{page} eq $params{destpage}) {
31 $params{levels}=1 unless exists $params{levels};
33 # It's too early to generate the toc here, so just record the
35 $tocpages{$params{destpage}}=\%params;
37 return "\n<div class=\"toc\"></div>\n";
40 # Don't generate toc in an inlined page, doesn't work
48 my $content=$params{content};
50 return $content unless exists $tocpages{$params{page}};
51 %params=%{$tocpages{$params{page}}};
53 my $p=HTML::Parser->new(api_version => 3);
57 my $startlevel=($params{startlevel} ? $params{startlevel} : 0);
58 my $curlevel=$startlevel-1;
60 my $indent=sub { "\t" x $curlevel };
61 $p->handler(start => sub {
62 my ($tagname, $text, $attr) = @_;
63 if ($tagname =~ /^h(\d+)$/i) {
65 my $anchor="index".++$anchors{$level}."h$level";
66 $page.="$text<a name=\"$anchor\"></a>";
67 # if the heading already has a unique ID, use that instead in TOC
69 $anchor = $attr->{id};
72 # Unless we're given startlevel as a parameter,
73 # take the first header level seen as the topmost level,
74 # even if there are higher levels seen later on.
77 $curlevel=$startlevel-1;
79 elsif (defined $params{startlevel} &&
80 $level < $params{startlevel}) {
83 elsif ($level < $startlevel) {
87 return if $level - $startlevel >= $params{levels};
89 if ($level > $curlevel) {
90 while ($level > $curlevel + 1) {
91 $index.=&$indent."<ol>\n";
93 $index.=&$indent."<li class=\"L$curlevel\">\n";
95 $index.=&$indent."<ol>\n";
99 elsif ($level < $curlevel) {
100 while ($level < $curlevel) {
101 $index.=&$indent."</li>\n" if $curlevel;
103 $index.=&$indent."</ol>\n";
108 $index.=&$indent."</li>\n" unless $liststarted;
110 $index.=&$indent."<li class=\"L$curlevel\">".
111 "<a href=\"#$anchor\">";
113 $p->handler(text => sub {
115 $index.=join("", @_);
117 $p->handler(end => sub {
119 if ($tagname =~ /^h(\d+)$/i) {
120 $p->handler(text => undef);
121 $p->handler(end => undef);
130 }, "tagname, text, attr");
131 $p->handler(default => sub { $page.=join("", @_) }, "text");
135 while ($startlevel && $curlevel >= $startlevel) {
136 $index.=&$indent."</li>\n" if $curlevel;
138 $index.=&$indent."</ol>\n";
141 $page=~s/(<div class=\"toc\">)/$1\n$index/;