1<?php
2/**
3 * DokuWiki Plugin simplenavi (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Andreas Gohr <gohr@cosmocode.de>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die();
11
12if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
13if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
14if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
15
16require_once DOKU_PLUGIN.'syntax.php';
17require_once DOKU_INC.'inc/search.php';
18
19class syntax_plugin_simplenavi extends DokuWiki_Syntax_Plugin {
20    function getType() {
21        return 'substition';
22    }
23
24    function getPType() {
25        return 'block';
26    }
27
28    function getSort() {
29        return 155;
30    }
31
32
33    function connectTo($mode) {
34        $this->Lexer->addSpecialPattern('{{simplenavi>[^}]*}}',$mode,'plugin_simplenavi');
35    }
36
37    function handle($match, $state, $pos, Doku_Handler $handler){
38        $data = array(cleanID(substr($match,13,-2)));
39
40        return $data;
41    }
42
43    function render($mode, Doku_Renderer $R, $pass) {
44        if($mode != 'xhtml') return false;
45
46        global $conf;
47        global $INFO;
48        $R->info['cache'] = false;
49
50        $ns = utf8_encodeFN(str_replace(':','/',$pass[0]));
51        $data = array();
52        search($data,$conf['datadir'],array($this,'_search'),array('ns' => $INFO['id']),$ns,1,'natural');
53        if ($this->getConf('sortByTitle') == true) {
54            $this->_sortByTitle($data,"id");
55        } else {
56            if ($this->getConf('sort') == 'ascii') {
57                uksort($data, array($this, '_cmp'));
58            }
59        }
60
61        $R->doc .= '<div class="plugin__simplenavi">';
62        $R->doc .= html_buildlist($data,'idx',array($this,'_list'),array($this,'_li'));
63        $R->doc .= '</div>';
64
65        return true;
66    }
67
68    function _list($item){
69        global $INFO;
70
71        if(($item['type'] == 'd' && $item['open']) || $INFO['id'] == $item['id']){
72            return '<strong>'.html_wikilink(':'.$item['id'],$this->_title($item['id'])).'</strong>';
73        }else{
74            return html_wikilink(':'.$item['id'],$this->_title($item['id']));
75        }
76
77    }
78
79    function _li($item){
80        if($item['type'] == "f"){
81            return '<li class="level'.$item['level'].'">';
82        }elseif($item['open']){
83            return '<li class="open">';
84        }else{
85            return '<li class="closed">';
86        }
87    }
88
89    function _search(&$data,$base,$file,$type,$lvl,$opts){
90        global $conf;
91        $return = true;
92
93        $item = array();
94
95        $id = pathID($file);
96
97        if($type == 'd' && !(
98            preg_match('#^'.$id.'(:|$)#',$opts['ns']) ||
99            preg_match('#^'.$id.'(:|$)#',getNS($opts['ns']))
100
101        )){
102            //add but don't recurse
103            $return = false;
104        }elseif($type == 'f' && (!empty($opts['nofiles']) || substr($file,-4) != '.txt')){
105            //don't add
106            return false;
107        }
108
109        if($type=='d' && $conf['sneaky_index'] && auth_quickaclcheck($id.':') < AUTH_READ){
110            return false;
111        }
112
113        if($type == 'd'){
114            // link directories to their start pages
115            $exists = false;
116            $id = "$id:";
117            resolve_pageid('',$id,$exists);
118            $this->startpages[$id] = 1;
119        }elseif(!empty($this->startpages[$id])){
120            // skip already shown start pages
121            return false;
122        }elseif(noNS($id) == $conf['start']){
123            // skip the main start page
124            return false;
125        }
126
127        //check hidden
128        if(isHiddenPage($id)){
129            return false;
130        }
131
132        //check ACL
133        if($type=='f' && auth_quickaclcheck($id) < AUTH_READ){
134            return false;
135        }
136
137        $data[$id]=array( 'id'    => $id,
138                       'type'  => $type,
139                       'level' => $lvl,
140                       'open'  => $return);
141        return $return;
142    }
143
144    function _title($id) {
145        global $conf;
146
147        if(useHeading('navigation')){
148            $p = p_get_first_heading($id);
149        }
150        if(!empty($p)) return $p;
151
152        $p = noNS($id);
153        if ($p == $conf['start'] || $p == false) {
154            $p = noNS(getNS($id));
155            if ($p == false) {
156                return $conf['start'];
157            }
158        }
159        return $p;
160    }
161
162    function _cmp($a, $b) {
163        global $conf;
164        $a = preg_replace('/'.preg_quote($conf['start'], '/').'$/', '', $a);
165        $b = preg_replace('/'.preg_quote($conf['start'], '/').'$/', '', $b);
166        $a = str_replace(':', '/', $a);
167        $b = str_replace(':', '/', $b);
168
169        return strcmp($a, $b);
170    }
171
172    function _sortByTitle(&$array, $key) {
173        $sorter = array();
174        $ret = array();
175        reset($array);
176        foreach ($array as $ii => $va) {
177            $sorter[$ii] = $this->_title($va[$key]);
178        }
179        if ($this->getConf('sort') == 'ascii') {
180            uksort($sorter, array($this, '_cmp'));
181        } else {
182            natcasesort($sorter);
183        }
184        foreach ($sorter as $ii => $va) {
185            $ret[$ii] = $array[$ii];
186        }
187        $array = $ret;
188    }
189
190}
191
192// vim:ts=4:sw=4:et:
193