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