1<?php 2/** 3 * Plugin catlist : Displays a list of the pages of a namespace recursively 4 * 5 * @license MIT 6 * @author Félix Faisant <xcodexif@xif.fr> 7 * 8 */ 9 10if (!defined('DOKU_INC')) die('meh.'); 11 12if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/'); 13require_once(DOKU_PLUGIN.'syntax.php'); 14require_once(DOKU_INC.'inc/search.php'); 15require_once(DOKU_INC.'inc/pageutils.php'); 16require_once(DOKU_INC.'inc/parserutils.php'); 17 18define('CATLIST_DISPLAY_LIST', 1); 19define('CATLIST_DISPLAY_LINE', 2); 20 21define('CATLIST_NSLINK_AUTO', 0); 22define('CATLIST_NSLINK_NONE', 1); 23define('CATLIST_NSLINK_FORCE', 2); 24 25define('CATLIST_INDEX_START', 0); 26define('CATLIST_INDEX_OUTSIDE', 1); 27define('CATLIST_INDEX_INSIDE', 2); 28 29define('CATLIST_SORT_NONE', 0); 30define('CATLIST_SORT_ASCENDING', 1); 31define('CATLIST_SORT_DESCENDING', 2); 32 33class syntax_plugin_catlist extends DokuWiki_Syntax_Plugin { 34 35 function connectTo ($aMode) { 36 $this->Lexer->addSpecialPattern('<catlist[^>]*>', $aMode, 'plugin_catlist'); 37 } 38 39 function getSort () { 40 return 189; 41 } 42 43 function getType () { 44 return 'substition'; 45 } 46 47 /*********************************************************************************************/ 48 /************************************ <catlist> directive ************************************/ 49 50 function _checkOption(&$match, $option, &$varAffected, $valIfFound){ 51 if (preg_match('/-'.$option.' /i', $match, $found)) { 52 $varAffected = $valIfFound; 53 $match = str_replace($found[0], '', $match); 54 } 55 } 56 function _checkOptionParam(&$match, $option, &$varAffected, $varAssoc){ 57 if (preg_match('/-'.$option.':('.implode('|',array_keys($varAssoc)).') /i', $match, $found)) { 58 $varAffected = $varAssoc[$found[1]]; 59 $match = str_replace($found[0], '', $match); 60 } 61 } 62 63 function handle ($match, $state, $pos, Doku_Handler $handler) { 64 global $conf; 65 66 $_default_sort_map = array("none" => CATLIST_SORT_NONE, 67 "ascending" => CATLIST_SORT_ASCENDING, 68 "descending" => CATLIST_SORT_DESCENDING); 69 $_index_priority_map = array("start" => CATLIST_INDEX_START, 70 "outside" => CATLIST_INDEX_OUTSIDE, 71 "inside" => CATLIST_INDEX_INSIDE); 72 73 $data = array('displayType' => CATLIST_DISPLAY_LIST, 'nsInBold' => true, 'expand' => 6, 74 'exclupage' => array(), 'excluns' => array(), 'exclunsall' => array(), 'exclunspages' => array(), 'exclunsns' => array(), 75 'exclutype' => 'id', 76 'createPageButtonNs' => true, 'createPageButtonSubs' => false, 77 'head' => (boolean)$this->getConf('showhead'), 78 'headTitle' => NULL, 'smallHead' => false, 'linkStartHead' => true, 'hn' => 'h1', 79 'useheading' => (boolean)$this->getConf('useheading'), 80 'nsuseheading' => NULL, 'nsLinks' => CATLIST_NSLINK_AUTO, 81 'columns' => 0, 'maxdepth' => 0, 82 'sort_order' => $_default_sort_map[$this->getConf('default_sort')], 'sort_by_title' => false, 'sort_by_type' => false, 83 'hide_index' => (boolean)$this->getConf('hide_index'), 84 'index_priority' => array(), 85 'nocache' => (boolean)$this->getConf('nocache'), 86 'hide_nsnotr' => (boolean)$this->getConf('hide_acl_nsnotr'), 'show_pgnoread' => false, 'show_perms' => (boolean)$this->getConf('show_acl'), 87 'show_leading_ns' => (boolean)$this->getConf('show_leading_ns'), 88 'show_notfound_error' => true ); 89 90 $index_priority = explode(',', $this->getConf('index_priority')); 91 foreach ($index_priority as $index_type) { 92 if (!array_key_exists($index_type, $_index_priority_map)) { 93 msg("catlist: invalid index type in index_priority", -1); 94 return false; 95 } 96 $data['index_priority'][] = $_index_priority_map[$index_type]; 97 } 98 $match = utf8_substr($match, 9, -1).' '; 99 100 // Display options 101 $this->_checkOption($match, "displayList", $data['displayType'], CATLIST_DISPLAY_LIST); 102 $this->_checkOption($match, "displayLine", $data['displayType'], CATLIST_DISPLAY_LINE); 103 $this->_checkOption($match, "noNSInBold", $data['nsInBold'], false); 104 if (preg_match("/-expandButton:([0-9]+)/i", $match, $found)) { 105 $data['expand'] = intval($found[1]); 106 $match = str_replace($found[0], '', $match); 107 } 108 $this->_checkOption($match, "noHeadTitle", $data['useheading'], false); 109 $this->_checkOption($match, "forceHeadTitle", $data['useheading'], true); 110 $data['nsuseheading'] = $data['useheading']; 111 $this->_checkOption($match, "noNSHeadTitle", $data['nsuseheading'], false); 112 $this->_checkOption($match, "hideNotFoundMsg", $data['show_notfound_error'], false); 113 114 // Namespace options 115 $this->_checkOption($match, "forceLinks", $data['nsLinks'], CATLIST_NSLINK_FORCE); // /!\ Deprecated 116 $this->_checkOptionParam($match, "nsLinks", $data['nsLinks'], array( "none" => CATLIST_NSLINK_NONE, 117 "auto" => CATLIST_NSLINK_AUTO, 118 "force" => CATLIST_NSLINK_FORCE )); 119 120 // Exclude options 121 for ($found; preg_match("/-(exclu(page|ns|nsall|nspages|nsns)!?):\"([^\\/\"]+)\" /i", $match, $found); ) { 122 $option = strtolower($found[1]); 123 // is regex negated ? 124 if (substr($option,-1) == "!") { 125 $data[substr($option,0,-1)][] = array('regex' => $found[3], 'neg' => true); 126 } else { 127 $data[$option][] = array('regex' => $found[3], 'neg' => false); 128 } 129 $match = str_replace($found[0], '', $match); 130 } 131 for ($found; preg_match("/-(exclu(page|ns|nsall|nspages|nsns)) /i", $match, $found); ) { 132 $data[strtolower($found[1])] = true; 133 $match = str_replace($found[0], '', $match); 134 } 135 // Exclude type (exclude based on id, name, or title) 136 $this->_checkOption($match, "excludeOnID", $data['exclutype'], 'id'); 137 $this->_checkOption($match, "excludeOnName", $data['exclutype'], 'name'); 138 $this->_checkOption($match, "excludeOnTitle", $data['exclutype'], 'title'); 139 // Exclude page/namespace id list 140 $data['excludelist'] = array(); 141 for ($found; preg_match("/-exclude:\\{([^\\}]*)\\} /", $match, $found); ) { 142 $list = explode(' ', $found[1]); 143 $data['excludelist'] = array_merge($data['excludelist'], $list); 144 $match = str_replace($found[0], '', $match); 145 } 146 147 // Max depth 148 if (preg_match("/-maxDepth:([0-9]+)/i", $match, $found)) { 149 $data['maxdepth'] = intval($found[1]); 150 $match = str_replace($found[0], '', $match); 151 } 152 153 // Columns 154 if (preg_match("/-columns:([0-9]+)/i", $match, $found)) { 155 $data['columns'] = intval($found[1]); 156 $match = str_replace($found[0], '', $match); 157 } 158 159 // Head options 160 $this->_checkOption($match, "noHead", $data['head'], false); 161 $this->_checkOption($match, "showHead", $data['head'], true); 162 $this->_checkOption($match, "smallHead", $data['smallHead'], true); 163 $this->_checkOption($match, "noLinkStartHead", $data['linkStartHead'], false); 164 if (preg_match("/-(h[1-5])/i", $match, $found)) { 165 $data['hn'] = $found[1]; 166 $match = str_replace($found[0], '', $match); 167 } 168 if (preg_match("/-titleHead:\"([^\"]*)\"/i", $match, $found)) { 169 $data['headTitle'] = $found[1]; 170 $match = str_replace($found[0], '', $match); 171 } 172 173 // Create page button options 174 $this->_checkOption($match, "noAddPageButton", $data['createPageButtonNs'], false); 175 $this->_checkOption($match, "addPageButtonEach", $data['createPageButtonSubs'], true); 176 177 // Sorting options 178 $this->_checkOption($match, "sortAscending", $data['sort_order'], CATLIST_SORT_ASCENDING); 179 $this->_checkOption($match, "sortDescending", $data['sort_order'], CATLIST_SORT_DESCENDING); 180 $this->_checkOption($match, "sortByTitle", $data['sort_by_title'], true); 181 $this->_checkOption($match, "sortByType", $data['sort_by_type'], true); 182 183 // ACL options 184 $this->_checkOption($match, "ACLshowPage", $data['show_pgnoread'], true); 185 $this->_checkOption($match, "ACLhideNs", $data['hide_nsnotr'], true); 186 187 // Remove other options and warn about 188 for ($found; preg_match("/ (-.*)/", $match, $found); ) { 189 msg(sprintf($this->getLang('unknownoption'), htmlspecialchars($found[1])), -1); 190 $match = str_replace($found[0], '', $match); 191 } 192 193 // Looking for the wanted namespace. Now, only the wanted namespace remains in $match. Then clean the namespace id 194 $ns = trim($match); 195 if ((boolean)$this->getConf('nswildcards')) { 196 global $ID; 197 $parsepagetemplate_data = array('id' => $ID, 'tpl' => $ns, 'doreplace' => true); 198 $ns = parsePageTemplate($parsepagetemplate_data); 199 } 200 if ($ns == '') $ns = '.'; // If there is nothing, we take the current namespace 201 global $ID; 202 if ($ns[0] == '.') $ns = getNS($ID).':'.$ns; // If it start with a '.', it is a relative path 203 $split = explode(':', $ns); 204 for ($i = 0; $i < count($split); $i++) { 205 if ($split[$i] === '' || $split[$i] === '.') { 206 array_splice($split, $i, 1); 207 $i--; 208 } else if ($split[$i] == '..') { 209 if ($i != 0) { 210 array_splice($split, $i-1, 2); 211 $i -= 2; 212 } else break; 213 } 214 } 215 if ($split[0] == '..') { 216 // Path would be outside the 'pages' directory 217 msg($this->getLang('outofpages'), -1); 218 return false; 219 } 220 $data['ns'] = implode(':', $split); 221 return $data; 222 } 223 224 /**************************************************************************************/ 225 /************************************ Tree walking ************************************/ 226 227 /* Utility function to check is a given page/namespace ($item) is excluded 228 * based on the relevant list of blacklisting/whitelisting regexes $arrayRegex 229 * ( array of array('regex'=>the_regex,'neg'=>false/true) ). The exclusion 230 * is based on item title, full id or name ($exclutype). 231 */ 232 function _isExcluded ($item, $exclutype, $arrayRegex) { 233 if ($arrayRegex === true) return true; 234 global $conf; 235 if ((strlen($conf['hidepages']) != 0) && preg_match('/'.$conf['hidepages'].'/i', $item['id'])) return true; 236 foreach($arrayRegex as $regex) { 237 if (!is_array($regex)) // temporary, for transitioning to v2021-07-21 238 $regex = array('regex' => $regex, 'neg' => false); 239 $match = preg_match('/'.$regex['regex'].(($exclutype=='title')?'/':'/i'), $item[$exclutype]); 240 if ($regex['neg']) { 241 if ($match === 0) 242 return true; 243 } else { 244 if ($match === 1) 245 return true; 246 } 247 } 248 return false; 249 } 250 251 function _getStartPage ($index_priority, $parid, $parpath, $name, $force, &$exists) { 252 $exists = false; 253 if ($parid != '') $parid .= ':'; 254 global $conf; 255 $index_path_map = array( CATLIST_INDEX_START => $parpath.'/'.$name.'/'.$conf['start'].'.txt', 256 CATLIST_INDEX_OUTSIDE => $parpath.'/'.$name.'.txt', 257 CATLIST_INDEX_INSIDE => $parpath.'/'.$name.'/'.$name.'.txt' ); 258 $index_id_map = array( CATLIST_INDEX_START => $parid .$name.':'.$conf['start'], 259 CATLIST_INDEX_OUTSIDE => $parid .$name, 260 CATLIST_INDEX_INSIDE => $parid .$name.':'.$name ); 261 foreach ($index_priority as $index_type) { 262 if (is_file($index_path_map[$index_type])) { 263 $exists = true; 264 return $index_id_map[$index_type]; 265 } 266 } 267 if ($force && isset($index_priority[0])) 268 return $index_id_map[0]; 269 else 270 return false; 271 } 272 273 /* Entry function for tree walking, called in render() 274 * 275 * $data contains the various options initialized and parsed in handle(), and will be passed along 276 * the tree walking. Moreover, $data['tree'] is filled by the pages found by _walk_recurse(), and 277 * will contain the full tree, minus the excluded pages (however, permissions are only evaluated at 278 * rendering time) and up to the max depth. _walk() prepares and start the tree walking. 279 */ 280 function _walk (&$data) { 281 global $conf; 282 283 // Get the directory path from namespace id, and check if it exists 284 $ns = $data['ns']; 285 if($ns == '%%CURRENT_NAMESPACE%%') 286 $ns = getNS(cleanID(getID())); // update namespace to the one currently displayed 287 $path = str_replace(':', '/', $ns); 288 $path = $conf['datadir'].'/'.utf8_encodeFN($path); 289 if (!is_dir($path)) { 290 if ($data['show_notfound_error']) 291 msg(sprintf($this->getLang('dontexist'), $ns), -1); 292 return false; 293 } 294 295 // Info on the main page (the "header" page) 296 $main = array( 'id' => $ns.':', 297 'exist' => false, 298 'title' => NULL ); 299 resolve_pageid('', $main['id'], $main['exist']); 300 if ($data['headTitle'] !== NULL) 301 $main['title'] = $data['headTitle']; 302 else { 303 if ($data['useheading'] && $main['exist']) 304 $main['title'] = p_get_first_heading($main['id'], true); 305 if (is_null($main['title'])) { 306 $ex = explode(':', $ns); 307 $main['title'] = end($ex); 308 } 309 } 310 $data['main'] = $main; 311 312 // Start the recursion 313 if (!isset($data['excludelist'])) // temporary, for transitioning to v2021-07-21 314 $data['excludelist'] = array(); 315 $data['tree'] = array(); 316 $data['index_pages'] = array( $main['id'] ); 317 $this->_walk_recurse($data, $path, $ns, "", false, false, 1/*root depth is 1*/, $data['tree']/*root*/); 318 return true; 319 } 320 321 /* Recursive function for tree walking. 322 * 323 * Scans the current namespace by looking directly at the filesystem directory 324 * for .txt files (pages) and sub-directories (namespaces). Excludes pages/namespaces 325 * based on the various exclusion options. The current/local directory path, namesapce 326 * ID and relative namespace ID are respectively $path, $ns and $relns. 327 * $data is described above. $data['tree'] is not modified directly, but only through 328 * $_TREE which is the *local* tree view (ie. a reference of a $data['tree'] node) and 329 * where found children are added. Optionally sorts this list of children. 330 * The local tree depth is $depth. $excluPages, $excluNS are flags indicates if the 331 * sub-pages/namespaces should be excluded. Fills $data['index_pages'] with all 332 * namespace IDs where an index has been found. 333 */ 334 function _walk_recurse (&$data, $path, $ns, $relns, $excluPages, $excluNS, $depth, &$_TREE) { 335 $scanDirs = @scandir($path, SCANDIR_SORT_NONE); 336 if ($scanDirs === false) { 337 msg("catlist: can't open directory of namespace ".$ns, -1); 338 return; 339 } 340 foreach ($scanDirs as $file) { 341 if ($file[0] == '.' || $file[0] == '_') continue; 342 $name = utf8_decodeFN(str_replace('.txt', '', $file)); 343 $id = ($ns == '') ? $name : $ns.':'.$name; 344 $rel_id = ($relns == '') ? $name : $relns.':'.$name; 345 $item = array('id' => $id, 'rel_id' => $rel_id, 'name' => $name, 'title' => NULL); 346 347 // ID exclusion 348 if (in_array($rel_id, $data['excludelist'])) continue; 349 350 // It's a namespace 351 if (is_dir($path.'/'.$file)) { 352 // Index page of the namespace 353 $index_exists = false; 354 $index_id = $this->_getStartPage($data['index_priority'], $ns, $path, $name, ($data['nsLinks']==CATLIST_NSLINK_FORCE), $index_exists); 355 if ($index_exists) 356 $data['index_pages'][] = $index_id; 357 // Exclusion 358 if ($excluNS) continue; 359 if ($this->_isExcluded($item, $data['exclutype'], $data['excluns'])) continue; 360 // Namespace 361 if ($index_exists && $data['nsuseheading']) 362 $item['title'] = p_get_first_heading($index_id, true); 363 if (is_null($item['title'])) 364 $item['title'] = $name; 365 $item['linkdisp'] = ($index_exists && ($data['nsLinks']==CATLIST_NSLINK_AUTO)) || ($data['nsLinks']==CATLIST_NSLINK_FORCE); 366 $item['linkid'] = $index_id; 367 // Button 368 $item['buttonid'] = $data['createPageButtonSubs'] ? $id.':' : NULL; 369 // Recursion if wanted 370 $item['_'] = array(); 371 $okdepth = ($depth < $data['maxdepth']) || ($data['maxdepth'] == 0); 372 $exclude_content = $this->_isExcluded($item, $data['exclutype'], $data['exclunsall']) 373 || in_array($rel_id.':', $data['excludelist']); 374 if (!$exclude_content && $okdepth) { 375 $exclunspages = $this->_isExcluded($item, $data['exclutype'], $data['exclunspages']); 376 $exclunsns = $this->_isExcluded($item, $data['exclutype'], $data['exclunsns']); 377 $this->_walk_recurse($data, $path.'/'.$file, $id, $rel_id, $exclunspages, $exclunsns, $depth+1, $item['_']); 378 } 379 // Tree 380 $_TREE[] = $item; 381 } else 382 383 // It's a page 384 if (!$excluPages) { 385 if (substr($file, -4) != ".txt") continue; 386 // Page title 387 if ($data['useheading']) { 388 $title = p_get_first_heading($id, true); 389 if (!is_null($title)) 390 $item['title'] = $title; 391 } 392 if (is_null($item['title'])) 393 $item['title'] = $name; 394 // Exclusion 395 if ($this->_isExcluded($item, $data['exclutype'], $data['exclupage'])) continue; 396 // Tree 397 $_TREE[] = $item; 398 } 399 400 // Sorting 401 if ($data['sort_order'] != CATLIST_SORT_NONE) { 402 usort($_TREE, function ($a, $b) use ($data) { 403 if ($data['sort_by_type'] && ( isset($a['_']) xor isset($b['_']) )) 404 return isset($b['_']); 405 $a_title = ($data['sort_by_title'] ? $a['title'] : $a['name']); 406 $b_title = ($data['sort_by_title'] ? $b['title'] : $b['name']); 407 $r = strnatcasecmp($a_title, $b_title); 408 if ($data['sort_order'] == CATLIST_SORT_DESCENDING) 409 $r *= -1; 410 return $r; 411 }); 412 } 413 } 414 } 415 416 /***********************************************************************************/ 417 /************************************ Rendering ************************************/ 418 419 function render ($mode, Doku_Renderer $renderer, $data) { 420 if (!is_array($data)) return false; 421 $ns = $data['ns']; 422 423 // Disabling cache 424 if ($data['nocache']) 425 $renderer->nocache(); 426 427 // Walk namespace tree 428 $r = $this->_walk($data); 429 if ($r == false) return false; 430 431 // Write params for the add page button 432 global $conf; 433 $renderer->doc .= '<script type="text/javascript"> catlist_baseurl = "'.DOKU_URL.'"; catlist_basescript = "'.DOKU_SCRIPT.'"; catlist_useslash = '.$conf['useslash'].'; catlist_userewrite = '.$conf['userewrite'].'; catlist_sepchar = "'.$conf['sepchar'].'"; catlist_deaccent = '.$conf['deaccent'].'; </script>'; 434 435 // Display headline 436 if ($data['head']) { 437 $html_tag_small = ($data['nsInBold']) ? 'strong' : 'span'; 438 $html_tag = ($data['smallHead']) ? $html_tag_small : $data['hn']; 439 $renderer->doc .= '<'.$html_tag.' class="catlist-head">'; 440 $main = $data['main']; 441 if (($main['exist'] && $data['linkStartHead'] && !($data['nsLinks']==CATLIST_NSLINK_NONE)) || ($data['nsLinks']==CATLIST_NSLINK_FORCE)) 442 $renderer->internallink(':'.$main['id'], $main['title']); 443 else 444 $renderer->doc .= htmlspecialchars($main['title']); 445 $renderer->doc .= '</'.$html_tag.'>'; 446 } 447 448 // Recurse and display 449 $global_ul_attr = ""; 450 if ($data['columns'] != 0) { 451 $global_ul_attr = 'column-count: '.$data['columns'].';'; 452 $global_ul_attr = 'style="-webkit-'.$global_ul_attr.' -moz-'.$global_ul_attr.' '.$global_ul_attr.'" '; 453 $global_ul_attr .= 'class="catlist_columns catlist-nslist" '; 454 } else { 455 $global_ul_attr = 'class="catlist-nslist" '; 456 } 457 if ($data['displayType'] == CATLIST_DISPLAY_LIST) $renderer->doc .= '<ul '.$global_ul_attr.'>'; 458 $this->_recurse($renderer, $data, $data['tree']); 459 $perm_create = $this->_cached_quickaclcheck($ns.':*') >= AUTH_CREATE; 460 $ns_button = ($ns == '') ? '' : $ns.':'; 461 if ($data['createPageButtonNs'] && $perm_create) $this->_displayAddPageButton($renderer, $ns_button, $data['displayType']); 462 if ($data['displayType'] == CATLIST_DISPLAY_LIST) $renderer->doc .= '</ul>'; 463 464 return true; 465 } 466 467 /* Just cache the calls to auth_quickaclcheck, mainly for _any_child_perms */ 468 function _cached_quickaclcheck($id) { 469 static $cache = array(); 470 if (!isset($cache[$id])) 471 $cache[$id] = auth_quickaclcheck($id); 472 return $cache[$id]; 473 } 474 475 /* Walk the tree to see if any page/namespace below this has read access access, for show_leading_ns option */ 476 function _any_child_perms ($data, $_TREE) { 477 foreach ($_TREE as $item) { 478 if (isset($item['_'])) { 479 $perms = $this->_cached_quickaclcheck($item['id'].':*'); 480 if ($perms >= AUTH_READ || $this->_any_child_perms($data, $item['_'])) 481 return true; 482 } else { 483 $perms = $this->_cached_quickaclcheck($item['id']); 484 if ($perms >= AUTH_READ) 485 return true; 486 } 487 } 488 return false; 489 } 490 491 function _recurse (&$renderer, $data, $_TREE) { 492 foreach ($_TREE as $item) { 493 if (isset($item['_'])) { 494 // It's a namespace 495 $perms = $this->_cached_quickaclcheck($item['id'].':*'); 496 $perms_exemption = $data['show_perms']; 497 // If we actually care about not showing the namespace because of permissions : 498 if ($perms < AUTH_READ && !$perms_exemption) { 499 // If show_leading_ns activated, walk the tree below this, see if any page/namespace below this has access 500 if ($data['show_leading_ns'] && $this->_any_child_perms($data, $item['_'])) { 501 $perms_exemption = true; 502 } else { 503 if ($data['hide_nsnotr']) continue; 504 if ($data['show_pgnoread']) 505 $perms_exemption = true; // Add exception if show_pgnoread enabled, but hide_nsnotr prevails 506 } 507 } 508 $linkdisp = $item['linkdisp'] && ($perms >= AUTH_READ); 509 $item['buttonid'] = ($perms >= AUTH_CREATE) ? $item['buttonid'] : NULL; 510 $this->_displayNSBegin($renderer, $data, $item['title'], $linkdisp, $item['linkid'], ($data['show_perms'] ? $perms : NULL)); 511 if ($perms >= AUTH_READ || $perms_exemption) 512 $this->_recurse($renderer, $data, $item['_']); 513 $this->_displayNSEnd($renderer, $data['displayType'], $item['buttonid']); 514 } else { 515 // It's a page 516 $perms = $this->_cached_quickaclcheck($item['id']); 517 if ($perms < AUTH_READ && !$data['show_perms'] && !$data['show_pgnoread']) 518 continue; 519 if ($data['hide_index'] && in_array($item['id'], $data['index_pages'])) 520 continue; 521 $displayLink = $perms >= AUTH_READ || $data['show_perms']; 522 $this->_displayPage($renderer, $item, $data['displayType'], ($data['show_perms'] ? $perms : NULL), $displayLink); 523 } 524 } 525 } 526 527 function _displayNSBegin (&$renderer, $data, $title, $displayLink, $idLink, $perms) { 528 if ($data['displayType'] == CATLIST_DISPLAY_LIST) { 529 $warper_ns = ($data['nsInBold']) ? 'strong' : 'span'; 530 $renderer->doc .= '<li class="catlist-ns"><'.$warper_ns.' class="li catlist-nshead">'; 531 if ($displayLink) $renderer->internallink($idLink, $title); 532 else $renderer->doc .= htmlspecialchars($title); 533 if ($perms !== NULL) $renderer->doc .= ' [ns, perm='.$perms.']'; 534 $renderer->doc .= '</'.$warper_ns.'>'; 535 $renderer->doc .= '<ul class="catlist-nslist">'; 536 } 537 else if ($data['displayType'] == CATLIST_DISPLAY_LINE) { 538 if ($data['nsInBold']) $renderer->doc .= '<strong>'; 539 if ($displayLink) $renderer->internallink($idLink, $title); 540 else $renderer->doc .= htmlspecialchars($title); 541 if ($data['nsInBold']) $renderer->doc .= '</strong>'; 542 $renderer->doc .= '[ '; 543 } 544 } 545 546 function _displayNSEnd (&$renderer, $displayType, $nsAddButton) { 547 if (!is_null($nsAddButton)) $this->_displayAddPageButton($renderer, $nsAddButton, $displayType); 548 if ($displayType == CATLIST_DISPLAY_LIST) $renderer->doc .= '</ul></li>'; 549 else if ($displayType == CATLIST_DISPLAY_LINE) $renderer->doc .= '] '; 550 } 551 552 function _displayPage (&$renderer, $item, $displayType, $perms, $displayLink) { 553 if ($displayType == CATLIST_DISPLAY_LIST) { 554 $renderer->doc .= '<li class="catlist-page">'; 555 if ($displayLink) $renderer->internallink(':'.$item['id'], $item['title']); 556 else $renderer->doc .= htmlspecialchars($item['title']); 557 if ($perms !== NULL) $renderer->doc .= ' [page, perm='.$perms.']'; 558 $renderer->doc .= '</li>'; 559 } else if ($displayType == CATLIST_DISPLAY_LINE) { 560 $renderer->internallink(':'.$item['id'], $item['title']); 561 $renderer->doc .= ' '; 562 } 563 } 564 565 function _displayAddPageButton (&$renderer, $ns, $displayType) { 566 $html = ($displayType == CATLIST_DISPLAY_LIST) ? 'li' : 'span'; 567 $renderer->doc .= '<'.$html.' class="catlist_addpage"><button class="button" onclick="catlist_button_add_page(this,\''.$ns.'\')">'.$this->getLang('addpage').'</button></'.$html.'>'; 568 } 569 570} 571