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