From 5800d2160c53113e1d811ce2234608760a3db243 Mon Sep 17 00:00:00 2001 From: joey Date: Sun, 26 Nov 2006 19:46:11 +0000 Subject: [PATCH] add a poll plugin --- IkiWiki/Plugin/poll.pm | 160 +++++++++++++++++++++++++++++++++++++++++ basewiki/style.css | 13 ++++ debian/changelog | 4 +- doc/plugins/poll.mdwn | 24 +++++++ 4 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 IkiWiki/Plugin/poll.pm create mode 100644 doc/plugins/poll.mdwn diff --git a/IkiWiki/Plugin/poll.pm b/IkiWiki/Plugin/poll.pm new file mode 100644 index 000000000..b862ccdaa --- /dev/null +++ b/IkiWiki/Plugin/poll.pm @@ -0,0 +1,160 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::poll; + +use warnings; +use strict; +use IkiWiki; +use URI; + +sub import { #{{{ + hook(type => "preprocess", id => "poll", call => \&preprocess); + hook(type => "cgi", id => "poll", call => \&cgi); +} # }}} + +sub yesno ($) { #{{{ + my $val=shift; + return (defined $val && lc($val) eq "yes"); +} #}}} + +my %pagenum; +sub preprocess (@) { #{{{ + my %params=(open => "yes", total => "yes", percent => "yes", @_); + + my $open=yesno($params{open}); + my $showtotal=yesno($params{total}); + my $percent=yesno($params{percent}); + $pagenum{$params{page}}++; + + my %choices; + my @choices; + my $total=0; + while (@_) { + my $key=shift; + my $value=shift; + + next unless $key =~ /^\d+/; + + my $num=$key; + $key=shift; + $value=shift; + + $choices{$key}=$num; + push @choices, $key; + $total+=$num; + } + + my $ret=""; + foreach my $choice (@choices) { + my $percent=int($choices{$choice} / $total * 100); + if ($percent) { + $ret.="$choice ($percent%) "; + } + else { + $ret.="$choice ($choices{$choice}) "; + } + if ($open && exists $config{cgiurl}) { + my $url=URI->new($config{cgiurl}); + $url->query_form( + "do" => "poll", + "num" => $pagenum{$params{page}}, + "page" => $params{page}, + "choice" => $choice, + ); + $ret.="vote"; + } + $ret.="
\n
\n"; + } + if ($showtotal) { + $ret.="Total votes: $total\n"; + } + return "
$ret
"; +} # }}} + +sub cgi ($) { #{{{ + my $cgi=shift; + if (defined $cgi->param('do') && $cgi->param('do') eq "poll") { + my $choice=$cgi->param('choice'); + if (! defined $choice) { + error("no choice specified"); + } + my $num=$cgi->param('num'); + if (! defined $num) { + error("no num specified"); + } + my $page=IkiWiki::possibly_foolish_untaint($cgi->param('page')); + if (! defined $page || ! exists $pagesources{$page}) { + error("bad page name"); + } + + # Did they vote before? If so, let them change their vote, + # and check for dups. + my $session=IkiWiki::cgi_getsession(); + my $choice_param="poll_choice_${page}_$num"; + my $oldchoice=$session->param($choice_param); + if (defined $oldchoice && $oldchoice eq $choice) { + # Same vote; no-op. + IkiWiki::redirect($cgi, "$config{url}/".htmlpage($page)); + } + + my $content=readfile(srcfile($pagesources{$page})); + # Now parse the content, find the right poll, + # and find the choice within it, and increment its number. + # If they voted before, decrement that one. + my $edit=sub { + my $escape=shift; + my $params=shift; + return "\\[[poll $params]]" if $escape; + return $params unless --$num == 0; + my @bits=split(' ', $params); + my @ret; + while (@bits) { + my $n=shift @bits; + if ($n=~/=/) { + # val=param setting + push @ret, $n; + next; + } + my $c=shift @bits; + $c=~s/^"(.*)"/$1/g; + next unless defined $n && defined $c; + if ($c eq $choice) { + $n++; + } + if (defined $oldchoice && $c eq $oldchoice) { + $n--; + } + push @ret, $n, "\"$c\""; + } + return "[[poll ".join(" ", @ret)."]]"; + }; + $content =~ s{(\\?)\[\[poll\s+([^]]+)\s*\]\]}{$edit->($1, $2)}seg; + + # Store their vote, update the page, and redirect to it. + writefile($pagesources{$page}, $config{srcdir}, $content); + $session->param($choice_param, $choice); + IkiWiki::cgi_savesession($session); + $oldchoice=$session->param($choice_param); + if ($config{rcs}) { + # prevent deadlock with post-commit hook + IkiWiki::unlockwiki(); + IkiWiki::rcs_commit($pagesources{$page}, "poll vote", + IkiWiki::rcs_prepedit($pagesources{$page}), + $session->param("name"), $ENV{REMOTE_ADDR}); + } + else { + require IkiWiki::Render; + IkiWiki::refresh(); + IkiWiki::saveindex(); + } + # Need to set cookie in same http response that does the + # redir. + eval q{use CGI::Cookie}; + error($@) if $@; + my $cookie = CGI::Cookie->new(-name=> $session->name, -value=> $session->id); + print $cgi->redirect(-cookie => $cookie, + -url => "$config{url}/".htmlpage($page)); + exit; + } +} #}}} + +1 diff --git a/basewiki/style.css b/basewiki/style.css index 032665e70..1017e957f 100644 --- a/basewiki/style.css +++ b/basewiki/style.css @@ -206,6 +206,19 @@ li.L8 { list-style: upper-alpha; } +hr.poll { + height: 10pt; + color: white !important; + background: #eee; + border: 2px solid black; +} +div.poll { + margin-top: 1ex; + margin-bottom: 1ex; + padding: 1ex 1ex; + border: 1px solid #aaa; +} + input#openid_url { background: url(http://openid.net/login-bg.gif) no-repeat; background-color: #fff; diff --git a/debian/changelog b/debian/changelog index 900e62de4..345878cfc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -44,8 +44,10 @@ ikiwiki (1.34) UNRELEASED; urgency=low and their IP address, and needs to construct its own commit message containing them, or do something more appropriate for the given RCS. * Add softwaresite example. + * Add a poll plugin. + * Add quick mode for archive page generation. - -- Joey Hess Wed, 22 Nov 2006 09:59:12 -0500 + -- Joey Hess Thu, 23 Nov 2006 17:13:32 -0500 ikiwiki (1.33) unstable; urgency=low diff --git a/doc/plugins/poll.mdwn b/doc/plugins/poll.mdwn new file mode 100644 index 000000000..385a78b42 --- /dev/null +++ b/doc/plugins/poll.mdwn @@ -0,0 +1,24 @@ +[[template id=plugin name=poll included=1 author="[[Joey]]"]] +[[tag type/useful]] + +This plugin allows you to create online polls in the wiki. Here's an +example use: + + \[[poll 0 "red" 0 "green" 0 "blue"]] + +The numbers indicate how many users voted for that choice. When a user +votes for a choice in the poll, the page is modified and the number +incremented. + +While some basic precautions are taken to prevent users from accidentially +voting twice, this sort of poll is should not be counted on the be very +accurate; all the usual concerns about web based polling apply. Unless the +page that the poll is in is locked, users can even edit the page and change +the numbers! + +Parameters: + +* `open` - Whether voting is still open. Set to "no" to close the poll to + voting. +* `total` - Show total number of votes at bottom of poll. Default is "yes". +* `percent` - Whether to display percents. Default is "yes". -- 2.26.2