xref: /plugin/simplenavi/syntax.php (revision 5655937a9d14161c9c88581bd8fbd137fa7e0d1f)
11169a1acSAndreas Gohr<?php
2d8ce5486SAndreas Gohr
3d8ce5486SAndreas Gohruse dokuwiki\File\PageResolver;
4d8ce5486SAndreas 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 */
11d8ce5486SAndreas Gohrclass syntax_plugin_simplenavi extends DokuWiki_Syntax_Plugin
12d8ce5486SAndreas Gohr{
13d8ce5486SAndreas Gohr    private $startpages = [];
141169a1acSAndreas Gohr
15d8ce5486SAndreas Gohr    /** @inheritdoc */
16d8ce5486SAndreas Gohr    public function getType()
17d8ce5486SAndreas Gohr    {
181169a1acSAndreas Gohr        return 'substition';
191169a1acSAndreas Gohr    }
201169a1acSAndreas Gohr
21d8ce5486SAndreas Gohr    /** @inheritdoc */
22d8ce5486SAndreas Gohr    public function getPType()
23d8ce5486SAndreas Gohr    {
241169a1acSAndreas Gohr        return 'block';
251169a1acSAndreas Gohr    }
261169a1acSAndreas Gohr
27d8ce5486SAndreas Gohr    /** @inheritdoc */
28d8ce5486SAndreas Gohr    public function getSort()
29d8ce5486SAndreas Gohr    {
301169a1acSAndreas Gohr        return 155;
311169a1acSAndreas Gohr    }
321169a1acSAndreas Gohr
33d8ce5486SAndreas Gohr    /** @inheritdoc */
34d8ce5486SAndreas Gohr    public function connectTo($mode)
35d8ce5486SAndreas Gohr    {
361169a1acSAndreas Gohr        $this->Lexer->addSpecialPattern('{{simplenavi>[^}]*}}', $mode, 'plugin_simplenavi');
371169a1acSAndreas Gohr    }
381169a1acSAndreas Gohr
39d8ce5486SAndreas Gohr    /** @inheritdoc */
40d8ce5486SAndreas Gohr    public function handle($match, $state, $pos, Doku_Handler $handler)
41d8ce5486SAndreas Gohr    {
42*5655937aSAndreas Gohr        return explode(' ', substr($match, 13, -2));
431169a1acSAndreas Gohr    }
441169a1acSAndreas Gohr
45d8ce5486SAndreas Gohr    /** @inheritdoc */
46d8ce5486SAndreas Gohr    public function render($format, Doku_Renderer $renderer, $data)
47d8ce5486SAndreas Gohr    {
48d8ce5486SAndreas Gohr        if ($format != 'xhtml') return false;
491169a1acSAndreas Gohr
501169a1acSAndreas Gohr        global $conf;
511169a1acSAndreas Gohr        global $INFO;
52b3e02951SAndreas Gohr        $renderer->nocache();
531169a1acSAndreas Gohr
54b3e02951SAndreas Gohr        // first data is namespace, rest is options
55*5655937aSAndreas Gohr        $ns = array_shift($data);
56*5655937aSAndreas Gohr        if ($ns && $ns[0] === '.') {
57*5655937aSAndreas Gohr            // resolve relative to current page
58*5655937aSAndreas Gohr            $ns = getNS((new PageResolver($INFO['id']))->resolveId("$ns:xxx"));
59*5655937aSAndreas Gohr        } else {
60*5655937aSAndreas Gohr            $ns = cleanID($ns);
61*5655937aSAndreas Gohr        }
62*5655937aSAndreas Gohr        // convert to path
63*5655937aSAndreas Gohr        $ns = utf8_encodeFN(str_replace(':', '/', $ns));
64b3e02951SAndreas Gohr
65d8ce5486SAndreas Gohr        $items = [];
66d8ce5486SAndreas Gohr        search($items, $conf['datadir'], [$this, 'cbSearch'], ['ns' => $INFO['id']], $ns, 1, 'natural');
67d8ce5486SAndreas Gohr        if ($this->getConf('sortByTitle')) {
68d8ce5486SAndreas Gohr            $this->sortByTitle($items, "id");
69daf2dc98SOliver        } else {
70db559ff9SMichael Große            if ($this->getConf('sort') == 'ascii') {
71d8ce5486SAndreas Gohr                uksort($items, [$this, 'pathCompare']);
72db559ff9SMichael Große            }
73daf2dc98SOliver        }
741169a1acSAndreas Gohr
75b3e02951SAndreas Gohr        $class = 'plugin__simplenavi';
76b3e02951SAndreas Gohr        if (in_array('filter', $data)) $class .= ' plugin__simplenavi_filter';
77b3e02951SAndreas Gohr
78b3e02951SAndreas Gohr        $renderer->doc .= '<div class="' . $class . '">';
79d8ce5486SAndreas Gohr        $renderer->doc .= html_buildlist($items, 'idx', [$this, 'cbList'], [$this, 'cbListItem']);
80d8ce5486SAndreas Gohr        $renderer->doc .= '</div>';
811169a1acSAndreas Gohr
821169a1acSAndreas Gohr        return true;
831169a1acSAndreas Gohr    }
841169a1acSAndreas Gohr
85d8ce5486SAndreas Gohr    /**
86d8ce5486SAndreas Gohr     * Create a list openening
87d8ce5486SAndreas Gohr     *
88d8ce5486SAndreas Gohr     * @param array $item
89d8ce5486SAndreas Gohr     * @return string
90d8ce5486SAndreas Gohr     * @see html_buildlist()
91d8ce5486SAndreas Gohr     */
92d8ce5486SAndreas Gohr    public function cbList($item)
93d8ce5486SAndreas Gohr    {
94492ddc4eSAndreas Gohr        global $INFO;
95492ddc4eSAndreas Gohr
96492ddc4eSAndreas Gohr        if (($item['type'] == 'd' && $item['open']) || $INFO['id'] == $item['id']) {
97d8ce5486SAndreas Gohr            return '<strong>' . html_wikilink(':' . $item['id'], $this->getTitle($item['id'])) . '</strong>';
98492ddc4eSAndreas Gohr        } else {
99d8ce5486SAndreas Gohr            return html_wikilink(':' . $item['id'], $this->getTitle($item['id']));
100492ddc4eSAndreas Gohr        }
1011169a1acSAndreas Gohr
1021169a1acSAndreas Gohr    }
1031169a1acSAndreas Gohr
104d8ce5486SAndreas Gohr    /**
105d8ce5486SAndreas Gohr     * Create a list item
106d8ce5486SAndreas Gohr     *
107d8ce5486SAndreas Gohr     * @param array $item
108d8ce5486SAndreas Gohr     * @return string
109d8ce5486SAndreas Gohr     * @see html_buildlist()
110d8ce5486SAndreas Gohr     */
111d8ce5486SAndreas Gohr    public function cbListItem($item)
112d8ce5486SAndreas Gohr    {
1131169a1acSAndreas Gohr        if ($item['type'] == "f") {
1141169a1acSAndreas Gohr            return '<li class="level' . $item['level'] . '">';
1151169a1acSAndreas Gohr        } elseif ($item['open']) {
1161169a1acSAndreas Gohr            return '<li class="open">';
1171169a1acSAndreas Gohr        } else {
1181169a1acSAndreas Gohr            return '<li class="closed">';
1191169a1acSAndreas Gohr        }
1201169a1acSAndreas Gohr    }
1211169a1acSAndreas Gohr
122d8ce5486SAndreas Gohr    /**
123d8ce5486SAndreas Gohr     * Custom search callback
124d8ce5486SAndreas Gohr     *
125d8ce5486SAndreas Gohr     * @param $data
126d8ce5486SAndreas Gohr     * @param $base
127d8ce5486SAndreas Gohr     * @param $file
128d8ce5486SAndreas Gohr     * @param $type
129d8ce5486SAndreas Gohr     * @param $lvl
130d8ce5486SAndreas Gohr     * @param $opts
131d8ce5486SAndreas Gohr     * @return bool
132d8ce5486SAndreas Gohr     */
133d8ce5486SAndreas Gohr    public function cbSearch(&$data, $base, $file, $type, $lvl, $opts)
134d8ce5486SAndreas Gohr    {
1351169a1acSAndreas Gohr        global $conf;
1361169a1acSAndreas Gohr        $return = true;
1371169a1acSAndreas Gohr
1381169a1acSAndreas Gohr        $id = pathID($file);
1391169a1acSAndreas Gohr
1401169a1acSAndreas Gohr        if ($type == 'd' && !(
1411169a1acSAndreas Gohr                preg_match('#^' . $id . '(:|$)#', $opts['ns']) ||
1421169a1acSAndreas Gohr                preg_match('#^' . $id . '(:|$)#', getNS($opts['ns']))
1431169a1acSAndreas Gohr
1441169a1acSAndreas Gohr            )) {
1451169a1acSAndreas Gohr            //add but don't recurse
1461169a1acSAndreas Gohr            $return = false;
147303e1405SMichael Große        } elseif ($type == 'f' && (!empty($opts['nofiles']) || substr($file, -4) != '.txt')) {
1481169a1acSAndreas Gohr            //don't add
1491169a1acSAndreas Gohr            return false;
1501169a1acSAndreas Gohr        }
1511169a1acSAndreas Gohr
1521169a1acSAndreas Gohr        if ($type == 'd' && $conf['sneaky_index'] && auth_quickaclcheck($id . ':') < AUTH_READ) {
1531169a1acSAndreas Gohr            return false;
1541169a1acSAndreas Gohr        }
1551169a1acSAndreas Gohr
1561169a1acSAndreas Gohr        if ($type == 'd') {
1571169a1acSAndreas Gohr            // link directories to their start pages
1581169a1acSAndreas Gohr            $id = "$id:";
159d8ce5486SAndreas Gohr            $id = (new PageResolver(''))->resolveId($id);
1601169a1acSAndreas Gohr            $this->startpages[$id] = 1;
161303e1405SMichael Große        } elseif (!empty($this->startpages[$id])) {
1621169a1acSAndreas Gohr            // skip already shown start pages
1631169a1acSAndreas Gohr            return false;
1641169a1acSAndreas Gohr        } elseif (noNS($id) == $conf['start']) {
1651169a1acSAndreas Gohr            // skip the main start page
1661169a1acSAndreas Gohr            return false;
1671169a1acSAndreas Gohr        }
1681169a1acSAndreas Gohr
1691169a1acSAndreas Gohr        //check hidden
1701169a1acSAndreas Gohr        if (isHiddenPage($id)) {
1711169a1acSAndreas Gohr            return false;
1721169a1acSAndreas Gohr        }
1731169a1acSAndreas Gohr
1741169a1acSAndreas Gohr        //check ACL
1751169a1acSAndreas Gohr        if ($type == 'f' && auth_quickaclcheck($id) < AUTH_READ) {
1761169a1acSAndreas Gohr            return false;
1771169a1acSAndreas Gohr        }
1781169a1acSAndreas Gohr
179d8ce5486SAndreas Gohr        $data[$id] = array(
180d8ce5486SAndreas Gohr            'id' => $id,
1811169a1acSAndreas Gohr            'type' => $type,
1821169a1acSAndreas Gohr            'level' => $lvl,
183d8ce5486SAndreas Gohr            'open' => $return,
184d8ce5486SAndreas Gohr        );
1851169a1acSAndreas Gohr        return $return;
1861169a1acSAndreas Gohr    }
1871169a1acSAndreas Gohr
188d8ce5486SAndreas Gohr    /**
189d8ce5486SAndreas Gohr     * Get the title for the given page ID
190d8ce5486SAndreas Gohr     *
191d8ce5486SAndreas Gohr     * @param string $id
192d8ce5486SAndreas Gohr     * @return string
193d8ce5486SAndreas Gohr     */
194d8ce5486SAndreas Gohr    protected function getTitle($id)
195d8ce5486SAndreas Gohr    {
196e306992cSAndreas Gohr        global $conf;
197e306992cSAndreas Gohr
198e306992cSAndreas Gohr        if (useHeading('navigation')) {
199e306992cSAndreas Gohr            $p = p_get_first_heading($id);
200e306992cSAndreas Gohr        }
201303e1405SMichael Große        if (!empty($p)) return $p;
202e306992cSAndreas Gohr
203e306992cSAndreas Gohr        $p = noNS($id);
204d8ce5486SAndreas Gohr        if ($p == $conf['start'] || !$p) {
205e306992cSAndreas Gohr            $p = noNS(getNS($id));
206d8ce5486SAndreas Gohr            if (!$p) {
207e306992cSAndreas Gohr                return $conf['start'];
208e306992cSAndreas Gohr            }
209e306992cSAndreas Gohr        }
210e306992cSAndreas Gohr        return $p;
211e306992cSAndreas Gohr    }
2121169a1acSAndreas Gohr
213d8ce5486SAndreas Gohr    /**
214d8ce5486SAndreas Gohr     * Custom comparator to compare IDs
215d8ce5486SAndreas Gohr     *
216d8ce5486SAndreas Gohr     * @param string $a
217d8ce5486SAndreas Gohr     * @param string $b
218d8ce5486SAndreas Gohr     * @return int
219d8ce5486SAndreas Gohr     */
220d8ce5486SAndreas Gohr    public function pathCompare($a, $b)
221d8ce5486SAndreas Gohr    {
2224591df21Slainme        global $conf;
223c9936b5bSMichael Große        $a = preg_replace('/' . preg_quote($conf['start'], '/') . '$/', '', $a);
224c9936b5bSMichael Große        $b = preg_replace('/' . preg_quote($conf['start'], '/') . '$/', '', $b);
2252122c0d0SMichael Große        $a = str_replace(':', '/', $a);
2262122c0d0SMichael Große        $b = str_replace(':', '/', $b);
2274591df21Slainme
2284591df21Slainme        return strcmp($a, $b);
2294591df21Slainme    }
230daf2dc98SOliver
231d8ce5486SAndreas Gohr    /**
232d8ce5486SAndreas Gohr     * Sort items by title
233d8ce5486SAndreas Gohr     *
234d8ce5486SAndreas Gohr     * @param array[] $array a list of items
235d8ce5486SAndreas Gohr     * @param string $key the key that contains the page ID in each item
236d8ce5486SAndreas Gohr     * @return void
237d8ce5486SAndreas Gohr     */
238d8ce5486SAndreas Gohr    protected function sortByTitle(&$array, $key)
239d8ce5486SAndreas Gohr    {
240d8ce5486SAndreas Gohr        $sorter = [];
241d8ce5486SAndreas Gohr        $ret = [];
242daf2dc98SOliver        reset($array);
243daf2dc98SOliver        foreach ($array as $ii => $va) {
244d8ce5486SAndreas Gohr            $sorter[$ii] = $this->getTitle($va[$key]);
245daf2dc98SOliver        }
246daf2dc98SOliver        if ($this->getConf('sort') == 'ascii') {
247d8ce5486SAndreas Gohr            uksort($sorter, [$this, 'pathCompare']);
248daf2dc98SOliver        } else {
249daf2dc98SOliver            natcasesort($sorter);
250daf2dc98SOliver        }
251daf2dc98SOliver        foreach ($sorter as $ii => $va) {
252daf2dc98SOliver            $ret[$ii] = $array[$ii];
253daf2dc98SOliver        }
254daf2dc98SOliver        $array = $ret;
255daf2dc98SOliver    }
256daf2dc98SOliver
2571169a1acSAndreas Gohr}
258