fix data:image handling
[ikiwiki.git] / IkiWiki / Plugin / toc.pm
blob279eef00837a66c901056096c89af1c1180e6a42
1 #!/usr/bin/perl
2 # Table Of Contents generator
3 package IkiWiki::Plugin::toc;
5 use warnings;
6 use strict;
7 use IkiWiki;
8 use HTML::Parser;
10 sub import { #{{{
11 hook(type => "preprocess", id => "toc", call => \&preprocess);
12 hook(type => "format", id => "toc", call => \&format);
13 } # }}}
15 my %tocpages;
17 sub preprocess (@) { #{{{
18 my %params=@_;
20 $params{levels}=1 unless exists $params{levels};
22 # It's too early to generate the toc here, so just record the
23 # info.
24 $tocpages{$params{destpage}}=\%params;
26 return "\n<div class=\"toc\"></div>\n";
27 } # }}}
29 sub format (@) { #{{{
30 my %params=@_;
31 my $content=$params{content};
33 return $content unless exists $tocpages{$params{page}};
34 %params=%{$tocpages{$params{page}}};
36 my $p=HTML::Parser->new(api_version => 3);
37 my $page="";
38 my $index="";
39 my %anchors;
40 my $curlevel;
41 my $startlevel=0;
42 my $liststarted=0;
43 my $indent=sub { "\t" x $curlevel };
44 $p->handler(start => sub {
45 my $tagname=shift;
46 my $text=shift;
47 if ($tagname =~ /^h(\d+)$/i) {
48 my $level=$1;
49 my $anchor="index".++$anchors{$level}."h$level";
50 $page.="$text<a name=\"$anchor\" />";
52 # Take the first header level seen as the topmost level,
53 # even if there are higher levels seen later on.
54 if (! $startlevel) {
55 $startlevel=$level;
56 $curlevel=$startlevel-1;
58 elsif ($level < $startlevel) {
59 $level=$startlevel;
62 return if $level - $startlevel >= $params{levels};
64 if ($level > $curlevel) {
65 while ($level > $curlevel + 1) {
66 $index.=&$indent."<ol>\n";
67 $curlevel++;
68 $index.=&$indent."<li class=\"L$curlevel\">\n";
70 $index.=&$indent."<ol>\n";
71 $curlevel=$level;
72 $liststarted=1;
74 elsif ($level < $curlevel) {
75 while ($level < $curlevel) {
76 $index.=&$indent."</li>\n" if $curlevel;
77 $curlevel--;
78 $index.=&$indent."</ol>\n";
80 $liststarted=0;
83 $p->handler(text => sub {
84 $page.=join("", @_);
85 $index.=&$indent."</li>\n" unless $liststarted;
86 $liststarted=0;
87 $index.=&$indent."<li class=\"L$curlevel\">".
88 "<a href=\"#$anchor\">".
89 join("", @_).
90 "</a>\n";
91 $p->handler(text => undef);
92 }, "dtext");
94 else {
95 $page.=$text;
97 }, "tagname, text");
98 $p->handler(default => sub { $page.=join("", @_) }, "text");
99 $p->parse($content);
100 $p->eof;
102 while ($startlevel && $curlevel >= $startlevel) {
103 $index.=&$indent."</li>\n" if $curlevel;
104 $curlevel--;
105 $index.=&$indent."</ol>\n";
108 $page=~s/(<div class=\"toc\">)/$1\n$index/;
109 return $page;