summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/postsparkline.pm
blob: c2ebbc5eb1da5f9e6daf6fcb704f48ebd2fe6dbf (plain)
  1. #!/usr/bin/perl
  2. package IkiWiki::Plugin::postsparkline;
  3. use warnings;
  4. use strict;
  5. use IkiWiki 3.00;
  6. sub import {
  7. IkiWiki::loadplugin('sparkline');
  8. hook(type => "getsetup", id => "postsparkline", call => \&getsetup);
  9. hook(type => "preprocess", id => "postsparkline", call => \&preprocess);
  10. }
  11. sub getsetup () {
  12. return
  13. plugin => {
  14. safe => 1,
  15. rebuild => undef,
  16. },
  17. }
  18. sub preprocess (@) {
  19. my %params=@_;
  20. if (! exists $params{max}) {
  21. $params{max}=100;
  22. }
  23. if (! exists $params{pages}) {
  24. return "";
  25. }
  26. if (! exists $params{time} || $params{time} ne 'mtime') {
  27. $params{timehash} = \%IkiWiki::pagectime;
  28. }
  29. else {
  30. $params{timehash} = \%IkiWiki::pagemtime;
  31. }
  32. if (! exists $params{formula}) {
  33. error gettext("missing formula")
  34. }
  35. my $formula=$params{formula};
  36. $formula=~s/[^a-zA-Z0-9]*//g;
  37. $formula=IkiWiki::possibly_foolish_untaint($formula);
  38. if (! length $formula ||
  39. ! IkiWiki::Plugin::postsparkline::formula->can($formula)) {
  40. error gettext("unknown formula");
  41. }
  42. add_depends($params{page}, $params{pages});
  43. my @list=pagespec_match_list(
  44. [ grep { $_ ne $params{page} } keys %pagesources],
  45. $params{pages}, location => $params{page});
  46. @list = sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } @list;
  47. my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)};
  48. if ($@) {
  49. error $@;
  50. }
  51. if (! @data) {
  52. # generate an empty graph
  53. push @data, 0 foreach 1..($params{max} / 2);
  54. }
  55. my $color=exists $params{color} ? "($params{color})" : "";
  56. delete $params{pages};
  57. delete $params{formula};
  58. delete $params{ftime};
  59. delete $params{color};
  60. return IkiWiki::Plugin::sparkline::preprocess(%params,
  61. map { $_.$color => "" } reverse @data);
  62. }
  63. sub perfoo ($@) {
  64. my $sub=shift;
  65. my $params=shift;
  66. my $max=$params->{max};
  67. my ($first, $prev, $cur);
  68. my $count=0;
  69. my @data;
  70. foreach (@_) {
  71. $cur=$sub->($params->{timehash}->{$_});
  72. if (defined $prev) {
  73. if ($prev != $cur) {
  74. push @data, "$prev,$count";
  75. $count=0;
  76. last if --$max <= 0;
  77. for ($cur+1 .. $prev-1) {
  78. push @data, "$_,0";
  79. last if --$max == 0;
  80. }
  81. }
  82. }
  83. else {
  84. $first=$cur;
  85. }
  86. $count++;
  87. $prev=$cur;
  88. }
  89. return @data;
  90. }
  91. package IkiWiki::Plugin::postsparkline::formula;
  92. sub peryear (@) {
  93. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  94. return (localtime $_[0])[5];
  95. }, @_);
  96. }
  97. sub permonth (@) {
  98. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  99. my ($month, $year)=(localtime $_[0])[4,5];
  100. return $year*12+$month;
  101. }, @_);
  102. }
  103. sub perday (@) {
  104. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  105. my ($year, $yday)=(localtime $_[0])[5,7];
  106. return $year*365+$yday;
  107. }, @_);
  108. }
  109. sub interval ($@) {
  110. my $params=shift;
  111. my $max=$params->{max};
  112. my @data;
  113. for (my $i=1; $i < @_; $i++) {
  114. push @data, $params->{timehash}->{$_[$i-1]} - $params->{timehash}->{$_[$i]};
  115. last if --$max <= 0;
  116. }
  117. return @data;
  118. }
  119. 1