summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/table.pm
blob: c7b6640525d6b88f4d6b58ac70164d222bbf8038 (plain)
  1. package IkiWiki::Plugin::table;
  2. # by Victor Moral <victor@taquiones.net>
  3. use warnings;
  4. use strict;
  5. use IkiWiki 2.00;
  6. sub import { #{{{
  7. hook(type => "preprocess", id => "table", call => \&preprocess);
  8. } # }}}
  9. sub preprocess (@) { #{{{
  10. my %params =(
  11. format => 'auto',
  12. header => 'yes',
  13. @_
  14. );
  15. if (exists $params{file}) {
  16. if (! $pagesources{$params{file}}) {
  17. return "[[table ".gettext("cannot find file")."]]";
  18. }
  19. $params{data} = readfile(srcfile($params{file}));
  20. }
  21. else {
  22. $params{data} = IkiWiki::linkify($params{page},
  23. $params{destpage}, $params{data});
  24. }
  25. if (lc $params{format} eq 'auto') {
  26. # first try the more simple format
  27. if (is_dsv_data($params{data})) {
  28. $params{format} = 'dsv';
  29. }
  30. else {
  31. $params{format} = 'csv';
  32. }
  33. }
  34. my @data;
  35. if (lc $params{format} eq 'csv') {
  36. @data=split_csv($params{data}, $params{delimiter});
  37. }
  38. elsif (lc $params{format} eq 'dsv') {
  39. @data=split_dsv($params{data}, $params{delimiter});
  40. }
  41. else {
  42. return "[[table ".gettext("unknown data format")."]]";
  43. }
  44. my $header;
  45. if (lc($params{header}) eq "yes") {
  46. $header=shift @data;
  47. }
  48. if (! @data) {
  49. return "[[table ".gettext("empty data")."]]";
  50. }
  51. my @lines;
  52. push @lines, defined $params{class}
  53. ? "<table class=\"".$params{class}.'">'
  54. : '<table>';
  55. push @lines, "\t<thead>",
  56. genrow($params{page}, $params{destpage}, "th", @$header),
  57. "\t</thead>" if defined $header;
  58. push @lines, "\t<tbody>";
  59. push @lines, genrow($params{page}, $params{destpage}, "td", @$_)
  60. foreach @data;
  61. push @lines, "\t</tbody>" if defined $header;
  62. push @lines, '</table>';
  63. my $html = join("\n", @lines);
  64. if (exists $params{file}) {
  65. return $html."\n\n".
  66. htmllink($params{page}, $params{destpage}, $params{file},
  67. linktext => gettext('Direct data download'));
  68. }
  69. else {
  70. return $html;
  71. }
  72. } #}}}
  73. sub is_dsv_data ($) { #{{{
  74. my $text = shift;
  75. my ($line) = split(/\n/, $text);
  76. return $line =~ m{.+\|};
  77. }
  78. sub split_csv ($$) { #{{{
  79. my @text_lines = split(/\n/, shift);
  80. my $delimiter = shift;
  81. eval q{use Text::CSV};
  82. error($@) if $@;
  83. my $csv = Text::CSV->new({
  84. sep_char => defined $delimiter ? $delimiter : ",",
  85. binary => 1,
  86. allow_loose_quotes => 1,
  87. }) || error("could not create a Text::CSV object");
  88. my $l=0;
  89. my @data;
  90. foreach my $line (@text_lines) {
  91. $l++;
  92. if ($csv->parse($line)) {
  93. push(@data, [ $csv->fields() ]);
  94. }
  95. else {
  96. debug(sprintf(gettext('parse fail at line %d: %s'),
  97. $l, $csv->error_input()));
  98. }
  99. }
  100. return @data;
  101. } #}}}
  102. sub split_dsv ($$) { #{{{
  103. my @text_lines = split(/\n/, shift);
  104. my $delimiter = shift;
  105. $delimiter="|" unless defined $delimiter;
  106. my @data;
  107. foreach my $line (@text_lines) {
  108. push @data, [ split(/\Q$delimiter\E/, $line, -1) ];
  109. }
  110. return @data;
  111. } #}}}
  112. sub genrow ($$$@) { #{{{
  113. my $page = shift;
  114. my $destpage = shift;
  115. my $elt = shift;
  116. my @data = @_;
  117. my @ret;
  118. push @ret, "\t\t<tr>";
  119. for (my $x=0; $x < @data; $x++) {
  120. my $cell=htmlize($page, $destpage, $data[$x]);
  121. my $colspan=1;
  122. while ($x+1 < @data && $data[$x+1] eq '') {
  123. $x++;
  124. $colspan++;
  125. }
  126. if ($colspan > 1) {
  127. push @ret, "\t\t\t<$elt colspan=\"$colspan\">$cell</$elt>"
  128. }
  129. else {
  130. push @ret, "\t\t\t<$elt>$cell</$elt>"
  131. }
  132. }
  133. push @ret, "\t\t</tr>";
  134. return @ret;
  135. } #}}}
  136. sub htmlize ($$$) { #{{{
  137. my $page = shift;
  138. my $destpage = shift;
  139. my $text = shift;
  140. $text=IkiWiki::htmlize($page, pagetype($pagesources{$page}),
  141. IkiWiki::preprocess($page, $destpage, $text));
  142. # hack to get rid of enclosing junk added by markdown
  143. $text=~s!^<p>!!;
  144. $text=~s!</p>$!!;
  145. chomp $text;
  146. return $text;
  147. }
  148. 1