1<?php
2/**
3 * DokuWiki Plugin nsindex (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Oliver Geisen <oliver@rehkopf-geisen.de>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die();
11
12class syntax_plugin_nsindex extends DokuWiki_Syntax_Plugin {
13    /**
14     * @return string Syntax mode type
15     */
16    public function getType() {
17        return 'substition';
18    }
19    /**
20     * @return string Paragraph type
21     */
22    public function getPType() {
23        return 'normal';
24    }
25    /**
26     * @return int Sort order - Low numbers go before high numbers
27     */
28    public function getSort() {
29        return 200;
30    }
31
32    /**
33     * Connect lookup pattern to lexer.
34     *
35     * @param string $mode Parser mode
36     */
37    public function connectTo($mode) {
38        $this->Lexer->addSpecialPattern('{{nsindex[^}]*}}',$mode,'plugin_nsindex');
39    }
40
41    /**
42     * Handle matches of the nsindex syntax
43     *
44     * @param string          $match   The match of the syntax
45     * @param int             $state   The state of the handler
46     * @param int             $pos     The position in the document
47     * @param Doku_Handler    $handler The handler
48     * @return array Data for the renderer
49     */
50    public function handle($match, $state, $pos, Doku_Handler $handler) {
51        $data = $this->_get_defaults();
52
53        /**
54         * parse options and override defaults
55         */
56        $match = explode(',',trim(substr($match,9,-2)));
57        foreach ($match as $m)
58        {
59            if (strstr($m, '=')) {
60                list($opt,$val) = explode('=', $m);
61            } else {
62                $opt = $m;
63                $val = true;
64            }
65            if (array_key_exists($m, $data))
66            {
67                $data[$opt] = $val;
68            }
69        }
70
71        return $data;
72    }
73
74    /**
75     * Render xhtml output or metadata
76     *
77     * @param string         $mode      Renderer mode (supported modes: xhtml)
78     * @param Doku_Renderer  $renderer  The renderer
79     * @param array          $data      The data from the handler() function
80     * @return bool If rendering was successful.
81     */
82    public function render($mode, Doku_Renderer $renderer, $data) {
83        if($mode != 'xhtml') return false;
84
85        global $conf;
86
87        // Never cache the result to get fresh info
88        $renderer->info['cache'] = false;
89
90        // Do not add section edit buttons unter group headers
91        $oldmaxecl = $conf['maxseclevel'];
92        $conf['maxseclevel'] = 0;
93
94        // To see the TOC, to not use ~~NOTOC~~
95        if ($renderer->info['toc']) {
96            $oldmaxtoc = $conf['maxtoclevel'];
97            $conf['maxtoclevel'] = 3;
98        } else {
99            $oldmaxtoc = -1;
100        }
101
102        // Build the list
103        $data = $this->_build_index($data, $renderer);
104
105        // Translate text to HTML for DW page
106        $data = p_render('xhtml', p_get_instructions($data), $_dummy);
107
108        // Append to current page
109        $renderer->doc .= '<div id="nsindex">' ;
110        $renderer->doc .= $data;
111        $renderer->doc .= '</div>' ;
112
113        // restore edit level and TOC
114        $conf['maxseclevel'] = $oldmaxecl;
115        if ($oldmaxtoc == -1) {
116            $conf['maxtoclevel'] = $oldmaxtoc;
117        }
118
119        return true;
120    }
121
122    //------------------------------------------------------------------------//
123
124    /**
125     * Default options for nsindex
126     */
127    private function _get_defaults() {
128        return array(
129            'nons'       => false,  // exclude start-page of namespaces found
130            'nopages'    => false,  // exclude all pages found, include only startpage of sub-namespaces
131            'nogroup'    => false,  // do not add alpha-index headings in list
132            'notemplate' => false,  // omitt pages with names like 'template' or '__template' or '_template'
133            'startns'    => '.',    // where to start lookup (default is current namespace)
134        );
135    }
136
137    /**
138     * Build the index from namespace scan
139     */
140    private function _build_index($opts, &$renderer) {
141        global $conf;
142        global $ID;
143
144        // get content of namespace (pages and subdirs)
145        if ( ! $opts['startns'] || $opts['startns'] == '.') {
146            $ns = getNS($ID); # current namespace (default)
147        } else {
148            $ns = $opts['startns'];
149            resolve_pageid(getNS($ID), $ns, $exists);
150            $ns = getNS($ns);
151        }
152        $data = array();
153        $nsdir = str_replace(':','/',$ns);
154        search($data,$conf['datadir'],'search_index',array(),$nsdir,1);
155
156        // filter and sort the list
157        $sort = array();
158        foreach ($data as $i=>$item) {
159
160            if (noNS($item['id']) == $conf['start']) {
161                continue;  # ignore index-page of current namespace
162            }
163
164            // get full wikipath and heading of page
165            if ($item['type'] == 'd') {
166                if ($opts['nons']) {
167                    continue;  # ignore namespace
168                }
169                $wikipath = $item['id'].':'.$conf['start'];
170                $data[$i]['id'] = $wikipath;  # change wikipath in data
171                if ($conf['useheading']) {
172                    $title = p_get_first_heading($wikipath);
173                } else {
174                    $title = '';
175                }
176                if ( ! $title) {
177                    $title = noNS(getNS($wikipath));
178                }
179            } else {  # page found
180                if ($opts['nopages']) {
181                    continue;  # ignore pages
182                }
183                $pn = noNS($item['id']);
184                if(($pn == 'template' || $pn == '_template' || $pn == '__template') && $opts['notemplate']) {
185                    continue;  # ignore template pages
186                }
187                $wikipath = $item['id'];
188                $title = p_get_first_heading($wikipath);
189                if ( ! $title) {
190                    $title = $pn;
191                }
192            }
193
194            // Check for access rights
195            if(auth_quickaclcheck($wikipath) < AUTH_READ) {
196                continue;  # no access for this page, omitt from list
197            }
198
199            // build array for later sort
200            $sortkey = cleanID($title);
201            $sort[$i] = $sortkey;
202
203            // add metadata
204            $data[$i]['title'] = $title;
205            $data[$i]['sortkey'] = $sortkey;
206            $data[$i]['sortgroup'] = substr($sortkey,0,1);
207        }
208
209        // sort the indexed pages
210        asort($sort);
211
212        // build pagesource of list
213        $txt = '';
214        $current_letter = '';
215        foreach ($sort as $i=>$sortkey) {
216            $title = $data[$i]['title'];
217
218            // show alpha-groups
219            if ( ! $opts['nogroup']) {
220                $first = strtoupper(substr($data[$i]['sortkey'],0,1));
221                if ($first != $current_letter) {
222                    $current_letter = $first;
223                    $txt .= '===== '.$current_letter.' ====='."\n";
224                }
225            }
226
227            $txt .= '  * [['.$data[$i]['id'].']]'."\n";
228        }
229
230        return $txt;
231    }
232}
233
234// vim:ts=4:sw=4:et:
235