1<?php // Last Change 2023-04-19 2 3if(!defined('DOKU_INC')) { 4 define ('DOKU_INC', realpath(dirname(__FILE__).'/../../').'/'); 5} 6if(!defined('DOKU_PLUGIN')) { 7 define ('DOKU_PLUGIN', DOKU_INC.'lib/plugins/'); 8} 9 10require_once (DOKU_PLUGIN.'syntax.php'); 11require_once (DOKU_INC.'inc/search.php'); 12require_once (DOKU_INC.'inc/pageutils.php'); 13 14class syntax_plugin_subpages extends DokuWiki_Syntax_Plugin { 15 var $debug = false; 16 var $pages = Array(); 17 var $subpages = Array(); 18 var $start = "start"; 19 var $useheading = 0; 20 var $datadir = ""; 21 22 /** 23 * Constructor 24 */ 25 function __construct() { 26 global $conf; 27 28 // if($conf ["allowdebug"] == 1) 29 // $this->debug = true; 30 31 $this->start = $conf['start']; 32 $this->useheading = $conf['useheading']; 33 $this->datadir = $conf['datadir']; 34 // $this->style = $this->getConf("style"); 35 } 36 37 /** 38 * return some info 39 */ 40 function getInfo() { 41 } 42 43 /** 44 * What kind of syntax are we? 45 */ 46 function getType() { 47 return "substition"; 48 } 49 50 /** 51 * Just before build in links 52 */ 53 function getSort() { 54 return 299; 55 } 56 57 /** 58 * Register the ~~SUBPAGES~~ verb 59 */ 60 function connectTo($mode) { 61 $this->Lexer->addSpecialPattern('~~SUBPAGES~~', $mode, 'plugin_subpages'); 62 } 63 64 /** 65 * Handle the match 66 */ 67 function handle($match, $state, $pos, Doku_Handler $handler) { 68 return preg_replace("%~~SUBPAGES~~%", "\\2", $match); 69 } 70 71 /** 72 * Create output 73 */ 74 function render($mode, Doku_Renderer $renderer, $data) { 75 $this->rdr =& $renderer; 76 $this->rdrMode = $mode; 77 78 $data = $this->_listSubpages($data); 79 80 $this->_put($data); 81 82 return true; 83 } 84 85 /** 86 * Put a debug message on screen... 87 */ 88 function _showDebugMsg($msg) { 89 if(!$this->debug) return; 90 91 if(is_array($msg)) { 92 foreach($msg as $index => $m) { 93 $this->_showDebugMsg("Array [$index]: ".$m); 94 } 95 return; 96 } 97 98 echo DOKU_LF."<span style='color:red;'>SUBPAGES_PLUGIN: ".hsc($msg)."</span><br>"; 99 } 100 101 /** 102 * Write data to the output stream 103 */ 104 function _put($data) { 105 if($data == NULL || $data == '') 106 return; 107 108 switch($this->rdrMode) { 109 case 'xhtml': 110 $this->rdr->doc .= $data; 111 break; 112 case 'latex': 113 $this->rdr->put($data); 114 break; 115 } 116 } 117 118 /** 119 * Get the namespace of the parent directory 120 * (always prefixed and postfixed with a colon, root is ':') 121 */ 122 function _getParentNS($id) { 123 // global $ID ; 124 $curNS = getNS($id); 125 126 if($curNS == '') return ':'; 127 128 if(substr($curNS, 0, 1) != ':') { 129 $curNS = ':'.$curNS; 130 } 131 132 return $curNS.':'; 133 } 134 135 /** 136 * Create a fully qualified namespace from the specified one. 137 * The second parameter must be true when the given namespace 138 * is never a page id. In that case, the returned namespace 139 * always ends with a colon. 140 */ 141 function _getFqidOfNS($ns, $mustBeNSnoPage) { 142 global $ID; 143 144 if(substr($ns, 0, 2) == '.:') { 145 $ns = ':'.getNS($ID).substr($ns, 1); 146 } elseif(substr($ns, 0, 3) == '..:') { 147 $ns = $this->_getParentNS($ID).substr($ns, 3); 148 } elseif($ns == '..') { 149 $ns = $this->_getParentNS($ID); 150 } elseif(substr($ns, 0, 1) == ':') { 151 } elseif($ns == '.' || $ns == '*') { 152 $ns = ':'.getNS($ID); 153 } else { 154 $ns = ':'.getNS($ID).':'.$ns; 155 } 156 157 if($mustBeNSnoPage && substr($ns, -1) <> ':') $ns .= ':'; 158 159 return $ns; 160 } 161 162 /** 163 * Convert namespace to its path 164 */ 165 function _getPathOfNS($ns) { 166 if($ns == ':' || $ns == '') return $this->datadir; 167 $ns = trim($ns, ':'); 168 $path = $this->datadir.'/'.utf8_encodeFN(str_replace(':', '/', $ns)); 169 return $path; 170 } 171 172 /** 173 * Get title of page 174 */ 175 function _getPageTitle($fqid) { 176 if ($this->useheading == 1) { 177 $p = p_get_first_heading($fqid); 178 } 179 if(!empty($p)) return $p; 180 181 $p = noNS($fqid); 182 if ($p == $this->start || $p == false) { 183 $p = noNS(getNS($fqid)); 184 if ($p == false) { 185 return $this->start; 186 } 187 } 188 return $p; 189 } 190 191 /** 192 * Receive the search result and add it to pages-array 193 */ 194 function _searchCallback(&$data, $base, $file, $type, $level, $opts) { 195 $this->_showDebugMsg('Entering '.__FUNCTION__); 196 global $ID; 197 198 if ($type == 'd') { 199 // subdirectory 200 $chkfile = $file.'/'.$this->start.'.txt'; 201 $pgid = pathID($chkfile); 202 $fqid = $opts['ns'].$pgid; 203 if (auth_quickaclcheck($pgid) > AUTH_NONE) { 204 $data['title'] = $this->_getPageTitle($fqid); 205 $data['linkid'] = $fqid; 206 $data['type'] = $type; 207 $data['level'] = $level; 208 } 209 else 210 return false; // no access 211 } 212 else { 213 // page in current directory 214 $pgid = pathID($file); 215 $fqid = $opts['ns'].$pgid; 216 if ($fqid != ':'.$ID) { 217 if (auth_quickaclcheck($pgid) > AUTH_NONE) { 218 $data['title'] = $this->_getPageTitle($fqid); 219 $data['linkid'] = $fqid; 220 $data['type'] = $type; 221 $data['level'] = $level; 222 } 223 else 224 return false; // no access 225 } 226 else 227 return false; // don't display current page 228 } 229 230 array_push($this->pages, $data); 231 $this->_showDebugMsg('Leaving '.__FUNCTION__); 232 } 233 234 /** 235 * Search all pages below the current one 236 */ 237 function _listSubpages($data) { 238 $this->_showDebugMsg('Entering '.__FUNCTION__); 239 240 $ns = '.'; 241 $ns = $this->_getFqidOfNS($ns, true); 242 $path = $this->_getPathOfNS($ns); 243 244 // 245 // Search the directory $dir, only if the pages array 246 // is empty, since we can pass here several times (xhtml, latex). 247 // 248 $this->_showDebugMsg("Namespace is $ns"); 249 $this->_showDebugMsg("Search dir is $path"); 250 251 if (count($this->pages) == 0) { 252 // https://xref.dokuwiki.org/reference/dokuwiki/////nav.html?inc/Search/index.html 253 $dummy = array(); 254 search($dummy, $path, array($this, '_searchCallback'), array('ns' => $ns),'',1,'natural'); 255 256 //echo highlight_string(print_r($this->pages, true)); 257 //asort($this->pages); 258 sort($this->pages); 259 //echo highlight_string(print_r($this->pages, true)); 260 } 261 $count = count($this->pages); 262 263 //$this->_showDebugMsg("Found ".$count." pages!"); 264 //foreach ($this->pages as $page) { 265 // $this->_showDebugMsg($page); 266 //} 267 268 if (count($this->pages) > 0) { 269 $ret = '<ul class="subpages">'; 270 foreach ($this->pages as $page) { 271 //$this->_showDebugMsg($page); 272 $ret .= '<li>'.html_wikilink($page['linkid'], $page['title']).'</li>'; 273 } 274 $ret .= '</ul>'; 275 } 276 else 277 $ret = ''; 278 279 $this->_showDebugMsg('Leaving '.__FUNCTION__); 280 return $ret; 281 } 282 283} // syntax_plugin_subpages 284