xref: /plugin/simplenavi/syntax.php (revision d8ce5486268fd1c02234429a87c5de7aaa6425c7)
11169a1acSAndreas Gohr<?php
2*d8ce5486SAndreas Gohr
3*d8ce5486SAndreas Gohruse dokuwiki\File\PageResolver;
4*d8ce5486SAndreas Gohr
51169a1acSAndreas Gohr/**
61169a1acSAndreas Gohr * DokuWiki Plugin simplenavi (Syntax Component)
71169a1acSAndreas Gohr *
81169a1acSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
91169a1acSAndreas Gohr * @author  Andreas Gohr <gohr@cosmocode.de>
101169a1acSAndreas Gohr */
111169a1acSAndreas Gohr
12*d8ce5486SAndreas Gohrclass syntax_plugin_simplenavi extends DokuWiki_Syntax_Plugin
13*d8ce5486SAndreas Gohr{
14*d8ce5486SAndreas Gohr    private $startpages = [];
151169a1acSAndreas Gohr
16*d8ce5486SAndreas Gohr    /** @inheritdoc */
17*d8ce5486SAndreas Gohr    public function getType()
18*d8ce5486SAndreas Gohr    {
191169a1acSAndreas Gohr        return 'substition';
201169a1acSAndreas Gohr    }
211169a1acSAndreas Gohr
22*d8ce5486SAndreas Gohr    /** @inheritdoc */
23*d8ce5486SAndreas Gohr    public function getPType()
24*d8ce5486SAndreas Gohr    {
251169a1acSAndreas Gohr        return 'block';
261169a1acSAndreas Gohr    }
271169a1acSAndreas Gohr
28*d8ce5486SAndreas Gohr    /** @inheritdoc */
29*d8ce5486SAndreas Gohr    public function getSort()
30*d8ce5486SAndreas Gohr    {
311169a1acSAndreas Gohr        return 155;
321169a1acSAndreas Gohr    }
331169a1acSAndreas Gohr
34*d8ce5486SAndreas Gohr    /** @inheritdoc */
35*d8ce5486SAndreas Gohr    public function connectTo($mode)
36*d8ce5486SAndreas Gohr    {
371169a1acSAndreas Gohr        $this->Lexer->addSpecialPattern('{{simplenavi>[^}]*}}', $mode, 'plugin_simplenavi');
381169a1acSAndreas Gohr    }
391169a1acSAndreas Gohr
40*d8ce5486SAndreas Gohr    /** @inheritdoc */
41*d8ce5486SAndreas Gohr    public function handle($match, $state, $pos, Doku_Handler $handler)
42*d8ce5486SAndreas Gohr    {
43*d8ce5486SAndreas Gohr        $data = [cleanID(substr($match, 13, -2))];
441169a1acSAndreas Gohr
451169a1acSAndreas Gohr        return $data;
461169a1acSAndreas Gohr    }
471169a1acSAndreas Gohr
48*d8ce5486SAndreas Gohr    /** @inheritdoc */
49*d8ce5486SAndreas Gohr    public function render($format, Doku_Renderer $renderer, $data)
50*d8ce5486SAndreas Gohr    {
51*d8ce5486SAndreas Gohr        if ($format != 'xhtml') return false;
521169a1acSAndreas Gohr
531169a1acSAndreas Gohr        global $conf;
541169a1acSAndreas Gohr        global $INFO;
55*d8ce5486SAndreas Gohr        $renderer->info['cache'] = false;
561169a1acSAndreas Gohr
57*d8ce5486SAndreas Gohr        $ns = utf8_encodeFN(str_replace(':', '/', $data[0]));
58*d8ce5486SAndreas Gohr        $items = [];
59*d8ce5486SAndreas Gohr        search($items, $conf['datadir'], [$this, 'cbSearch'], ['ns' => $INFO['id']], $ns, 1, 'natural');
60*d8ce5486SAndreas Gohr        if ($this->getConf('sortByTitle')) {
61*d8ce5486SAndreas Gohr            $this->sortByTitle($items, "id");
62daf2dc98SOliver        } else {
63db559ff9SMichael Große            if ($this->getConf('sort') == 'ascii') {
64*d8ce5486SAndreas Gohr                uksort($items, [$this, 'pathCompare']);
65db559ff9SMichael Große            }
66daf2dc98SOliver        }
671169a1acSAndreas Gohr
68*d8ce5486SAndreas Gohr        $renderer->doc .= '<div class="plugin__simplenavi">';
69*d8ce5486SAndreas Gohr        $renderer->doc .= html_buildlist($items, 'idx', [$this, 'cbList'], [$this, 'cbListItem']);
70*d8ce5486SAndreas Gohr        $renderer->doc .= '</div>';
711169a1acSAndreas Gohr
721169a1acSAndreas Gohr        return true;
731169a1acSAndreas Gohr    }
741169a1acSAndreas Gohr
75*d8ce5486SAndreas Gohr    /**
76*d8ce5486SAndreas Gohr     * Create a list openening
77*d8ce5486SAndreas Gohr     *
78*d8ce5486SAndreas Gohr     * @param array $item
79*d8ce5486SAndreas Gohr     * @return string
80*d8ce5486SAndreas Gohr     * @see html_buildlist()
81*d8ce5486SAndreas Gohr     */
82*d8ce5486SAndreas Gohr    public function cbList($item)
83*d8ce5486SAndreas Gohr    {
84492ddc4eSAndreas Gohr        global $INFO;
85492ddc4eSAndreas Gohr
86492ddc4eSAndreas Gohr        if (($item['type'] == 'd' && $item['open']) || $INFO['id'] == $item['id']) {
87*d8ce5486SAndreas Gohr            return '<strong>' . html_wikilink(':' . $item['id'], $this->getTitle($item['id'])) . '</strong>';
88492ddc4eSAndreas Gohr        } else {
89*d8ce5486SAndreas Gohr            return html_wikilink(':' . $item['id'], $this->getTitle($item['id']));
90492ddc4eSAndreas Gohr        }
911169a1acSAndreas Gohr
921169a1acSAndreas Gohr    }
931169a1acSAndreas Gohr
94*d8ce5486SAndreas Gohr    /**
95*d8ce5486SAndreas Gohr     * Create a list item
96*d8ce5486SAndreas Gohr     *
97*d8ce5486SAndreas Gohr     * @param array $item
98*d8ce5486SAndreas Gohr     * @return string
99*d8ce5486SAndreas Gohr     * @see html_buildlist()
100*d8ce5486SAndreas Gohr     */
101*d8ce5486SAndreas Gohr    public function cbListItem($item)
102*d8ce5486SAndreas Gohr    {
1031169a1acSAndreas Gohr        if ($item['type'] == "f") {
1041169a1acSAndreas Gohr            return '<li class="level' . $item['level'] . '">';
1051169a1acSAndreas Gohr        } elseif ($item['open']) {
1061169a1acSAndreas Gohr            return '<li class="open">';
1071169a1acSAndreas Gohr        } else {
1081169a1acSAndreas Gohr            return '<li class="closed">';
1091169a1acSAndreas Gohr        }
1101169a1acSAndreas Gohr    }
1111169a1acSAndreas Gohr
112*d8ce5486SAndreas Gohr    /**
113*d8ce5486SAndreas Gohr     * Custom search callback
114*d8ce5486SAndreas Gohr     *
115*d8ce5486SAndreas Gohr     * @param $data
116*d8ce5486SAndreas Gohr     * @param $base
117*d8ce5486SAndreas Gohr     * @param $file
118*d8ce5486SAndreas Gohr     * @param $type
119*d8ce5486SAndreas Gohr     * @param $lvl
120*d8ce5486SAndreas Gohr     * @param $opts
121*d8ce5486SAndreas Gohr     * @return bool
122*d8ce5486SAndreas Gohr     */
123*d8ce5486SAndreas Gohr    public function cbSearch(&$data, $base, $file, $type, $lvl, $opts)
124*d8ce5486SAndreas Gohr    {
1251169a1acSAndreas Gohr        global $conf;
1261169a1acSAndreas Gohr        $return = true;
1271169a1acSAndreas Gohr
1281169a1acSAndreas Gohr        $id = pathID($file);
1291169a1acSAndreas Gohr
1301169a1acSAndreas Gohr        if ($type == 'd' && !(
1311169a1acSAndreas Gohr                preg_match('#^' . $id . '(:|$)#', $opts['ns']) ||
1321169a1acSAndreas Gohr                preg_match('#^' . $id . '(:|$)#', getNS($opts['ns']))
1331169a1acSAndreas Gohr
1341169a1acSAndreas Gohr            )) {
1351169a1acSAndreas Gohr            //add but don't recurse
1361169a1acSAndreas Gohr            $return = false;
137303e1405SMichael Große        } elseif ($type == 'f' && (!empty($opts['nofiles']) || substr($file, -4) != '.txt')) {
1381169a1acSAndreas Gohr            //don't add
1391169a1acSAndreas Gohr            return false;
1401169a1acSAndreas Gohr        }
1411169a1acSAndreas Gohr
1421169a1acSAndreas Gohr        if ($type == 'd' && $conf['sneaky_index'] && auth_quickaclcheck($id . ':') < AUTH_READ) {
1431169a1acSAndreas Gohr            return false;
1441169a1acSAndreas Gohr        }
1451169a1acSAndreas Gohr
1461169a1acSAndreas Gohr        if ($type == 'd') {
1471169a1acSAndreas Gohr            // link directories to their start pages
1481169a1acSAndreas Gohr            $id = "$id:";
149*d8ce5486SAndreas Gohr            $id = (new PageResolver(''))->resolveId($id);
1501169a1acSAndreas Gohr            $this->startpages[$id] = 1;
151303e1405SMichael Große        } elseif (!empty($this->startpages[$id])) {
1521169a1acSAndreas Gohr            // skip already shown start pages
1531169a1acSAndreas Gohr            return false;
1541169a1acSAndreas Gohr        } elseif (noNS($id) == $conf['start']) {
1551169a1acSAndreas Gohr            // skip the main start page
1561169a1acSAndreas Gohr            return false;
1571169a1acSAndreas Gohr        }
1581169a1acSAndreas Gohr
1591169a1acSAndreas Gohr        //check hidden
1601169a1acSAndreas Gohr        if (isHiddenPage($id)) {
1611169a1acSAndreas Gohr            return false;
1621169a1acSAndreas Gohr        }
1631169a1acSAndreas Gohr
1641169a1acSAndreas Gohr        //check ACL
1651169a1acSAndreas Gohr        if ($type == 'f' && auth_quickaclcheck($id) < AUTH_READ) {
1661169a1acSAndreas Gohr            return false;
1671169a1acSAndreas Gohr        }
1681169a1acSAndreas Gohr
169*d8ce5486SAndreas Gohr        $data[$id] = array(
170*d8ce5486SAndreas Gohr            'id' => $id,
1711169a1acSAndreas Gohr            'type' => $type,
1721169a1acSAndreas Gohr            'level' => $lvl,
173*d8ce5486SAndreas Gohr            'open' => $return,
174*d8ce5486SAndreas Gohr        );
1751169a1acSAndreas Gohr        return $return;
1761169a1acSAndreas Gohr    }
1771169a1acSAndreas Gohr
178*d8ce5486SAndreas Gohr    /**
179*d8ce5486SAndreas Gohr     * Get the title for the given page ID
180*d8ce5486SAndreas Gohr     *
181*d8ce5486SAndreas Gohr     * @param string $id
182*d8ce5486SAndreas Gohr     * @return string
183*d8ce5486SAndreas Gohr     */
184*d8ce5486SAndreas Gohr    protected function getTitle($id)
185*d8ce5486SAndreas Gohr    {
186e306992cSAndreas Gohr        global $conf;
187e306992cSAndreas Gohr
188e306992cSAndreas Gohr        if (useHeading('navigation')) {
189e306992cSAndreas Gohr            $p = p_get_first_heading($id);
190e306992cSAndreas Gohr        }
191303e1405SMichael Große        if (!empty($p)) return $p;
192e306992cSAndreas Gohr
193e306992cSAndreas Gohr        $p = noNS($id);
194*d8ce5486SAndreas Gohr        if ($p == $conf['start'] || !$p) {
195e306992cSAndreas Gohr            $p = noNS(getNS($id));
196*d8ce5486SAndreas Gohr            if (!$p) {
197e306992cSAndreas Gohr                return $conf['start'];
198e306992cSAndreas Gohr            }
199e306992cSAndreas Gohr        }
200e306992cSAndreas Gohr        return $p;
201e306992cSAndreas Gohr    }
2021169a1acSAndreas Gohr
203*d8ce5486SAndreas Gohr    /**
204*d8ce5486SAndreas Gohr     * Custom comparator to compare IDs
205*d8ce5486SAndreas Gohr     *
206*d8ce5486SAndreas Gohr     * @param string $a
207*d8ce5486SAndreas Gohr     * @param string $b
208*d8ce5486SAndreas Gohr     * @return int
209*d8ce5486SAndreas Gohr     */
210*d8ce5486SAndreas Gohr    public function pathCompare($a, $b)
211*d8ce5486SAndreas Gohr    {
2124591df21Slainme        global $conf;
213c9936b5bSMichael Große        $a = preg_replace('/' . preg_quote($conf['start'], '/') . '$/', '', $a);
214c9936b5bSMichael Große        $b = preg_replace('/' . preg_quote($conf['start'], '/') . '$/', '', $b);
2152122c0d0SMichael Große        $a = str_replace(':', '/', $a);
2162122c0d0SMichael Große        $b = str_replace(':', '/', $b);
2174591df21Slainme
2184591df21Slainme        return strcmp($a, $b);
2194591df21Slainme    }
220daf2dc98SOliver
221*d8ce5486SAndreas Gohr    /**
222*d8ce5486SAndreas Gohr     * Sort items by title
223*d8ce5486SAndreas Gohr     *
224*d8ce5486SAndreas Gohr     * @param array[] $array a list of items
225*d8ce5486SAndreas Gohr     * @param string $key the key that contains the page ID in each item
226*d8ce5486SAndreas Gohr     * @return void
227*d8ce5486SAndreas Gohr     */
228*d8ce5486SAndreas Gohr    protected function sortByTitle(&$array, $key)
229*d8ce5486SAndreas Gohr    {
230*d8ce5486SAndreas Gohr        $sorter = [];
231*d8ce5486SAndreas Gohr        $ret = [];
232daf2dc98SOliver        reset($array);
233daf2dc98SOliver        foreach ($array as $ii => $va) {
234*d8ce5486SAndreas Gohr            $sorter[$ii] = $this->getTitle($va[$key]);
235daf2dc98SOliver        }
236daf2dc98SOliver        if ($this->getConf('sort') == 'ascii') {
237*d8ce5486SAndreas Gohr            uksort($sorter, [$this, 'pathCompare']);
238daf2dc98SOliver        } else {
239daf2dc98SOliver            natcasesort($sorter);
240daf2dc98SOliver        }
241daf2dc98SOliver        foreach ($sorter as $ii => $va) {
242daf2dc98SOliver            $ret[$ii] = $array[$ii];
243daf2dc98SOliver        }
244daf2dc98SOliver        $array = $ret;
245daf2dc98SOliver    }
246daf2dc98SOliver
2471169a1acSAndreas Gohr}
248