diff options
-rw-r--r-- | IkiWiki/Plugin/postsparkline.pm | 123 | ||||
-rw-r--r-- | debian/changelog | 1 | ||||
-rw-r--r-- | doc/plugins/postsparkline.mdwn | 46 |
3 files changed, 170 insertions, 0 deletions
diff --git a/IkiWiki/Plugin/postsparkline.pm b/IkiWiki/Plugin/postsparkline.pm new file mode 100644 index 000000000..2bc93088d --- /dev/null +++ b/IkiWiki/Plugin/postsparkline.pm @@ -0,0 +1,123 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::postsparkline; + +use warnings; +use strict; +use IkiWiki; + +sub import { #{{{ + IkiWiki::loadplugin('sparkline'); + hook(type => "preprocess", id => "postsparkline", call => \&preprocess); +} # }}} + +sub preprocess (@) { #{{{ + my %params=@_; + + if (! exists $params{max}) { + $params{max}=100; + } + + if (! exists $params{pages}) { + return ""; + } + + if (! exists $params{formula}) { + return "[[postsparkline ".gettext("missing formula")."]]"; + } + my $formula=$params{formula}; + $formula=~s/[^a-zA-Z0-9]*//g; + $formula=IkiWiki::possibly_foolish_untaint($formula); + if (! length $formula || + ! IkiWiki::Plugin::postsparkline::formula->can($formula)) { + return "[[postsparkline ".gettext("unknown formula")."]]"; + } + + add_depends($params{page}, $params{pages}); + + my @list; + foreach my $page (keys %pagesources) { + next if $page eq $params{page}; + if (pagespec_match($page, $params{pages}, $params{page})) { + push @list, $page; + } + } + + @list = sort { $IkiWiki::pagectime{$b} <=> $IkiWiki::pagectime{$a} } @list; + + delete $params{pages}; + delete $params{formula}; + my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)}; + if ($@) { + return "[[postsparkline error $@]]"; + } + return IkiWiki::Plugin::sparkline::preprocess(%params, + map { $_ => "" } reverse @data); +} # }}} + +sub perfoo ($@) { + my $sub=shift; + my $params=shift; + + my $max=$params->{max}; + my ($first, $prev, $cur); + my $count=0; + my @data; + foreach (@_) { + $cur=$sub->($IkiWiki::pagectime{$_}); + if (defined $prev) { + if ($prev != $cur) { + push @data, "$prev,$count"; + $count=0; + last if --$max <= 0; + + for ($cur+1 .. $prev-1) { + push @data, "$_,0"; + last if --$max == 0; + } + } + } + else { + $first=$cur; + } + $count++; + $prev=$cur; + } + + return @data; +} + +package IkiWiki::Plugin::postsparkline::formula; + +sub peryear (@) { + return IkiWiki::Plugin::postsparkline::perfoo(sub { + return (localtime $_[0])[5]; + }, @_); +} + +sub permonth (@) { + return IkiWiki::Plugin::postsparkline::perfoo(sub { + my ($month, $year)=(localtime $_[0])[4,5]; + return $year*12+$month; + }, @_); +} + +sub perday (@) { + return IkiWiki::Plugin::postsparkline::perfoo(sub { + my ($year, $yday)=(localtime $_[0])[5,7]; + return $year*365+$yday; + }, @_); +} + +sub interval ($@) { + my $params=shift; + + my $max=$params->{max}; + my @data; + for (my $i=1; $i < @_; $i++) { + push @data, $IkiWiki::pagectime{$_[$i-1]} - $IkiWiki::pagectime{$_[$i]}; + last if --$max <= 0; + } + return @data; +} + +1 diff --git a/debian/changelog b/debian/changelog index faddbb983..f14443217 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,7 @@ ikiwiki (1.45) UNRELEASED; urgency=low image using width and height attributes. * Also fixes img preview display, the links were wrong in preview before. * Add a sparkline plugin. + * Add a postsparkline plugin. * The slash escaping when adding to a blog from the CGI was not working since it ended up being double-escaped. Instead, just remove slashes. * Fix some nasty issues with page name escaping during previewing diff --git a/doc/plugins/postsparkline.mdwn b/doc/plugins/postsparkline.mdwn new file mode 100644 index 000000000..a85d7e824 --- /dev/null +++ b/doc/plugins/postsparkline.mdwn @@ -0,0 +1,46 @@ +[[template id=plugin name=postsparkline author="[[Joey]]"]] +[[tag type/chrome]] + +This plugin uses the [[sparkline]] plugin to create a sparkline of +statistics about a set of pages, such as posts to a blog. + +# examples + + Post interval: + \[[postsparkline pages="blog/* and !*/Discussion" max=100 + formula=interval style=bar barwidth=2 barspacing=1 height=13]] + + Posts per month this year: + \[[postsparkline pages="blog/* and !*/Discussion" max=12 + formula=permonth style=bar barwidth=2 barspacing=1 height=13]] + +# usage + +All options aside fron the `pages`, `max`, and `forumla` options are passed +on to the sparkline plugin. + +You don't need to specify any data points (though you can if you want to). +Instead, data points are automatically generated based on the creation +times of pages matched by the specified `pages` [[PageSpec]]. A maximum of +`max` data points will be generated. + +The `formula` parameter controls the formula used to generate data points. +Available forumlae: + +* `interval` - The height of each point represents how long it has been + since the previous post. +* `perday` - Each point represents a day; the height represents how + many posts were made that day. +* `permonth` - Each point represents a month; the height represents how + many posts were made that month. +* `peryear` - Each point represents a day; the height represents how + many posts were made that year. + +# adding formulae + +Additional formulae can be added without modifying this plugin by writing +plugins that register functions in the +`IkiWiki::Plugin::postsparkline::formula` namespace. These functions will +receive on input a reference to a hash of parameters, and a sorted list of +pages (newest pages first), and should return a list of data points for +the sparkline plugin. |