tables-long.pl 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # Copyright (C) 2004–2015 Alex Schroeder <alex@gnu.org>
  2. # Copyright (C) 2015 Matt Adams <opensource@radicaldynamic.com>
  3. #
  4. # This program is free software: you can redistribute it and/or modify it under
  5. # the terms of the GNU General Public License as published by the Free Software
  6. # Foundation, either version 3 of the License, or (at your option) any later
  7. # version.
  8. #
  9. # This program is distributed in the hope that it will be useful, but WITHOUT
  10. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License along with
  14. # this program. If not, see <http://www.gnu.org/licenses/>.
  15. use strict;
  16. use v5.10;
  17. AddModuleDescription('tables-long.pl', 'Long Table Markup Extension');
  18. our ($bol, @Flags, $Fragment, @Blocks, $FS, @MyRules, $PortraitSupportColorDiv);
  19. push(@MyRules, \&TablesLongRule);
  20. my $TablesLongLabels = '';
  21. sub TablesLongRule {
  22. # start table by declaring the abbreviations used:
  23. # <table foo,bar,baz>
  24. # end with a horizontal line:
  25. # ----
  26. # use label: or label= to start a cell
  27. # label: bla
  28. # bla bla bla
  29. # a new row is started when a cell is repeated
  30. # if cells are missing, column spans are created (the first row
  31. # could use row spans...)
  32. if ($bol && m|\G\s*\n*\&lt;table(/[A-Za-z\x{0080}-\x{fffd}/]+)? +([A-Za-z\x{0080}-\x{fffd},;\/ ]+)\&gt; *\n|cg) {
  33. my $class = join(' ', split(m|/|, $1)); # leading / in $1 will make sure we have leading space
  34. Clean(CloseHtmlEnvironments() . "<table class=\"user long$class\">");
  35. # labels and their default class
  36. my %default_class = ();
  37. my @labels = map { my ($label, @classes) = split m|/|;
  38. $default_class{$label} = join(' ', @classes);
  39. $label;
  40. } split(/ *[,;] */, $2);
  41. my $regexp = join('|', @labels);
  42. # read complete table
  43. my @lines = ();
  44. while (m/\G(.*)\n?/cg) { # last line may miss newline
  45. my $line = $1;
  46. last if substr($line,0,4) eq ('----'); # the rest of this line is ignored!
  47. push(@lines, $line);
  48. }
  49. # parse lines and print table rows
  50. my $lastpos = pos;
  51. my @rows = ();
  52. my %row = ();
  53. my %class = %default_class;
  54. my %rowspan = ();
  55. my $label = '';
  56. my $rowspan = '';
  57. my $rownum = 1;
  58. for my $line (@lines) {
  59. if ($line =~ m|^($regexp)/?([0-9]+)?/?([A-Za-z\x{0080}-\x{fffd}/]+)?[:=] *(.*)|) { # regexp changes for other tables
  60. $label = $1;
  61. $rowspan = $2;
  62. $class = join(' ', split(m|/|, $3)); # no leading / therefore no leading space
  63. $line = $4;
  64. if ($row{$label}) { # repetition of label, we must start a new row
  65. TablesLongRow(\@labels, \%row, \%class, \%rowspan, $rownum++);
  66. %row = ();
  67. %class = %default_class;
  68. foreach my $key (keys %rowspan) {
  69. delete $rowspan{$key} if $rowspan{$key} == 1;
  70. $rowspan{$key}--; # 0 will turn into negative numbers
  71. }
  72. }
  73. $class{$label} = $class if $class;
  74. $rowspan{$label} = $rowspan if $rowspan;
  75. }
  76. $row{$label} .= $line . "\n";
  77. }
  78. TablesLongRow(\@labels, \%row, \%class, \%rowspan, $rownum); # don't forget the last row
  79. Clean('</table>' . AddHtmlEnvironment('p'));
  80. pos = $lastpos;
  81. return '';
  82. }
  83. return;
  84. }
  85. sub TablesLongRow {
  86. my @labels = @{$_[0]};
  87. my %row = %{$_[1]};
  88. my %class = %{$_[2]};
  89. my %rowspan = %{$_[3]};
  90. my $rownum = $_[4];
  91. if ($rownum == 1) {
  92. Clean('<tr class="first odd">');
  93. } elsif ($rownum % 2 == 0) {
  94. Clean('<tr class="even">');
  95. } else {
  96. Clean('<tr class="odd">');
  97. }
  98. # first print the old row
  99. for my $i (0 .. $#labels) {
  100. next if not $row{$labels[$i]}; # should only happen after previous cellspans
  101. my $colspan = 1;
  102. while ($i + $colspan < $#labels + 1
  103. and not $row{$labels[$i+$colspan]}
  104. and not $rowspan{$labels[$i+$colspan]}) {
  105. $colspan++;
  106. }
  107. my $rowspan = $rowspan{$labels[$i]};
  108. my $class = $class{$labels[$i]};
  109. my $html = '<';
  110. $html .= $rownum == 1 ? 'th' : 'td';
  111. $html .= " colspan=\"$colspan\"" if $colspan != 1;
  112. $html .= " rowspan=\"$rowspan\"" if defined $rowspan and $rowspan >= 0; # ignore negatives
  113. $html .= " class=\"$class\"" if $class;
  114. $html .= '>';
  115. Clean($html);
  116. # WATCH OUT: here comes the evil magic messing with the internals! first, clean everything up like at the end of
  117. # ApplyRules. The reason we are doing this is because we don't want to treat the entire long table as a single dirty
  118. # block. We want to cache as much as possible.
  119. if ($Fragment ne '') {
  120. $Fragment =~ s|<p>\s*</p>||g; # clean up extra paragraphs (see end Dirty())
  121. print $Fragment;
  122. push(@Blocks, $Fragment);
  123. push(@Flags, 0);
  124. $Fragment = '';
  125. }
  126. # call ApplyRules, and *inline* the results; ignoring $PortraitSupportColorDiv
  127. local $PortraitSupportColorDiv;
  128. my ($blocks, $flags) = ApplyRules($row{$labels[$i]}, 1, 1); # local links, anchors
  129. # split using a negative limit so that trailing empty fields are not stripped
  130. push(@Blocks, split(/$FS/, $blocks, -1));
  131. push(@Flags, split(/$FS/, $flags, -1));
  132. # end of evil magic
  133. Clean(CloseHtmlEnvironments() . '</' . ($rownum == 1 ? 'th' : 'td') . '>');
  134. }
  135. Clean('</tr>');
  136. }