4 * Copyright 2004 $ThePhpWikiProgrammingTeam
5 * Copyright 2008 Marc-Etienne Vargenau, Alcatel-lucent
7 * This file is part of PhpWiki.
9 * PhpWiki is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * PhpWiki is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * This plugin provides configurable polls.
27 <<WikiPoll require_all=0 require_least=2
28 question[1]="Do you like PhpWiki?"
29 answer[1][1]="Yes" answer[1][2]="Do not know" answer[1][3]="No"
30 question[2]="Do you have PhpWiki installed by your own?"
31 answer[2][1]="Yes" answer[2][2]="No"
32 question[3]="Did you install any other wiki engine?"
33 answer[3][1]="Yes" answer[3][2]="No"
34 question[4]="What wiki engine do you like most?"
35 answer[4][1]="c2Wiki" answer[4][2]="MoinMoin" answer[4][3]="PhpWiki"
36 answer[4][4]="usemod" answer[4][5]="Twiki" answer[4][5]="guiki"
37 answer[4][6]="Mediawiki" answer[4][7]="Other"
38 question[5]="Which PhpWiki version do you use?"
39 answer[5][1]="1.2.x" answer[5][2]="1.3.1-12" answer[5][3]="1.3.13"
44 * <<WikiPoll page=PhpWikiPoll admin=1 >>
45 * and protect this page properly (e.g. PhpWikiPoll/Admin)
48 * admin page (view and reset statistics)
49 * for now only radio, support checkboxes (multiple selections) also?
54 class WikiPlugin_WikiPoll
59 function getDescription()
61 return _("Enable configurable polls.");
64 function getDefaultArguments()
66 return array('page' => '[pagename]',
68 'require_all' => 1, // 1 if all questions must be answered
69 'require_least' => 0, // how many at least
73 function getArgs($argstr, $request = false, $defaults = false)
75 if ($defaults === false)
76 $defaults = $this->getDefaultArguments();
77 //Fixme: on POST argstr is empty
79 list ($argstr_args, $argstr_defaults) = $this->parseArgStr($argstr);
80 if (isset($argstr_args["question_1"])) {
81 $args['question'] = $this->str2array("question", $argstr_args);
82 $args['answer'] = array();
83 for ($i = 0; $i <= count($args['question']); $i++) {
84 if ($array = $this->str2array(sprintf("%s_%d", "answer", $i), $argstr_args))
85 $args['answer'][$i] = $array;
89 if (!empty($defaults))
90 foreach ($defaults as $arg => $default_val) {
91 if (isset($argstr_args[$arg]))
92 $args[$arg] = $argstr_args[$arg];
93 elseif ($request and ($argval = $request->getArg($arg)) !== false)
94 $args[$arg] = $argval; elseif (isset($argstr_defaults[$arg]))
95 $args[$arg] = (string)$argstr_defaults[$arg]; else
96 $args[$arg] = $default_val;
99 $args[$arg] = $this->expandArg($args[$arg], $request);
101 unset($argstr_args[$arg]);
102 unset($argstr_defaults[$arg]);
105 foreach (array_merge($argstr_args, $argstr_defaults) as $arg => $val) {
106 if (!preg_match("/^(answer_|question_)/", $arg))
107 trigger_error(sprintf(_("Argument ā%sā not declared by plugin."),
108 $arg), E_USER_NOTICE);
114 function handle_plugin_args_cruft($argstr, $args)
116 $argstr = str_replace("\n", " ", $argstr);
117 $argstr = str_replace(array("[", "]"), array("_", ""), $argstr);
118 $this->_args = $this->getArgs($argstr, $GLOBALS['request']);
122 private function str2array($var, $obarray = false)
124 if (!$obarray) $obarray = $GLOBALS;
127 $name = sprintf("%s_%d", $var, $i);
128 if (isset($obarray[$name])) $array[$i] = $obarray[$name];
131 $name = sprintf("%s_%d", $var, $i);
132 if (isset($obarray[$name])) $array[$i] = $obarray[$name];
133 } while (isset($obarray[$name]));
137 function run($dbi, $argstr, &$request, $basepage)
139 if (!isset($_SERVER))
140 $_SERVER =& $GLOBALS['HTTP_SERVER_VARS'];
141 $request->setArg('nocache', 'purge');
142 $args = $this->getArgs($argstr, $request);
143 if (!$args['page']) {
144 return $this->error(sprintf(_("A required argument ā%sā is missing."), 'page'));
146 if (!empty($args['admin']) and $request->_user->isAdmin()) {
148 return $this->doPollAdmin($dbi, $request, $page);
150 extract($this->_args);
151 $page = $dbi->getPage($args['page']);
152 // check ip and last visit
153 $poll = $page->get("poll");
154 $ip = $_SERVER['REMOTE_ADDR'];
155 $disable_submit = false;
156 if (isset($poll['ip'][$ip]) and ((time() - $poll['ip'][$ip]) < 20 * 60)) {
157 //view at least the result or disable the Go button
158 $html = HTML(HTML::strong(
159 _("Sorry! You must wait at least 20 minutes until you can vote again!")));
160 $html->pushContent($this->doPoll($page, $request, $request->getArg('answer'), true));
164 $poll['ip'][$ip] = time();
166 foreach ($poll['ip'] as $ip => $time) {
167 if ((time() - $time) > 21 * 60)
168 unset($poll['ip'][$ip]);
170 $html = HTML::form(array('action' => $request->getPostURL(),
171 'method' => 'post'));
173 if ($request->isPost()) {
174 // checkme: check if all answers are answered
175 if ($request->getArg('answer') and (
176 ($args['require_all'] and
177 count($request->getArg('answer')) == count($question))
179 ($args['require_least'] and
180 count($request->getArg('answer')) >= $args['require_least']))
182 $page->set("poll", $poll);
183 // update statistics and present them the user
184 return $this->doPoll($page, $request, $request->getArg('answer'));
186 $html->pushContent(HTML::p(HTML::strong(_("Not enough questions answered!"))));
190 $init = isset($question[0]) ? 0 : 1;
191 for ($i = $init; $i <= count($question); $i++) {
192 if (!isset($question[$i])) break;
194 if (!isset($answer[$i]))
195 trigger_error(fmt("Missing %s for %s", "answer" . "[$i]", "question" . "[$i]"),
200 $html->pushContent(HTML::p(HTML::strong($q)));
201 $html->pushContent(HTML::div(
202 HTML::input(array('type' => 'checkbox',
203 'name' => "answer[$i]",
205 HTML::raw(" "), $a));
208 for ($j = 0; $j <= count($a); $j++) {
210 $row->pushContent(HTML::div(
211 HTML::input(array('type' => 'radio',
212 'name' => "answer[$i]",
214 HTML::raw(" "), $a[$j]));
216 $html->pushContent(HTML::p(HTML::strong($q)), $row);
219 if (!$disable_submit)
220 $html->pushContent(HTML::p(
221 HTML::input(array('type' => 'submit',
222 'name' => "WikiPoll",
223 'value' => _("OK"))),
224 HTML::input(array('type' => 'reset',
226 'value' => _("Reset")))));
228 $html->pushContent(HTML::p(), HTML::strong(
229 _("Sorry! You must wait at least 20 minutes until you can vote again!")));
233 private function bar($percent)
236 return HTML(HTML::img(array('src' => $WikiTheme->getImageUrl('leftbar'),
238 HTML::img(array('src' => $WikiTheme->getImageUrl('mainbar'),
240 'width' => sprintf("%02d", $percent),
242 HTML::img(array('src' => $WikiTheme->getImageUrl('rightbar'),
246 private function doPoll($page, $request, $answers, $readonly = false)
248 $question = $this->_args['question'];
249 $answer = $this->_args['answer'];
250 $html = HTML::table(array('cellspacing' => 2));
251 $init = isset($question[0]) ? 0 : 1;
252 for ($i = $init; $i <= count($question); $i++) {
253 if (!isset($question[$i])) break;
254 $poll = $page->get('poll');
255 @$poll['data']['all'][$i]++;
257 if (!isset($answer[$i]))
258 trigger_error(fmt("Missing %s for %s", "answer" . "[$i]", "question" . "[$i]"),
261 $page->set('poll', $poll);
263 $result = (isset($answers[$i])) ? $answers[$i] : -1;
265 $checkbox = HTML::input(array('type' => 'checkbox',
266 'name' => "answer[$i]",
269 $checkbox->setAttr('checked', "checked");
271 list($percent, $count, $all) = $this->storeResult($page, $i, $result ? 1 : 0);
273 list($percent, $count, $all) = $this->getResult($page, $i, 1);
274 $print = sprintf(_(" %d%% (%d/%d)"), $percent, $count, $all);
275 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 4, 'align' => 'left'), $q)));
276 $html->pushContent(HTML::tr(HTML::td($checkbox),
278 HTML::td($this->bar($percent)),
281 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 4, 'align' => 'left'), $q)));
284 $this->storeResult($page, $i, $answers[$i]);
285 for ($j = 0; $j <= count($a); $j++) {
287 list($percent, $count, $all) = $this->getResult($page, $i, $j);
288 $print = sprintf(_(" %d%% (%d/%d)"), $percent, $count, $all);
289 $radio = HTML::input(array('type' => 'radio',
290 'name' => "answer[$i]",
293 $radio->setAttr('checked', "checked");
294 $row->pushContent(HTML::tr(HTML::td($radio),
296 HTML::td($this->bar($percent)),
300 $html->pushContent($row);
304 return HTML(HTML::h3(_("The result of this poll so far:")), $html, HTML::p(_("Thanks for participating!")));
306 return HTML(HTML::h3(_("The result of this poll so far:")), $html);
310 private function getResult($page, $i, $j)
312 $poll = $page->get("poll");
313 @$count = $poll['data']['count'][$i][$j];
314 @$all = $poll['data']['all'][$i];
315 $percent = sprintf("%d", $count * 100.0 / $all);
316 return array($percent, $count, $all);
319 private function storeResult($page, $i, $j)
321 $poll = $page->get("poll");
323 $poll = array('data' => array('count' => array(),
326 @$poll['data']['count'][$i][$j]++;
327 //@$poll['data']['all'][$i];
328 $page->set("poll", $poll);
329 $percent = sprintf("%d", $poll['data']['count'][$i][$j] * 100.0 / $poll['data']['all'][$i]);
330 return array($percent, $poll['data']['count'][$i][$j], $poll['data']['all'][$i]);
339 // c-hanging-comment-ender-p: nil
340 // indent-tabs-mode: nil