1<?php
2
3/**
4 * Info Alphaindex: Displays the alphabetical index of a specified namespace.
5 *
6 * Version: 1.2
7 * last modified: 2006-06-14 12:00:00
8 * @license     GPL 2 (http://www.gnu.org/licenses/gpl.html)
9 * @author      Hubert Molière  <hubert.moliere@alternet.fr>
10 * Modified by  Nicolas H. <prog@a-et-n.com>
11 * Modified by  Jonesy <jonesy@oryma.org>
12 * Modified by  Samuele Tognini <samuele@netsons.org>
13 */
14
15if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
16if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
17require_once(DOKU_PLUGIN.'syntax.php');
18require_once(DOKU_INC.'inc/search.php');
19
20/**
21 * All DokuWiki plugins to extend the parser/rendering mechanism
22 * need to inherit from this class
23 */
24class syntax_plugin_alphaindex extends DokuWiki_Syntax_Plugin {
25
26    function getType(){ return 'substition';}
27
28    function getAllowedTypes() { return array('baseonly', 'substition', 'formatting', 'paragraphs', 'protected'); }
29
30    function getPType() { return 'block'; }
31
32    /**
33     * Where to sort in?
34     */
35    function getSort(){
36        return 139;
37    }
38
39    /**
40     * Connect pattern to lexer
41     */
42    function connectTo($mode) {
43        $this->Lexer->addSpecialPattern('{{alphaindex>.+?}}',$mode,'plugin_alphaindex');
44    }
45
46    /**
47     * Handle the match
48     */
49    function handle($match, $state, $pos, Doku_Handler $handler){
50        $level = 0;
51        $nons = true;
52        $match = substr($match, 13, -2);
53
54        // split namespaces
55        $match = preg_split('/\|/u', $match, 2);
56
57        // split level
58        $ns_opt = preg_split('/\#/u', $match[0], 2);
59
60        // namespace name
61        $ns = $ns_opt[0];
62
63        // add @NS@ option
64        if(empty($ns) || $ns == '@NS@') {
65            $pos = strrpos($ID,':');
66              if($pos != false){
67	                $ns = substr($ID,0,$pos);
68              } else {
69	              $ns = '.';
70              }
71        }
72
73        // level;
74        if (is_numeric($ns_opt[1])) {
75            $level = $ns_opt[1];
76        }
77
78        $match = explode(" ", $match[1]);
79
80        // namespaces option
81        $nons = in_array('nons', $match);
82
83        // multi-columns option
84        $incol = in_array('incol', $match);
85
86        return array($ns, array('level' => $level, 'nons' => $nons, 'incol' => $incol));
87    }
88
89    /**
90     * Render output
91     */
92    function render($mode, Doku_Renderer $renderer, $data) {
93        global $conf;
94
95        if($mode == 'xhtml'){
96            $alpha_data = $this->_alpha_index($data, $renderer);
97            if ((!@$n)) {
98                if ($this->getConf('empty_msg')) {
99                    $n = $this->getConf('empty_msg');
100                } else {
101                    $n = 'No index for <b>{{ns}}</b>';
102                }
103            }
104
105            $alpha_data = str_replace('{{ns}}', cleanID($data[0]), $alpha_data);
106
107            $alpha_data = p_render('xhtml', p_get_instructions($alpha_data), $info);
108
109            // remove toc, section edit buttons and category tags
110            $patterns = array('!<div class="toc">.*?(</div>\n</div>)!s',
111                            '#<!-- SECTION \[(\d*-\d*)\] -->#e',
112                            '!<div class="category">.*?</div>!s');
113            $replace  = array('','','');
114            $alpha_data = preg_replace($patterns, $replace, $alpha_data);
115            $renderer->doc .= '<div id="alphaindex_content">' ;
116            $renderer->doc .= $ns_data;
117            $renderer->doc .= '<hr />';
118            $renderer->doc .= $alpha_data;
119            $renderer->doc .= '</div>' ;
120            return true;
121        }
122
123        return false;
124    }
125
126    /**
127     * Return the alphabetical index
128     * @author Hubert MOLIERE <hubert.moliere@alternet.fr>
129     *
130     * This function is a hack of Indexmenu _tree_menu($ns)
131     * @author Samuele Tognini <samuele@samuele.netsons.org>
132     *
133     * This function is a simple hack of DokuWiki html_index($ns)
134     * @author Andreas Gohr <andi@splitbrain.org>
135     */
136    function _alpha_index($myns, &$renderer) {
137        global $conf;
138        global $ID;
139
140        $ns = $myns[0];
141        $opts = $myns[1];
142
143        // Articles deletion configuration
144        $articlesDeletionPatterns = array();
145        if($this->getConf('articles_deletion')) {
146            $articlesDeletionPatterns = explode('|', $this->getConf('articles_deletion'));
147            $articlesDeletion = true;
148        } else {
149            $articlesDeletion = false;
150        }
151
152        // Hide pages configuration
153        $hidepages = array();
154        if($this->getConf('hidepages')) {
155            $hidepages = explode('|', $this->getConf('hidepages'));
156        }
157
158        // template configuration
159        if($this->getConf('title_tpl')) {
160            $titleTpl = $this->getConf('title_tpl');
161        } else {
162            $titleTpl = '===== Index =====';
163        }
164
165        if($this->getConf('begin_letter_tpl')) {
166            $beginLetterTpl = $this->getConf('begin_letter_tpl');
167        } else {
168            $beginLetterTpl = '==== {{letter}} ====';
169        }
170
171        if($this->getConf('entry_tpl')) {
172            $entryTpl = $this->getConf('entry_tpl');
173        } else {
174            $entryTpl = '  * [[{{link}}|{{name}}]]';
175        }
176
177        if($this->getConf('end_letter_tpl')) {
178            $endLetterTpl = $this->getConf('end_letter_tpl');
179        } else {
180            $endLetterTpl = '';
181        }
182
183        if($ns == '.') {
184            $ns = dirname(str_replace(':','/',$ID));
185            if ($ns == '.') $ns = '';
186        } else {
187            $ns = cleanID($ns);
188        }
189
190        $ns  = utf8_encodeFN(str_replace(':','/',$ns));
191        $data = array();
192        // Searches for files below the given datadir and calls for every file the function alphaindex_search_index
193        search($data, $conf['datadir'], 'alphaindex_search_index', $opts, "/" . $ns);
194
195        $nb_data = count($data);
196        $alpha_data = array();
197
198        // alphabetical ordering
199        for($cpt = 0; $cpt <$nb_data; $cpt++) {
200            $tmpData = $data[$cpt]['id'];
201
202            $pos = strrpos(utf8_decode($tmpData), ':');
203            if($conf['useheading']) {
204                $pageName = p_get_first_heading($tmpData);
205
206                if($pageName == NULL) {
207                    if($pos != FALSE) {
208                        $pageName = utf8_substr($tmpData, $pos+1, utf8_strlen($tmpData));
209                    } else {
210                        $pageName = $tmpData;
211                    }
212                    $pageName = str_replace('_', ' ', $pageName);
213                }
214            } else {
215                if($pos != FALSE) {
216                    $pageName = utf8_substr($tmpData, $pos+1, utf8_strlen($tmpData));
217                } else {
218                    $pageName = $tmpData;
219                }
220
221                $pageName = str_replace('_', ' ', $pageName);
222            }
223            $pageNameArticle = '';
224
225            // if the current page is not a page to hide
226            if(!in_array($pageName, $hidepages)) {
227                // Articles deletion
228                if($articlesDeletion) {
229                    foreach($articlesDeletionPatterns as $pattern) {
230                        if(eregi($pattern, $pageName, $result)) {
231                            $pageName = eregi_replace($pattern, '', $pageName);
232                            $pageNameArticle = ucfirst(trim($result[0]));
233                        }
234                    }
235                }
236
237                // Fix for useheading - Decide if the heading is used or the pagename
238                if($this->getConf('metadata_title')) {
239                    $tmp = p_get_metadata($data[$cpt]['id']);
240                    if(isset($tmp['title'])) $pageName = $tmp['title'];
241        		}
242
243        		// R�cup�ration de la premi�re lettre du mot et classement
244                $firstLetter = utf8_deaccent(utf8_strtolower(utf8_substr($pageName, 0, 1)));
245
246                if(is_numeric($firstLetter)) {
247                    if($this->getConf('numerical_index')) {
248                        $firstLetter = $this->getConf('numerical_index');
249                    } else {
250                        $firstLetter = '0-9';
251                    }
252                }
253
254                if($this->getConf('articles_moving')) {
255                    $articleMoving = $this->getConf('articles_moving');
256                } else {
257                    $articleMoving = 1;
258                }
259                if($articleMoving == 0) {
260                    $pageName = $pageNameArticle.' '.$pageName;
261                } else if (($articleMoving == 1)&&($pageNameArticle != '')) {
262                    $pageName = $pageName.' ('.$pageNameArticle.')';
263                }
264
265                $data[$cpt]['id2'] = ucfirst($pageName);
266                $alpha_data[$firstLetter][] = $data[$cpt];
267            }
268        }
269
270        // array sorting by key
271        ksort($alpha_data);
272
273        // Display of results
274
275        // alphabetical index
276        $alphaOutput .= $titleTpl . "\n";
277        $nb_data = count($alpha_data);
278
279        foreach($alpha_data as $key => $currentLetter) {
280            // Sorting of $currentLetter array
281            usort($currentLetter, create_function('$a, $b', "return strnatcasecmp(\$a['id2'], \$b['id2']);"));
282
283            $begin = str_replace("{{letter}}" ,utf8_strtoupper($key), $beginLetterTpl);
284            $alphaOutput .= $begin."\n";
285            foreach($currentLetter as $currentLetterEntry) {
286                $link = str_replace("{{link}}" ,$currentLetterEntry['id'], $entryTpl);
287                $alphaOutput .= str_replace("{{name}}" ,$currentLetterEntry['id2'], $link);
288                $alphaOutput .= "\n";
289            }
290
291            $end = str_replace("{{letter}}" ,utf8_strtoupper($key), $endLetterTpl);
292            $alphaOutput .= $end."\n";
293        }
294
295        return $alphaOutput;
296    }
297
298} // Alphaindex class end
299
300/**
301 * Build the browsable index of pages
302 *
303 * $opts['ns'] is the current namespace
304 *
305 * @author  Andreas Gohr <andi@splitbrain.org>
306 * modified by Samuele Tognini <samuele@samuele.netsons.org>
307 */
308function alphaindex_search_index(&$data, $base, $file, $type, $lvl, $opts) {
309    $return = true;
310    $item = array();
311
312    if($type == 'd'){
313        if ($opts['level'] == $lvl) $return = false;
314        if ($opts['nons']) return $return;
315    }elseif($type == 'f' && !preg_match('#\.txt$#',$file)){
316        // don't add the page
317        return false;
318    }
319
320    $id = pathID($file);
321
322    // check hidden
323    if($type=='f' && isHiddenPage($id)){
324        return false;
325    }
326
327    // check ACL
328    if($type == 'f' && auth_quickaclcheck($id) < AUTH_READ) {
329        return false;
330    }
331
332    // Set all pages at first level
333    if ($opts['nons']) {
334        $lvl = 1;
335    }
336
337    $data[] = array( 'id' => $id,
338		 'type'  => $type,
339		 'level' => $lvl,
340		 'open'  => $return);
341
342    return $return;
343}