summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/postsparkline.pm
blob: 2fae9c5fee90ab266aa0be0d0b2fb4a5267afbb3 (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. section => "widget",
  17. },
  18. }
  19. sub preprocess (@) {
  20. my %params=@_;
  21. if (! exists $params{max}) {
  22. $params{max}=100;
  23. }
  24. if (! exists $params{pages}) {
  25. return "";
  26. }
  27. my $deptype;
  28. if (! exists $params{time} || $params{time} ne 'mtime') {
  29. $params{timehash} = \%IkiWiki::pagectime;
  30. # need to update when pages are added or removed
  31. $deptype = deptype("presence");
  32. }
  33. else {
  34. $params{timehash} = \%IkiWiki::pagemtime;
  35. # need to update when pages are changed
  36. $deptype = deptype("content");
  37. }
  38. if (! exists $params{formula}) {
  39. error gettext("missing formula")
  40. }
  41. my $formula=$params{formula};
  42. $formula=~s/[^a-zA-Z0-9]*//g;
  43. $formula=IkiWiki::possibly_foolish_untaint($formula);
  44. if (! length $formula ||
  45. ! IkiWiki::Plugin::postsparkline::formula->can($formula)) {
  46. error gettext("unknown formula");
  47. }
  48. my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} }
  49. pagespec_match_list($params{page}, $params{pages},
  50. deptype => $deptype,
  51. filter => sub { $_[0] eq $params{page} },
  52. );
  53. my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)};
  54. if ($@) {
  55. error $@;
  56. }
  57. if (! @data) {
  58. # generate an empty graph
  59. push @data, 0 foreach 1..($params{max} / 2);
  60. }
  61. my $color=exists $params{color} ? "($params{color})" : "";
  62. delete $params{pages};
  63. delete $params{formula};
  64. delete $params{ftime};
  65. delete $params{color};
  66. return IkiWiki::Plugin::sparkline::preprocess(%params,
  67. map { $_.$color => "" } reverse @data);
  68. }
  69. sub perfoo ($@) {
  70. my $sub=shift;
  71. my $params=shift;
  72. my $max=$params->{max};
  73. my ($first, $prev, $cur);
  74. my $count=0;
  75. my @data;
  76. foreach (@_) {
  77. $cur=$sub->($params->{timehash}->{$_});
  78. if (defined $prev) {
  79. if ($prev != $cur) {
  80. push @data, "$prev,$count";
  81. $count=0;
  82. last if --$max <= 0;
  83. for ($cur+1 .. $prev-1) {
  84. push @data, "$_,0";
  85. last if --$max == 0;
  86. }
  87. }
  88. }
  89. else {
  90. $first=$cur;
  91. }
  92. $count++;
  93. $prev=$cur;
  94. }
  95. return @data;
  96. }
  97. package IkiWiki::Plugin::postsparkline::formula;
  98. sub peryear (@) {
  99. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  100. return (localtime $_[0])[5];
  101. }, @_);
  102. }
  103. sub permonth (@) {
  104. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  105. my ($month, $year)=(localtime $_[0])[4,5];
  106. return $year*12+$month;
  107. }, @_);
  108. }
  109. sub perday (@) {
  110. return IkiWiki::Plugin::postsparkline::perfoo(sub {
  111. my ($year, $yday)=(localtime $_[0])[5,7];
  112. return $year*365+$yday;
  113. }, @_);
  114. }
  115. sub interval ($@) {
  116. my $params=shift;
  117. my $max=$params->{max};
  118. my @data;
  119. for (my $i=1; $i < @_; $i++) {
  120. push @data, $params->{timehash}->{$_[$i-1]} - $params->{timehash}->{$_[$i]};
  121. last if --$max <= 0;
  122. }
  123. return @data;
  124. }
  125. 1