xref: /plugin/simplenavi/syntax.php (revision b3e0295120c0248c0cb6debebd6cf37cdbde2ee3)
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*b3e02951SAndreas Gohr        $data = explode(' ', substr($match, 13, -2));
43*b3e02951SAndreas Gohr        $data[0] = cleanID($data[0]);
441169a1acSAndreas Gohr
451169a1acSAndreas Gohr        return $data;
461169a1acSAndreas Gohr    }
471169a1acSAndreas Gohr
48d8ce5486SAndreas Gohr    /** @inheritdoc */
49d8ce5486SAndreas Gohr    public function render($format, Doku_Renderer $renderer, $data)
50d8ce5486SAndreas Gohr    {
51d8ce5486SAndreas Gohr        if ($format != 'xhtml') return false;
521169a1acSAndreas Gohr
531169a1acSAndreas Gohr        global $conf;
541169a1acSAndreas Gohr        global $INFO;
55*b3e02951SAndreas Gohr        $renderer->nocache();
561169a1acSAndreas Gohr
57*b3e02951SAndreas Gohr        // first data is namespace, rest is options
58*b3e02951SAndreas Gohr        $ns = utf8_encodeFN(str_replace(':', '/', array_shift($data)));
59*b3e02951SAndreas Gohr
60d8ce5486SAndreas Gohr        $items = [];
61d8ce5486SAndreas Gohr        search($items, $conf['datadir'], [$this, 'cbSearch'], ['ns' => $INFO['id']], $ns, 1, 'natural');
62d8ce5486SAndreas Gohr        if ($this->getConf('sortByTitle')) {
63d8ce5486SAndreas Gohr            $this->sortByTitle($items, "id");
64daf2dc98SOliver        } else {
65db559ff9SMichael Große            if ($this->getConf('sort') == 'ascii') {
66d8ce5486SAndreas Gohr                uksort($items, [$this, 'pathCompare']);
67db559ff9SMichael Große            }
68daf2dc98SOliver        }
691169a1acSAndreas Gohr
70*b3e02951SAndreas Gohr        $class = 'plugin__simplenavi';
71*b3e02951SAndreas Gohr        if(in_array('filter', $data)) $class .= ' plugin__simplenavi_filter';
72*b3e02951SAndreas Gohr
73*b3e02951SAndreas Gohr        $renderer->doc .= '<div class="'.$class.'">';
74d8ce5486SAndreas Gohr        $renderer->doc .= html_buildlist($items, 'idx', [$this, 'cbList'], [$this, 'cbListItem']);
75d8ce5486SAndreas Gohr        $renderer->doc .= '</div>';
761169a1acSAndreas Gohr
771169a1acSAndreas Gohr        return true;
781169a1acSAndreas Gohr    }
791169a1acSAndreas Gohr
80d8ce5486SAndreas Gohr    /**
81d8ce5486SAndreas Gohr     * Create a list openening
82d8ce5486SAndreas Gohr     *
83d8ce5486SAndreas Gohr     * @param array $item
84d8ce5486SAndreas Gohr     * @return string
85d8ce5486SAndreas Gohr     * @see html_buildlist()
86d8ce5486SAndreas Gohr     */
87d8ce5486SAndreas Gohr    public function cbList($item)
88d8ce5486SAndreas Gohr    {
89492ddc4eSAndreas Gohr        global $INFO;
90492ddc4eSAndreas Gohr
91492ddc4eSAndreas Gohr        if (($item['type'] == 'd' && $item['open']) || $INFO['id'] == $item['id']) {
92d8ce5486SAndreas Gohr            return '<strong>' . html_wikilink(':' . $item['id'], $this->getTitle($item['id'])) . '</strong>';
93492ddc4eSAndreas Gohr        } else {
94d8ce5486SAndreas Gohr            return html_wikilink(':' . $item['id'], $this->getTitle($item['id']));
95492ddc4eSAndreas Gohr        }
961169a1acSAndreas Gohr
971169a1acSAndreas Gohr    }
981169a1acSAndreas Gohr
99d8ce5486SAndreas Gohr    /**
100d8ce5486SAndreas Gohr     * Create a list item
101d8ce5486SAndreas Gohr     *
102d8ce5486SAndreas Gohr     * @param array $item
103d8ce5486SAndreas Gohr     * @return string
104d8ce5486SAndreas Gohr     * @see html_buildlist()
105d8ce5486SAndreas Gohr     */
106d8ce5486SAndreas Gohr    public function cbListItem($item)
107d8ce5486SAndreas Gohr    {
1081169a1acSAndreas Gohr        if ($item['type'] == "f") {
1091169a1acSAndreas Gohr            return '<li class="level' . $item['level'] . '">';
1101169a1acSAndreas Gohr        } elseif ($item['open']) {
1111169a1acSAndreas Gohr            return '<li class="open">';
1121169a1acSAndreas Gohr        } else {
1131169a1acSAndreas Gohr            return '<li class="closed">';
1141169a1acSAndreas Gohr        }
1151169a1acSAndreas Gohr    }
1161169a1acSAndreas Gohr
117d8ce5486SAndreas Gohr    /**
118d8ce5486SAndreas Gohr     * Custom search callback
119d8ce5486SAndreas Gohr     *
120d8ce5486SAndreas Gohr     * @param $data
121d8ce5486SAndreas Gohr     * @param $base
122d8ce5486SAndreas Gohr     * @param $file
123d8ce5486SAndreas Gohr     * @param $type
124d8ce5486SAndreas Gohr     * @param $lvl
125d8ce5486SAndreas Gohr     * @param $opts
126d8ce5486SAndreas Gohr     * @return bool
127d8ce5486SAndreas Gohr     */
128d8ce5486SAndreas Gohr    public function cbSearch(&$data, $base, $file, $type, $lvl, $opts)
129d8ce5486SAndreas Gohr    {
1301169a1acSAndreas Gohr        global $conf;
1311169a1acSAndreas Gohr        $return = true;
1321169a1acSAndreas Gohr
1331169a1acSAndreas Gohr        $id = pathID($file);
1341169a1acSAndreas Gohr
1351169a1acSAndreas Gohr        if ($type == 'd' && !(
1361169a1acSAndreas Gohr                preg_match('#^' . $id . '(:|$)#', $opts['ns']) ||
1371169a1acSAndreas Gohr                preg_match('#^' . $id . '(:|$)#', getNS($opts['ns']))
1381169a1acSAndreas Gohr
1391169a1acSAndreas Gohr            )) {
1401169a1acSAndreas Gohr            //add but don't recurse
1411169a1acSAndreas Gohr            $return = false;
142303e1405SMichael Große        } elseif ($type == 'f' && (!empty($opts['nofiles']) || substr($file, -4) != '.txt')) {
1431169a1acSAndreas Gohr            //don't add
1441169a1acSAndreas Gohr            return false;
1451169a1acSAndreas Gohr        }
1461169a1acSAndreas Gohr
1471169a1acSAndreas Gohr        if ($type == 'd' && $conf['sneaky_index'] && auth_quickaclcheck($id . ':') < AUTH_READ) {
1481169a1acSAndreas Gohr            return false;
1491169a1acSAndreas Gohr        }
1501169a1acSAndreas Gohr
1511169a1acSAndreas Gohr        if ($type == 'd') {
1521169a1acSAndreas Gohr            // link directories to their start pages
1531169a1acSAndreas Gohr            $id = "$id:";
154d8ce5486SAndreas Gohr            $id = (new PageResolver(''))->resolveId($id);
1551169a1acSAndreas Gohr            $this->startpages[$id] = 1;
156303e1405SMichael Große        } elseif (!empty($this->startpages[$id])) {
1571169a1acSAndreas Gohr            // skip already shown start pages
1581169a1acSAndreas Gohr            return false;
1591169a1acSAndreas Gohr        } elseif (noNS($id) == $conf['start']) {
1601169a1acSAndreas Gohr            // skip the main start page
1611169a1acSAndreas Gohr            return false;
1621169a1acSAndreas Gohr        }
1631169a1acSAndreas Gohr
1641169a1acSAndreas Gohr        //check hidden
1651169a1acSAndreas Gohr        if (isHiddenPage($id)) {
1661169a1acSAndreas Gohr            return false;
1671169a1acSAndreas Gohr        }
1681169a1acSAndreas Gohr
1691169a1acSAndreas Gohr        //check ACL
1701169a1acSAndreas Gohr        if ($type == 'f' && auth_quickaclcheck($id) < AUTH_READ) {
1711169a1acSAndreas Gohr            return false;
1721169a1acSAndreas Gohr        }
1731169a1acSAndreas Gohr
174d8ce5486SAndreas Gohr        $data[$id] = array(
175d8ce5486SAndreas Gohr            'id' => $id,
1761169a1acSAndreas Gohr            'type' => $type,
1771169a1acSAndreas Gohr            'level' => $lvl,
178d8ce5486SAndreas Gohr            'open' => $return,
179d8ce5486SAndreas Gohr        );
1801169a1acSAndreas Gohr        return $return;
1811169a1acSAndreas Gohr    }
1821169a1acSAndreas Gohr
183d8ce5486SAndreas Gohr    /**
184d8ce5486SAndreas Gohr     * Get the title for the given page ID
185d8ce5486SAndreas Gohr     *
186d8ce5486SAndreas Gohr     * @param string $id
187d8ce5486SAndreas Gohr     * @return string
188d8ce5486SAndreas Gohr     */
189d8ce5486SAndreas Gohr    protected function getTitle($id)
190d8ce5486SAndreas Gohr    {
191e306992cSAndreas Gohr        global $conf;
192e306992cSAndreas Gohr
193e306992cSAndreas Gohr        if (useHeading('navigation')) {
194e306992cSAndreas Gohr            $p = p_get_first_heading($id);
195e306992cSAndreas Gohr        }
196303e1405SMichael Große        if (!empty($p)) return $p;
197e306992cSAndreas Gohr
198e306992cSAndreas Gohr        $p = noNS($id);
199d8ce5486SAndreas Gohr        if ($p == $conf['start'] || !$p) {
200e306992cSAndreas Gohr            $p = noNS(getNS($id));
201d8ce5486SAndreas Gohr            if (!$p) {
202e306992cSAndreas Gohr                return $conf['start'];
203e306992cSAndreas Gohr            }
204e306992cSAndreas Gohr        }
205e306992cSAndreas Gohr        return $p;
206e306992cSAndreas Gohr    }
2071169a1acSAndreas Gohr
208d8ce5486SAndreas Gohr    /**
209d8ce5486SAndreas Gohr     * Custom comparator to compare IDs
210d8ce5486SAndreas Gohr     *
211d8ce5486SAndreas Gohr     * @param string $a
212d8ce5486SAndreas Gohr     * @param string $b
213d8ce5486SAndreas Gohr     * @return int
214d8ce5486SAndreas Gohr     */
215d8ce5486SAndreas Gohr    public function pathCompare($a, $b)
216d8ce5486SAndreas Gohr    {
2174591df21Slainme        global $conf;
218c9936b5bSMichael Große        $a = preg_replace('/' . preg_quote($conf['start'], '/') . '$/', '', $a);
219c9936b5bSMichael Große        $b = preg_replace('/' . preg_quote($conf['start'], '/') . '$/', '', $b);
2202122c0d0SMichael Große        $a = str_replace(':', '/', $a);
2212122c0d0SMichael Große        $b = str_replace(':', '/', $b);
2224591df21Slainme
2234591df21Slainme        return strcmp($a, $b);
2244591df21Slainme    }
225daf2dc98SOliver
226d8ce5486SAndreas Gohr    /**
227d8ce5486SAndreas Gohr     * Sort items by title
228d8ce5486SAndreas Gohr     *
229d8ce5486SAndreas Gohr     * @param array[] $array a list of items
230d8ce5486SAndreas Gohr     * @param string $key the key that contains the page ID in each item
231d8ce5486SAndreas Gohr     * @return void
232d8ce5486SAndreas Gohr     */
233d8ce5486SAndreas Gohr    protected function sortByTitle(&$array, $key)
234d8ce5486SAndreas Gohr    {
235d8ce5486SAndreas Gohr        $sorter = [];
236d8ce5486SAndreas Gohr        $ret = [];
237daf2dc98SOliver        reset($array);
238daf2dc98SOliver        foreach ($array as $ii => $va) {
239d8ce5486SAndreas Gohr            $sorter[$ii] = $this->getTitle($va[$key]);
240daf2dc98SOliver        }
241daf2dc98SOliver        if ($this->getConf('sort') == 'ascii') {
242d8ce5486SAndreas Gohr            uksort($sorter, [$this, 'pathCompare']);
243daf2dc98SOliver        } else {
244daf2dc98SOliver            natcasesort($sorter);
245daf2dc98SOliver        }
246daf2dc98SOliver        foreach ($sorter as $ii => $va) {
247daf2dc98SOliver            $ret[$ii] = $array[$ii];
248daf2dc98SOliver        }
249daf2dc98SOliver        $array = $ret;
250daf2dc98SOliver    }
251daf2dc98SOliver
2521169a1acSAndreas Gohr}
253