summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/postsparkline.pm
blob: ba43561fbc0d5f291f3eb80163dc88c9b506effe (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;
  44. foreach my $page (keys %pagesources) {
  45. next if $page eq $params{page};
  46. if (pagespec_match($page, $params{pages}, location => $params{page})) {
  47. push @list, $page;
  48. }
  49. }
  50. @list = sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } @list;
  51. my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)};
  52. if ($@) {
  53. error $@;
  54. }
  55. if (! @data) {
  56. # generate an empty graph
  57. push @data, 0 foreach 1..($params{max} / 2);
  58. }
  59. my $color=exists $params{color} ? "($params{color})" : "";
  60. delete $params{pages};
  61. delete $params{formula};
  62. delete $params{ftime};
  63. delete $params{color};
  64. return IkiWiki::Plugin::sparkline::preprocess(%params,
  65. map { $_.$color => "" } reverse @data);
  66. }
  67. sub perfoo ($@) {
  68. my $sub=shift;
  69. my $params=shift;
  70. my $max=$params->{max};
  71. my ($first, $prev, $cur);
  72. my $count=0;
  73. my @data;
  74. foreach (@_) {
  75. $cur=$sub->($params->{timehash}->{$_});
  76. if (defined $prev) {
  77. if ($prev != $cur) {
  78. push @data, "$prev,$count";
  79. $count=0;
  80. last if --$max <= 0;
  81. for ($cur+1 .. $prev-1) {
  82. push @data, "$_,0";
  83. last if --$max == 0;
  84. }
  85. }
  86. }
  87. else {
  88. $first=$cur;
  89. }
  90. $count++;
  91. $prev=$cur;
  92. }
  93. return @data;
  94. }
  95. package IkiWiki::Plugin::postsparkline::formula;
  96. sub peryear (@) {
  97. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  98. return (localtime $_[0])[5];
  99. }, @_);
  100. }
  101. sub permonth (@) {
  102. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  103. my ($month, $year)=(localtime $_[0])[4,5];
  104. return $year*12+$month;
  105. }, @_);
  106. }
  107. sub perday (@) {
  108. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  109. my ($year, $yday)=(localtime $_[0])[5,7];
  110. return $year*365+$yday;
  111. }, @_);
  112. }
  113. sub interval ($@) {
  114. my $params=shift;
  115. my $max=$params->{max};
  116. my @data;
  117. for (my $i=1; $i < @_; $i++) {
  118. push @data, $params->{timehash}->{$_[$i-1]} - $params->{timehash}->{$_[$i]};
  119. last if --$max <= 0;
  120. }
  121. return @data;
  122. }
  123. 1