1<?php
2/**
3 * Poll Plugin: allows to create simple polls
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Esther Brunner <wikidesign@gmail.com>
7 */
8
9if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
10if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
11require_once(DOKU_PLUGIN.'syntax.php');
12
13/**
14 * All DokuWiki plugins to extend the parser/rendering mechanism
15 * need to inherit from this class
16 */
17class syntax_plugin_poll extends DokuWiki_Syntax_Plugin {
18
19    function getType() { return 'substition';}
20    function getPType() { return 'block';}
21    function getSort() { return 167; }
22
23    /**
24     * Connect pattern to lexer
25     */
26    function connectTo($mode) {
27        $this->Lexer->addSpecialPattern('<poll.*?>.+?</poll>', $mode, 'plugin_poll');
28    }
29
30    /**
31     * Handle the match
32     */
33    function handle($match, $state, $pos, Doku_Handler $handler) {
34        $match = substr($match, 6, -7);  // strip markup
35        list($title, $options) = preg_split('/>/u', $match, 2);
36        if (!$options) {
37            $options = $title;
38            $title   = NULL;
39        }
40        $options = explode('*', $options);
41
42        $c = count($options);
43        for ($i = 0; $i < $c; $i++) {
44            $options[$i] = trim($options[$i]);
45        }
46
47        return array(trim($title), $options);
48    }
49
50    /**
51     * Create output
52     */
53    function render($mode, Doku_Renderer $renderer, $data) {
54
55        if ($mode == 'xhtml') {
56            global $ID;
57
58            $options = $data[1];
59            $title   = $renderer->_xmlEntities($data[0]);
60
61            // prevent caching to ensure the poll results are fresh
62            $renderer->info['cache'] = false;
63
64            // get poll file contents
65            $pfile = metaFN(md5($title), '.poll');
66            $poll  = unserialize(@file_get_contents($pfile));
67
68            // output the poll
69            $renderer->doc .= '<fieldset class="poll">'.
70                '<legend>'.$title.'</legend>';
71            $more = trim(array_shift($options));
72            if ($more) {
73                $renderer->doc .= '<div>'.$renderer->_xmlEntities($more).'</div>';
74            }
75
76            // check if user has voted already
77            $ip = clientIP(true);
78            if (isset($poll['ips']) && in_array($ip, $poll['ips'])) {
79
80                // display results
81                $renderer->doc .= $this->_pollResults($poll);
82
83            } elseif ($vote = $_REQUEST['vote']) {
84
85                // user has just voted -> update results
86                $c = count($options);
87                for ($i = 0; $i < $c; $i++) {
88                    $opt = $renderer->_xmlEntities($options[$i]);
89                    if ($vote == $opt) {
90                        $poll['results'][$opt] += 1;
91                        $poll['votes'] += 1;
92                        $poll['ips'][] = $ip;
93                    } elseif (!isset($poll['results'][$opt])) {
94                        $poll['results'][$opt] = 0;
95                    }
96                }
97                $fh = fopen($pfile, 'w');
98                fwrite($fh, serialize($poll));
99                fclose($fh);
100
101                // display results
102                $renderer->doc .= $this->_pollResults($poll);
103
104            } elseif (count($options) > 0) {
105
106                // display poll form
107                $renderer->doc .= $this->_pollForm($options, $renderer);
108
109            } else {
110
111                // display results
112                $renderer->doc .= $this->_pollResults($poll);
113
114            }
115            $renderer->doc .= '</fieldset>';
116
117            return true;
118        }
119        return false;
120    }
121
122    function _pollResults($poll) {
123        $total = $poll['votes'];
124        if ($total == 0) return '';
125
126        $ret = '<table class="blind">';
127        $c = count($poll['results']);
128        $options = array_keys($poll['results']);
129        $votes   = array_values($poll['results']);
130        for ($i = 0; $i < $c; $i++) {
131            $absolute = $votes[$i];
132            $percent  = round(($absolute*100)/$total);
133            $ret .= '<tr><td>'.$options[$i].'</td><td><div class="poll_bar">';
134            if ($percent) $ret .= '<div class="poll_full" style="width:'.($percent*2).'px">&nbsp;</div>';
135            $ret .= '</div></td><td class="rightalign">'.$percent.'%</td>'.
136                '<td class="rightalign">('.$absolute.')</td></tr>';
137        }
138        $ret .= '</table>';
139
140        return $ret;
141    }
142
143    function _pollForm($options, &$renderer) {
144        global $lang;
145        global $ID;
146
147        $i = 0;
148        $ret = '<form id="poll__form" method="post" action="'.script().'" accept-charset="'.$lang['encoding'].'"><div class="no">'.
149            '<input type="hidden" name="do" value="show" />'.
150            '<input type="hidden" name="id" value="'.$ID.'" />';
151        foreach ($options as $option) {
152            $i++;
153            $option = $renderer->_xmlEntities($option);
154            $ret.= '<label class="simple" for="poll__option'.$i.'">'.
155                '<input type="radio" name="vote" id="poll__option'.$i.'" '.
156                'value="'.$option.'" /> <span>'.$option.'</span></label>';
157        }
158        $ret .= '<input class="button" type="submit" '.
159            'value="'.$this->getLang('btn_vote').'" />'.
160            '</div></form>';
161
162        return $ret;
163    }
164}
165// vim:ts=4:sw=4:et:enc=utf-8:
166