1<?php
2/**
3 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 * @author     Esther Brunner <wikidesign@gmail.com>
5 * @author     Gina Häußge <osd@foosel.net>
6 */
7
8class helper_plugin_pagelist extends DokuWiki_Plugin {
9
10    /* public */
11
12    var $page       = NULL;    // associative array for page to list
13    // must contain a value to key 'id'
14    // can contain: 'title', 'date', 'user', 'desc', 'comments',
15    // 'tags', 'status' and 'priority'
16
17    var $style      = '';      // table style: 'default', 'table', 'list'
18    var $showheader = false;   // show a heading line
19    var $column     = array(); // which columns to show
20    var $header     = array(); // language strings for table headers
21    var $sort       = false;   // alphabetical sort of pages by pagename
22    var $rsort      = false;   // reverse alphabetical sort of pages by pagename
23
24    var $plugins    = array(); // array of plugins to extend the pagelist
25    var $discussion = NULL;    // discussion class object
26    var $tag        = NULL;    // tag class object
27
28    var $doc        = '';      // the final output XHTML string
29
30    /* private */
31
32    var $_meta      = NULL;    // metadata array for page
33
34    /**
35     * Constructor gets default preferences
36     *
37     * These can be overriden by plugins using this class
38     */
39    function __construct() {
40        $this->style       = $this->getConf('style');
41        $this->showheader  = $this->getConf('showheader');
42        $this->showfirsthl = $this->getConf('showfirsthl');
43        $this->sort        = $this->getConf('sort');
44        $this->rsort       = $this->getConf('rsort');
45
46        $this->column = array(
47                'page'     => true,
48                'date'     => $this->getConf('showdate'),
49                'user'     => $this->getConf('showuser'),
50                'desc'     => $this->getConf('showdesc'),
51                'comments' => $this->getConf('showcomments'),
52                'linkbacks'=> $this->getConf('showlinkbacks'),
53                'tags'     => $this->getConf('showtags'),
54                'image'    => $this->getConf('showimage'),
55                'diff'     => $this->getConf('showdiff'),
56                );
57
58        $this->plugins = array(
59                'discussion' => 'comments',
60                'linkback'   => 'linkbacks',
61                'tag'        => 'tags',
62                'pageimage'  => 'image',
63                );
64    }
65
66    function getMethods() {
67        $result = array();
68        $result[] = array(
69                'name'   => 'addColumn',
70                'desc'   => 'adds an extra column for plugin data',
71                'params' => array(
72                    'plugin name' => 'string',
73                    'column key' => 'string'),
74                );
75        $result[] = array(
76                'name'   => 'setFlags',
77                'desc'   => 'overrides standard values for showfooter and firstseconly settings',
78                'params' => array('flags' => 'array'),
79                'return' => array('success' => 'boolean'),
80                );
81        $result[] = array(
82                'name'   => 'startList',
83                'desc'   => 'prepares the table header for the page list',
84                );
85        $result[] = array(
86                'name'   => 'addPage',
87                'desc'   => 'adds a page to the list',
88                'params' => array("page attributes, 'id' required, others optional" => 'array'),
89                );
90        $result[] = array(
91                'name'   => 'finishList',
92                'desc'   => 'returns the XHTML output',
93                'return' => array('xhtml' => 'string'),
94                );
95        return $result;
96    }
97
98    /**
99     * Adds an extra column for plugins
100     */
101    function addColumn($plugin, $col) {
102        $this->plugins[$plugin] = $col;
103        $this->column[$col]     = true;
104    }
105
106    /**
107     * Overrides standard values for style, showheader and show(column) settings
108     */
109    function setFlags($flags) {
110        if (!is_array($flags)) return false;
111
112        $columns = array('date', 'user', 'desc', 'comments', 'linkbacks', 'tags', 'image', 'diff');
113        foreach ($flags as $flag) {
114            switch ($flag) {
115                case 'default':
116                    $this->style = 'default';
117                    break;
118                case 'table':
119                    $this->style = 'table';
120                    break;
121                case 'list':
122                    $this->style = 'list';
123                    break;
124                case 'simplelist':
125                    $this->style = 'simplelist'; // Displays pagenames only, no other information
126                    break;
127                case 'header':
128                    $this->showheader = true;
129                    break;
130                case 'noheader':
131                    $this->showheader = false;
132                    break;
133                case 'firsthl':
134                    $this->showfirsthl = true;
135                    break;
136                case 'nofirsthl':
137                    $this->showfirsthl = false;
138                    break;
139                case 'sort':
140                    $this->sort = true;
141                    $this->rsort = false;
142                    break;
143                case 'rsort':
144                    $this->sort = false;
145                    $this->rsort = true;
146                    break;
147                case 'nosort':
148                    $this->sort = false;
149                    $this->rsort = false;
150                    break;
151                case 'showdiff':
152                    $flag = 'diff';
153                    break;
154            }
155
156            if (substr($flag, 0, 2) == 'no') {
157                $value = false;
158                $flag  = substr($flag, 2);
159            } else {
160                $value = true;
161            }
162
163            if (in_array($flag, $columns)) $this->column[$flag] = $value;
164        }
165        return true;
166    }
167
168    /**
169     * Sets the list header
170     */
171    function startList($callerClass=NULL) {
172
173        // table style
174        switch ($this->style) {
175            case 'table':
176                $class = 'inline';
177                break;
178            case 'list':
179                $class = 'ul';
180                break;
181            case 'simplelist':
182                $class = false;
183                break;
184            default:
185                $class = 'pagelist';
186        }
187
188        if($class) {
189            if ($callerClass) {
190                $class .= ' '.$callerClass;
191            }
192            $this->doc = '<div class="table">'.DOKU_LF.'<table class="'.$class.'">'.DOKU_LF;
193        } else {
194            // Simplelist is enabled; Skip header and firsthl
195            $this->showheader = false;
196            $this->showfirsthl = false;
197            //$this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
198            $this->doc = '<ul>';
199        }
200
201        $this->page = NULL;
202
203        // check if some plugins are available - if yes, load them!
204        foreach ($this->plugins as $plug => $col) {
205            if (!$this->column[$col]) continue;
206            if (plugin_isdisabled($plug) || (!$this->$plug = plugin_load('helper', $plug)))
207                $this->column[$col] = false;
208        }
209
210        // header row
211        if ($this->showheader) {
212            $this->doc .= DOKU_TAB.'<tr>'.DOKU_LF.DOKU_TAB.DOKU_TAB;
213            $columns = array('page', 'date', 'user', 'desc', 'diff');
214            if ($this->column['image']) {
215                if (!$this->header['image']) $this->header['image'] = hsc($this->pageimage->th());
216                    $this->doc .= '<th class="images">'.$this->header['image'].'</th>';
217            }
218            foreach ($columns as $col) {
219                if ($this->column[$col]) {
220                    if (!$this->header[$col]) $this->header[$col] = hsc($this->getLang($col));
221                    $this->doc .= '<th class="'.$col.'">'.$this->header[$col].'</th>';
222                }
223            }
224            foreach ($this->plugins as $plug => $col) {
225                if ($this->column[$col] && $col != 'image') {
226                    if (!$this->header[$col]) $this->header[$col] = hsc($this->$plug->th());
227                    $this->doc .= '<th class="'.$col.'">'.$this->header[$col].'</th>';
228                }
229            }
230            $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
231        }
232        return true;
233    }
234
235    /**
236     * Sets a list row
237     */
238    function addPage($page) {
239
240        $id = $page['id'];
241        if (!$id) return false;
242        $this->page = $page;
243        $this->_meta = NULL;
244
245        if($this->style != 'simplelist') {
246            // priority and draft
247            if (!isset($this->page['draft'])) {
248                $this->page['draft'] = ($this->_getMeta('type') == 'draft');
249            }
250            $class = '';
251            if (isset($this->page['priority'])) $class .= 'priority'.$this->page['priority']. ' ';
252            if ($this->page['draft']) $class .= 'draft ';
253            if ($this->page['class']) $class .= $this->page['class'];
254            if(!empty($class)) $class = ' class="' . $class . '"';
255
256            $this->doc .= DOKU_TAB.'<tr'.$class.'>'.DOKU_LF;
257            if ($this->column['image']) $this->_pluginCell('pageimage','image',$id);
258            $this->_pageCell($id);
259            if ($this->column['date']) $this->_dateCell();
260            if ($this->column['user']) $this->_userCell();
261            if ($this->column['desc']) $this->_descCell();
262            if ($this->column['diff']) $this->_diffCell($id);
263            foreach ($this->plugins as $plug => $col) {
264                if ($this->column[$col] && $col != 'image') $this->_pluginCell($plug, $col, $id);
265            }
266
267            $this->doc .= DOKU_TAB.'</tr>'.DOKU_LF;
268        } else {
269            $class = '';
270            // simplelist is enabled; just output pagename
271            $this->doc .= DOKU_TAB . '<li>' . DOKU_LF;
272            if(page_exists($id)) $class = 'wikilink1';
273            else $class = 'wikilink2';
274
275            if (!$this->page['title']) $this->page['title'] = str_replace('_', ' ', noNS($id));
276            $title = hsc($this->page['title']);
277
278            $content = '<a href="'.wl($id).'" class="'.$class.'" title="'.$id.'">'.$title.'</a>';
279            $this->doc .= $content;
280            $this->doc .= DOKU_TAB . '</li>' . DOKU_LF;
281        }
282
283        return true;
284    }
285
286    /**
287     * Sets the list footer
288     */
289    function finishList() {
290        if($this->style != 'simplelist') {
291            if (!isset($this->page)) $this->doc = '';
292            else $this->doc .= '</table>'.DOKU_LF.'</div>'.DOKU_LF;
293        } else {
294            $this->doc .= '</ul>' . DOKU_LF;
295        }
296
297        // reset defaults
298        $this->__construct();
299
300        return $this->doc;
301    }
302
303    /* ---------- Private Methods ---------- */
304
305    /**
306     * Page title / link to page
307     */
308    function _pageCell($id) {
309
310        // check for page existence
311        if (!isset($this->page['exists'])) {
312            if (!isset($this->page['file'])) $this->page['file'] = wikiFN($id);
313            $this->page['exists'] = @file_exists($this->page['file']);
314        }
315        if ($this->page['exists']) $class = 'wikilink1';
316        else $class = 'wikilink2';
317
318        // handle image and text titles
319        if ($this->page['titleimage']) {
320            $title = '<img src="'.ml($this->page['titleimage']).'" class="media"';
321            if ($this->page['title']) $title .= ' title="'.hsc($this->page['title']).'"'.
322                ' alt="'.hsc($this->page['title']).'"';
323            $title .= ' />';
324        } else {
325            if($this->showfirsthl) {
326                $this->page['title'] = $this->_getMeta('title');
327            } else {
328                $this->page['title'] = $id;
329            }
330
331            if (!$this->page['title']) $this->page['title'] = str_replace('_', ' ', noNS($id));
332            $title = hsc($this->page['title']);
333        }
334
335        // produce output
336        $content = '<a href="'.wl($id).($this->page['section'] ? '#'.$this->page['section'] : '').
337            '" class="'.$class.'" title="'.$id.'">'.$title.'</a>';
338        if ($this->style == 'list') $content = '<ul><li>'.$content.'</li></ul>';
339        return $this->_printCell('page', $content);
340    }
341
342    /**
343     * Date - creation or last modification date if not set otherwise
344     */
345    function _dateCell() {
346        global $conf;
347
348        if($this->column['date'] == 2) {
349            $this->page['date'] = $this->_getMeta(array('date', 'modified'));
350        } elseif(!$this->page['date'] && $this->page['exists']) {
351            $this->page['date'] = $this->_getMeta(array('date', 'created'));
352        }
353
354        if ((!$this->page['date']) || (!$this->page['exists'])) {
355            return $this->_printCell('date', '');
356        } else {
357            return $this->_printCell('date', dformat($this->page['date'], $conf['dformat']));
358        }
359    }
360
361    /**
362     * User - page creator or contributors if not set otherwise
363     */
364    function _userCell() {
365        if (!array_key_exists('user', $this->page)) {
366            if ($this->column['user'] == 2) {
367                $users = $this->_getMeta('contributor');
368                if (is_array($users)) $this->page['user'] = join(', ', $users);
369            } else {
370                $this->page['user'] = $this->_getMeta('creator');
371            }
372        }
373        return $this->_printCell('user', hsc($this->page['user']));
374    }
375
376    /**
377     * Description - (truncated) auto abstract if not set otherwise
378     */
379    function _descCell() {
380        if (array_key_exists('desc', $this->page)) {
381            $desc = $this->page['desc'];
382        } elseif (strlen($this->page['description']) > 0) {
383            // This condition will become true, when a page-description is given
384            // inside the syntax-block
385            $desc = $this->page['description'];
386        } else {
387            $desc = $this->_getMeta(array('description', 'abstract'));
388        }
389
390        $max = $this->column['desc'];
391        if (($max > 1) && (utf8_strlen($desc) > $max)) $desc = utf8_substr($desc, 0, $max).'…';
392        return $this->_printCell('desc', hsc($desc));
393    }
394
395    /**
396     * Diff icon / link to diff page
397     */
398    function _diffCell($id) {
399        // check for page existence
400        if (!isset($this->page['exists'])) {
401            if (!isset($this->page['file'])) $this->page['file'] = wikiFN($id);
402            $this->page['exists'] = @file_exists($this->page['file']);
403        }
404
405        // produce output
406        $url_params = array();
407        $url_params ['do'] = 'diff';
408        $content = '<a href="'.wl($id, $url_params).($this->page['section'] ? '#'.$this->page['section'] : '').'" class="diff_link">
409<img src="/lib/images/diff.png" width="15" height="11" title="'.hsc($this->getLang('diff_title')).'" alt="'.hsc($this->getLang('diff_alt')).'"/>
410</a>';
411        return $this->_printCell('page', $content);
412    }
413
414    /**
415     * Plugins - respective plugins must be installed!
416     */
417    function _pluginCell($plug, $col, $id) {
418        if (!isset($this->page[$col])) $this->page[$col] = $this->$plug->td($id);
419        return $this->_printCell($col, $this->page[$col]);
420    }
421
422    /**
423     * Produce XHTML cell output
424     */
425    function _printCell($class, $content) {
426        if (!$content) {
427            $content = '&nbsp;';
428            $empty   = true;
429        } else {
430            $empty   = false;
431        }
432        $this->doc .= DOKU_TAB.DOKU_TAB.'<td class="'.$class.'">'.$content.'</td>'.DOKU_LF;
433        return (!$empty);
434    }
435
436
437    /**
438     * Get default value for an unset element
439     */
440    function _getMeta($key) {
441        if (!$this->page['exists']) return false;
442        if (!isset($this->_meta)) $this->_meta = p_get_metadata($this->page['id'], '', METADATA_RENDER_USING_CACHE);
443        if (is_array($key)) return $this->_meta[$key[0]][$key[1]];
444        else return $this->_meta[$key];
445    }
446
447}
448// vim:ts=4:sw=4:et:
449