1<?php
2/**
3 * Task Plugin, tasks component: lists tasks of a given namespace
4 *
5 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author   Esther Brunner <wikidesign@gmail.com>
7 */
8
9class syntax_plugin_task_tasks extends DokuWiki_Syntax_Plugin {
10    protected $helper = NULL;
11
12    /**
13     * Constructor. Loads helper plugin.
14     */
15    public function __construct() {
16        $this->helper = plugin_load('helper', 'task');
17    }
18
19    function getType() { return 'substition'; }
20    function getPType() { return 'block'; }
21    function getSort() { return 306; }
22
23    function connectTo($mode) {
24        $this->Lexer->addSpecialPattern('\{\{tasks>.+?\}\}', $mode, 'plugin_task_tasks');
25    }
26
27    function handle($match, $state, $pos, Doku_Handler $handler) {
28        global $ID;
29
30        $match = substr($match, 8, -2); // strip {{topic> from start and }} from end
31        list($match, $flags) = explode('&', $match, 2);
32        $flags = explode('&', $flags);
33        list($match, $refine) = explode(' ', $match, 2);
34        list($ns, $filter) = explode('?', $match, 2);
35
36        if (($ns == '*') || ($ns == ':')) $ns = '';
37        elseif ($ns == '.') $ns = getNS($ID);
38        else $ns = cleanID($ns);
39
40        return array($ns, $filter, $flags, $refine);
41    }
42
43    function render($mode, Doku_Renderer $renderer, $data) {
44        global $conf;
45
46        list($ns, $filter, $flags, $refine) = $data;
47
48        if (!$filter || ($filter == 'select')) {
49            $select = true;
50            $filter = trim($_REQUEST['filter']);
51        }
52        $filter = strtolower($filter);
53        $filters = $this->_viewFilters();
54        if (!in_array($filter, $filters)) $filter = 'open';
55        if(isset($_REQUEST['view_user'])) $user = $_REQUEST['view_user'];
56
57        if ($this->helper) $pages = $this->helper->getTasks($ns, NULL, $filter, $user);
58
59        // use tag refinements?
60        if ($refine) {
61            if (plugin_isdisabled('tag') || (!$tag = plugin_load('helper', 'tag'))) {
62                msg('The Tag Plugin must be installed to use tag refinements.', -1);
63            } else {
64                $pages = $tag->tagRefine($pages, $refine);
65            }
66        }
67
68        if(!$pages) {
69            if($mode != 'xhtml') return true;
70            $renderer->nocache();
71            if($select) $renderer->doc .= $this->_viewMenu($filter);
72            if(auth_quickaclcheck($ns.':*') >= AUTH_CREATE) {
73                if(!in_array('noform', $flags)) {
74                    if ($this->helper) $renderer->doc .= $this->helper->_newTaskForm($ns);
75                }
76            }
77            return true; // nothing to display
78        }
79
80        // prepare pagination
81        $c = count($pages);
82        $perpage = ($conf['recent'] != 0) ? $conf['recent'] : 20; // prevent division by zero
83        if ($c > $perpage) {
84            $numOfPages = ceil($c / $perpage);
85            $first = $_REQUEST['first'];
86            if (!is_numeric($first)) $first = 0;
87            $currentPage = round($first / $perpage) + 1;
88            $pages = array_slice($pages, $first, $perpage);
89        }
90
91        if ($mode == 'xhtml') {
92
93            // prevent caching to ensure content is always fresh
94            $renderer->nocache();
95
96            // show form to create a new task?
97            $perm_create = (auth_quickaclcheck($ns.':*') >= AUTH_CREATE);
98            if($perm_create && ($this->getConf('tasks_formposition') == 'top')) {
99                if(!in_array('noform', $flags)) {
100                    if ($this->helper) $renderer->doc .= $this->helper->_newTaskForm($ns);
101                }
102            }
103
104            // let Pagelist Plugin do the work for us
105            if (plugin_isdisabled('pagelist')
106                    || (!$pagelist = plugin_load('helper', 'pagelist'))) {
107                msg('The Pagelist Plugin must be installed for task lists.', -1);
108                return false;
109            }
110
111            // show view filter popup if not
112            if ($select) $renderer->doc .= $this->_viewMenu($filter);
113
114            // prepare pagelist columns
115            $pagelist->header['page'] = $this->getLang('task');
116            $pagelist->header['date'] = str_replace(' ', '&nbsp;', $this->getLang('date'));
117            $pagelist->header['user'] = str_replace(' ', '&nbsp;', $this->getLang('user'));
118            $pagelist->column['date'] = $this->getConf('datefield');
119            $pagelist->column['user'] = true;
120            $pagelist->setFlags($flags);
121            $pagelist->addColumn('task', 'status');
122
123            // output list
124            $pagelist->startList();
125            if($this->getConf('tasks_newestfirst')) {
126                $pages = array_reverse($pages);
127            }
128            foreach ($pages as $page) {
129                $pagelist->addPage($page);
130            }
131            $renderer->doc .= $pagelist->finishList();
132            $renderer->doc .= $this->_paginationLinks($numOfPages, $currentPage, $filter);
133
134            // show form to create a new task?
135            if($perm_create && ($this->getConf('tasks_formposition') == 'bottom')) {
136                if(!in_array('noform', $flags)) {
137                    if ($this->helper) $renderer->doc .= $this->helper->_newTaskForm($ns);
138                }
139            }
140
141            return true;
142
143            // for metadata renderer
144        } elseif ($mode == 'metadata') {
145            foreach ($pages as $page) {
146                $renderer->meta['relation']['references'][$page['id']] = true;
147            }
148
149            return true;
150        }
151        return false;
152    }
153
154/* ---------- (X)HTML Output Functions ---------- */
155
156    /**
157     * Show a popup to select the task view filter.
158     * Just forwards call to the old or new function.
159     */
160    function _viewMenu($filter) {
161        if (class_exists('dokuwiki\Form\Form')) {
162            return $this->_viewMenuNew($filter);
163        } else {
164            return $this->_viewMenuOld($filter);
165        }
166    }
167
168    /**
169     * Show a popup to select the task view filter.
170     * This is the new version using class dokuwiki\Form\Form.
171     *
172     * @see _viewMenu
173     */
174    function _viewMenuNew($filter) {
175        global $ID, $lang;
176
177        $options = $this->_viewFilters();
178
179        $form = new dokuwiki\Form\Form(array('id' => 'task__changeview_form'));
180        $pos = 1;
181
182        $form->addHTML('<label class="simple">', $pos++);
183        $form->addHTML('<span>'.$this->getLang('view').'</span>', $pos++);
184
185        // Set hidden fields
186        $form->setHiddenField ('id', $ID);
187        $form->setHiddenField ('do', 'show');
188
189        // Select status from drop down list
190        $dropDownOptions = array();
191        $selected = NULL;
192        $value = 0;
193        foreach ($options as $option) {
194            if ($filter == $option) {
195                $selected = $option.' ';
196            }
197            $dropDownOptions [$option.' '] = $this->getLang('view_'.$option);
198        }
199        $input = $form->addDropdown('filter', $dropDownOptions, NULL, $pos++);
200        $input->val($selected);
201
202        $form->addHTML('</label>', $pos++);
203
204        if(isset($_SERVER['REMOTE_USER'])) {
205            $form->addHTML('<label class="simple"><span>'.$this->getLang('view_user').':</span>', $pos++);
206            $input = $form->addCheckbox('view_user', NULL, $pos++);
207            $input->attr('value', $_SERVER['REMOTE_USER']);
208            if ($_REQUEST['view_user']) {
209                $input->attr('checked', 'checked');
210            }
211            $form->addHTML('</label>', $pos++);
212        }
213
214        // Add button
215        $form->addButton(NULL, $this->getLang('btn_refresh'), $pos++);
216
217        $ret  = '<div class="task_viewmenu">';
218        $ret .= $form->toHTML();
219        $ret .= '</div>';
220
221        return $ret;
222    }
223
224    /**
225     * Show a popup to select the task view filter.
226     * Old function generating all HTML on its own.
227     *
228     * @see _viewMenu
229     */
230    function _viewMenuOld($filter) {
231        global $ID, $lang;
232
233        $options = $this->_viewFilters();
234
235        $ret  = '<div class="task_viewmenu">';
236        $ret .= '<form id="task__changeview_form" method="post" action="'.script().'" accept-charset="'.$lang['encoding'].'">';
237        $ret .= '<label class="simple">';
238        $ret .= '<span>'.$this->getLang('view').'</span>';
239        $ret .= '<input type="hidden" name="id" value="'.$ID.'" />';
240        $ret .= '<input type="hidden" name="do" value="show" />';
241        $ret .= '<select name="filter" size="1" class="edit">';
242
243        foreach ($options as $option) {
244            $ret .= '<option value="'.$option.'"';
245            if ($filter == $option) $ret .= ' selected="selected"';
246            $ret .= '>'.$this->getLang('view_'.$option).'</option>';
247        }
248
249        $ret .= '</select>';
250        $ret .= '</label>';
251
252        if(isset($_SERVER['REMOTE_USER'])) {
253            $ret .= '<label class="simple"><span>'.$this->getLang('view_user').':</span>';
254            $ret .= '<input type="checkbox" name="view_user" value="' . $_SERVER['REMOTE_USER'] . '"';
255            $ret .= ($_REQUEST['view_user']) ? ' checked="checked"' : '';
256            $ret .= '/></label>';
257        }
258
259        $ret .= '<input class="button" type="submit" value="'.$this->getLang('btn_refresh').'" />';
260        $ret .= '</form></div>';
261
262        return $ret;
263    }
264
265   /**
266    * Returns an array of available view filters for the task list
267    */
268    function _viewFilters() {
269        if (!$_SERVER['REMOTE_USER']) $filters = array('all', 'open', 'done');
270        else $filters = array('all', 'open', 'new', 'done', 'my', 'rejected', 'started', 'accepted', 'verified');
271        if ($this->getConf('datefield')) {
272            $filters[] = 'due';
273            $filters[] = 'overdue';
274        }
275        return $filters;
276    }
277
278    /**
279    * Returns pagination links if more than one page
280    */
281    function _paginationLinks($num, $cur, $filter) {
282        global $ID, $conf;
283
284        if (!is_numeric($num) || ($num < 2)) return '';
285        $perpage = ($conf['recent'] != 0) ? $conf['recent'] : 20; // prevent division by zero
286
287        $ret = array();
288        for ($i = 1; $i <= $num; $i++) {
289            if ($i == $cur) {
290                $ret[] = '<strong>'.$i.'</strong>';
291            } else {
292                $opt = array();
293                $opt['first']  = $perpage * ($i - 1);
294                $opt['filter'] = $filer;
295                if(isset($_REQUEST['view_user'])) {
296                    $user = array();
297                    $user['id'] = $_REQUEST['view_user'];
298                    if($this->helper->_isResponsible($user)) {
299                        $opt['view_user'] = $_REQUEST['view_user'];
300                    }
301                }
302                $ret[] = '<a href="'.wl($ID, $opt).'" class="wikilink1" title="'.$i.'">'.$i.'</a>';
303            }
304        }
305        return '<div class="centeralign">'.DOKU_LF.
306            join(' | ', $ret).DOKU_LF.
307            '</div>'.DOKU_LF;
308    }
309}
310// vim:et:ts=4:sw=4:enc=utf-8:
311