2011/07/29

markdown文書に TOC を追加する

この日記(wiki)では markdown を採用している。HTML 化には Text::MultiMarkdown を使用しているわけですが、特にページがある程度のサイズになってくるものだと、TOC(Table Of Content: もくじ) が欲しくなる。

例えば sandbox の冒頭で見出しがページ内リンクで並んでいるようなやつ。

というわけで、以下のようなコードで TOC に対応した。

sub toc {
    my ($self, $text_ref, $c) = @_;

    while ( $$text_ref =~ s#\{\{(?:toc|TOC) (\d)(\-)?(\d)?\}\}#<div class="toc">\n<!-- MyAppTOC -->\n</div># ) {
        my $toc_h_min = $1 || 1;
        my $toc_h_max = ($1 && $3) ? $3 : (!$3 && !$2 && $1) ? $1 : 9;
        $toc_h_min = 9 if $toc_h_min > 9;
        $toc_h_max = 9 if $toc_h_max > 9 || $toc_h_max < $toc_h_min;
        my $toc = HTML::Toc->new;
        my $tocInsertor = HTML::TocInsertor->new;
        $toc->setOptions({
            header => '',
            footer => '',
            insertionPoint => 'replace <!-- MyAppTOC -->',
            doLinkToId => 0,
            levelToToc => "[$toc_h_min-$toc_h_max]",
            templateAnchorName => \&__assembleAnchorName,
        });
        $tocInsertor->insert($toc, $$text_ref, { output => $text_ref });
    }
    sub __assembleAnchorName {
        my ($aFile, $aGroupId, $aLevel, $aNode, $text, $children) = @_;

        if ($text !~ /^\s*$/) {
            $text =~ s/\s/_/g;
            html_decode($text);
            $text = encode($text);
            $text =~ s/([^A-Za-z0-9_:.-])/sprintf('.%02X', ord($1))/eog;
            $text = 'L'.$text if $text =~ /\A\W/o;
        }
        $text = 'id' if $text eq '';
        return $text;
    }
}

{{TOC 3-}} (実際は半角)というような記述を目次に整形してくれる。
HTML::TocHTML::TocInsertor を使えばだいたいこれだけ。
正規表現のあたりは改良の余地があるかと思う。

元ねたは MojoMojo から。

サイト内検索