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