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};
32 $params{startlevel}=2 unless exists $params{startlevel};
34 # It's too early to generate the toc here, so just record the
36 $tocpages{$params{destpage}}=\%params;
38 return "\n<div class=\"toc\"></div>\n";
41 # Don't generate toc in an inlined page, doesn't work
49 my $content=$params{content};
51 return $content unless exists $tocpages{$params{page}};
52 %params=%{$tocpages{$params{page}}};
54 my $p=HTML::Parser->new(api_version => 3);
58 my $startlevel=($params{startlevel} ? $params{startlevel} : 0);
59 my $curlevel=$startlevel-1;
61 my $indent=sub { "\t" x $curlevel };
62 $p->handler(start => sub {
65 if ($tagname =~ /^h(\d+)$/i) {
67 my $anchor="index".++$anchors{$level}."h$level";
68 $page.="$text<a name=\"$anchor\"></a>";
70 # Unless we're given startlevel as a parameter,
71 # take the first header level seen as the topmost level,
72 # even if there are higher levels seen later on.
75 $curlevel=$startlevel-1;
77 elsif (defined $params{startlevel} &&
78 $level < $params{startlevel}) {
81 elsif ($level < $startlevel) {
85 return if $level - $startlevel >= $params{levels};
87 if ($level > $curlevel) {
88 while ($level > $curlevel + 1) {
89 $index.=&$indent."<ol>\n";
91 $index.=&$indent."<li class=\"L$curlevel\">\n";
93 $index.=&$indent."<ol>\n";
97 elsif ($level < $curlevel) {
98 while ($level < $curlevel) {
99 $index.=&$indent."</li>\n" if $curlevel;
101 $index.=&$indent."</ol>\n";
106 $index.=&$indent."</li>\n" unless $liststarted;
108 $index.=&$indent."<li class=\"L$curlevel\">".
109 "<a href=\"#$anchor\">";
111 $p->handler(text => sub {
113 $index.=join("", @_);
115 $p->handler(end => sub {
117 if ($tagname =~ /^h(\d+)$/i) {
118 $p->handler(text => undef);
119 $p->handler(end => undef);
129 $p->handler(default => sub { $page.=join("", @_) }, "text");
133 while ($startlevel && $curlevel >= $startlevel) {
134 $index.=&$indent."</li>\n" if $curlevel;
136 $index.=&$indent."</ol>\n";
139 $page=~s/(<div class=\"toc\">)/$1\n$index/;