toc-headers.pl 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # Copyright (C) 2004 Alex Schroeder <alex@emacswiki.org>
  2. # Copyright (C) 2006 Igor Afanasyev <afan@mail.ru>
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. use strict;
  17. use v5.10;
  18. AddModuleDescription('toc-headers.pl');
  19. our ($q, $bol, %Page, @MyRules);
  20. our ($MinTocSize, $OrderedLists);
  21. push(@MyRules, \&HeadersRule);
  22. $MinTocSize = 4; # show toc only if the number of headings is greater or equal to this value
  23. $OrderedLists = 0; # 1 if use <ol> instead of <ul>
  24. my $TocCounter = 0; # private
  25. my $TocShown = 0; # private
  26. sub HeadersRule {
  27. my $html = undef;
  28. if (!$TocShown) {
  29. $html = CloseHtmlEnvironments() . TocHeadings() . AddHtmlEnvironment('p');
  30. $TocShown = 1;
  31. }
  32. if ($bol && (m/\G((.+?)[ \t]*\n(---+|===+)[ \t]*\n)/cg)) {
  33. $html .= CloseHtmlEnvironments();
  34. $TocCounter++;
  35. $html .= "<a name=\"#$TocCounter\"></a>";
  36. if (substr($3,0,1) eq '=') {
  37. $html .= $q->h2($2);
  38. } else {
  39. $html .= $q->h3($2);
  40. }
  41. $html .= AddHtmlEnvironment('p');
  42. }
  43. return $html;
  44. }
  45. sub TocHeadings {
  46. my $oldpos = pos; # make this sub not destroy the value of pos
  47. my $page = $Page{text}; # work on the page that is currently open!
  48. # ignore all the stuff that gets processed anyway
  49. foreach my $tag ('nowiki', 'pre', 'code') {
  50. $page =~ s|<$tag>(.*\n)*?</$tag>||gi;
  51. }
  52. my $Headings = "<h2>" . T('Contents') . "</h2>";
  53. my $HeadingsLevel = undef;
  54. my $HeadingsLevelStart = undef;
  55. my $count = 1;
  56. my $tag = $OrderedLists ? 'ol' : 'ul';
  57. while ($page =~ m/((.+?)[ \t]*\n(---+|===+)[ \t]*\n)/g) {
  58. my $depth = (substr($3,0,1) eq '=') ? 2 : 3;
  59. my $text = $2;
  60. next unless $text;
  61. my $link = "$count"; #1, #2, etc. links seem to work fine
  62. $text = QuoteHtml($text);
  63. if (not defined $HeadingsLevelStart) {
  64. # $HeadingsLevel is set to $depth - 1 so that we get an opening
  65. # of the list. We need $HeadingsLevelStart to close all open
  66. # tags at the end.
  67. $HeadingsLevel = $depth - 1;
  68. $HeadingsLevelStart = $depth - 1;
  69. }
  70. $count++;
  71. # if the first subheading is has depth 2, then
  72. # $HeadingsLevelStart is 1, and later subheadings may not be
  73. # at level 1 or below.
  74. $depth = $HeadingsLevelStart + 1 if $depth <= $HeadingsLevelStart;
  75. # the order of the three expressions is important!
  76. while ($HeadingsLevel > $depth) {
  77. $Headings .= "</li></$tag>";
  78. $HeadingsLevel--;
  79. }
  80. if ($HeadingsLevel == $depth) {
  81. $Headings .= '</li><li>';
  82. }
  83. while ($HeadingsLevel < $depth) {
  84. $Headings .= "<$tag class=\"h$depth\"><li>";
  85. $HeadingsLevel++;
  86. }
  87. $Headings .= "<a href=\"#$link\">$text</a>";
  88. }
  89. while ($HeadingsLevel > $HeadingsLevelStart) {
  90. $Headings .= "</li></$tag>";
  91. $HeadingsLevel--;
  92. }
  93. pos = $oldpos;
  94. return '' if $count <= $MinTocSize;
  95. return $q->div({-class=>'toc'}, $Headings)
  96. if $Headings;
  97. }