1<?php 2/** 3 * Renderer for XHTML output 4 * 5 * @author Harry Fuecks <hfuecks@gmail.com> 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8if (!defined('DOKU_INC')) die('meh.'); 9 10 11require_once DOKU_INC . 'inc/parser/xhtml.php'; 12 13/** 14 * DokuWiki Plugin nicorender (Renderer Component) 15 * 16 * The Nico XHTML Renderer 17 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 18 * @author Nicolas GERARD <gerardnico@gmail.com> 19 * 20 * This is a replacement render of the DokuWiki's main renderer 21 * That format the content that's output the tpl_content function. 22 */ 23class renderer_plugin_rplus_renderer extends Doku_Renderer_xhtml 24{ 25 26 /** 27 * @var array that hold the position of the parent 28 */ 29 protected $nodeParentPosition = []; 30 31 /** 32 * @var array that hold the current position of an header for a level 33 * $headerNum[level]=position 34 */ 35 protected $header = []; 36 37 /** 38 * @var array that will contains the whole doc but by section 39 */ 40 protected $sections = []; 41 42 /** 43 * @var the section number 44 */ 45 protected $sectionNumber = 0; 46 47 /** 48 * @var variable that permits to carry the header text of a previous section 49 */ 50 protected $previousSectionTextHeader = ''; 51 52 53 /** 54 * @var variable that permits to carry the position of a previous section 55 */ 56 protected $previousNodePosition = 0; 57 58 /** 59 * @var variable that permits to carry the position of a previous section 60 */ 61 protected $previousNodeLevel = 0; 62 63 64 function getFormat() 65 { 66 return 'xhtml'; 67 } 68 69 /* 70 * Function that enable to list the plugin in the options for config:renderer_xhtml 71 * http://www.dokuwiki.org/config:renderer_xhtml 72 * setting in its Configuration Manager. 73 */ 74 public function canRender($format) 75 { 76 return ($format == 'xhtml'); 77 } 78 79 80 /** 81 * Render a heading 82 * 83 * The rendering of the heading is done through the parent 84 * The function just: 85 * - save the rendering between each header in the class variable $this->sections 86 * This variblae is used in the function document_end to recreate the whole doc. 87 * - add the numbering to the header text 88 * 89 * @param string $text the text to display 90 * @param int $level header level 91 * @param int $pos byte position in the original source 92 */ 93 function header($text, $level, $pos) 94 { 95 96 97 // We are going from 2 to 3 98 // The parent is 2 99 if ($level > $this->previousNodeLevel) { 100 $nodePosition = 1; 101 // Keep the position of the parent 102 $this->nodeParentPosition[$this->previousNodeLevel] = $this->previousNodePosition; 103 } elseif 104 // We are going from 3 to 2 105 // The parent is 1 106 ($level < $this->previousNodeLevel 107 ) { 108 $nodePosition = $this->nodeParentPosition[$level] + 1; 109 } else { 110 $nodePosition = $this->previousNodePosition + 1; 111 } 112 113 // Grab the doc from the previous section 114 $this->sections[$this->sectionNumber] = array( 115 'level' => $this->previousNodeLevel, 116 'position' => $this->previousNodePosition, 117 'content' => $this->doc, 118 'text' => $this->previousSectionTextHeader); 119 120 // And reset it 121 $this->doc = ''; 122 // Set the looping variable 123 $this->sectionNumber = $this->sectionNumber + 1; 124 $this->previousNodeLevel = $level; 125 $this->previousNodePosition = $nodePosition; 126 $this->previousSectionTextHeader = $text; 127 128 $numbering = ""; 129 if ($level == 2) { 130 $numbering = $nodePosition; 131 } 132 if ($level == 3) { 133 $numbering = $this->nodeParentPosition[$level - 1] . "." . $nodePosition; 134 } 135 if ($level == 4) { 136 $numbering = $this->nodeParentPosition[$level - 2] . "." . $this->nodeParentPosition[$level - 1] . "." . $nodePosition; 137 } 138 if ($level == 5) { 139 $numbering = $this->nodeParentPosition[$level - 3] . "." . $this->nodeParentPosition[$level - 2] . "." . $this->nodeParentPosition[$level - 1] . "." . $nodePosition; 140 } 141 if ($numbering <> "") { 142 $textWithLocalization = $numbering . " - " . $text; 143 } else { 144 $textWithLocalization = $text; 145 } 146 147 // Rendering is done by the parent 148 parent::header($textWithLocalization, $level, $pos); 149 150 // Add the page detail after the first header 151 if ($level == 1 and $nodePosition == 1) { 152 153 global $ID; 154 $this->doc .= $this->youarehere($ID); 155 156 } 157 158 159 } 160 161 162 function document_end() 163 { 164 165 // TOC init 166 // Dow we need to show the toc ? 167 $showToc = $this->getShowToc(); 168 global $TOC; 169 // If the TOC is null (The toc may be initialized by a plugin) 170 if (!is_array($TOC)) { 171 $TOC = $this->toc; 172 } 173 174 // Pump the last doc 175 $this->sections[$this->sectionNumber] = array('level' => $this->previousNodeLevel, 'position' => $this->previousNodePosition, 'content' => $this->doc, 'text' => $this->previousSectionTextHeader); 176 177 // Recreate the doc 178 $this->doc = ''; 179 foreach ($this->sections as $sectionNumber => $section) { 180 181 // The content 182 $this->doc .= $section['content']; 183 184 if ($section['level'] == 1 and $section['position'] == 1) { 185 186 if ($showToc) { 187 global $ACT; 188 switch ($ACT){ 189 case 'admin': 190 $this->doc .= tpl_toc($return = true); 191 break; 192 default: 193 global $conf; 194 if (count($TOC) > $conf['tocminheads']) { 195 $this->doc .= tpl_toc($return = true); 196 } 197 break; 198 } 199 } 200 201 // Advertisement bar after the content ??? 202 // if ($section['level'] == 2 and 203 // $section['position'] == 1 and 204 // $ID <> 'adbar12' and 205 // $ID <> 'start' 206 // ) { 207 // 208 // // $ID <> 'adbar12' to not come in a recursive call 209 // // as tpl_include_call also the renderer process 210 // 211 // $this->doc .= tpl_include_page('adbar12', $print = false, $propagate = true); 212 // 213 // } 214 215 } 216 217 218 } 219 220 parent::document_end(); 221 222 } 223 224 /** 225 * Start a table 226 * 227 * @param int $maxcols maximum number of columns 228 * @param int $numrows NOT IMPLEMENTED 229 * @param int $pos byte position in the original source 230 * @param string|string[] classes - have to be valid, do not pass unfiltered user input 231 */ 232 function table_open($maxcols = null, $numrows = null, $pos = null, $classes = NULL) 233 { 234 // initialize the row counter used for classes 235 $this->_counter['row_counter'] = 0; 236 $class = 'table'; 237 if ($pos !== null) { 238 $sectionEditStartData = ['target' => 'table']; 239 if (!defined('SEC_EDIT_PATTERN')) { 240 // backwards-compatibility for Frusterick Manners (2017-02-19) 241 $sectionEditStartData = 'table'; 242 } 243 $class .= ' ' . $this->startSectionEdit($pos, $sectionEditStartData); 244 } 245 // table-responsive and 246 $bootResponsiveClass = 'table-responsive'; 247 $bootTableClass = 'table table-hover table-striped'; 248 249 $this->doc .= '<div class="' . $class . ' ' . $bootResponsiveClass . '"><table class="inline ' . $bootTableClass . '">' . DOKU_LF; 250 251 } 252 253 254 /** 255 * Hierarchical breadcrumbs 256 * 257 * This will return the Hierarchical breadcrumbs. 258 * 259 * Config: 260 * - $conf['youarehere'] must be true 261 * - add $lang['youarehere'] if $printPrefix is true 262 * 263 * @return string 264 */ 265 function youarehere() 266 { 267 268 global $conf; 269 global $lang; 270 271 // check if enabled 272 if (!$conf['youarehere']) return; 273 274 // print intermediate namespace links 275 $htmlOutput = '<ol class="breadcrumb rplus">' . PHP_EOL; 276 277 // Print the home page 278 $htmlOutput .= '<li>' . PHP_EOL; 279 $page = $conf['start']; 280 $pageTitle = tpl_pagetitle($page, true); 281 $htmlOutput .= tpl_link(wl($page), '<span class="nicon_home" aria-hidden="true"></span>', 'title="' . $pageTitle . '"', $return = true); 282 $htmlOutput .= '</li>' . PHP_EOL; 283 284 // Print the parts if there is more than one 285 global $ID; 286 $idParts = explode(':', $ID); 287 $countPart = count($idParts); 288 if ($countPart > 1) { 289 290 // Print the parts without the last one ($count -1) 291 $pagePart = ""; 292 for ($i = 0; $i < $countPart - 1; $i++) { 293 294 $pagePart .= $idParts[$i] . ':'; 295 296 // We pass the value to the page variable 297 // because the resolve part will change it 298 $page = $pagePart; 299 $exist = null; 300 resolve_pageid(getNS($ID), $page, $exist, "", true); 301 302 $pageTitle = tpl_pagetitle($page, true); 303 $linkContent = $pageTitle; 304 if ($i < $countPart - 1) { 305 $linkContent = " > " . $linkContent; 306 } 307 $htmlOutput .= '<li>'; 308 // html_wikilink because the page has the form pagename: and not pagename:pagename 309 $htmlOutput .= tpl_link(wl($page), $linkContent, 'title="' . $pageTitle . '" class="navlink"', $return = true); 310 $htmlOutput .= '</li>' . PHP_EOL; 311 312 } 313 } 314 315 316 // print current page 317 // print '<li>'; 318 // tpl_link(wl($page), tpl_pagetitle($page,true), 'title="' . $page . '"'); 319 $htmlOutput .= '</li>' . PHP_EOL; 320 321 // close the breadcrumb 322 $htmlOutput .= '</ol>' . PHP_EOL; 323 return $htmlOutput; 324 325 } 326 327 /** 328 * @return bool if the toc need to be shown 329 */ 330 private function getShowToc() 331 { 332 // No TOC or bar for an admin page 333 global $ACT; 334 $showToc = null; 335 336 if ($ACT == 'search') { 337 338 $showToc = false; 339 340 } 341 342 if ($ACT == 'admin' and $showToc == null) { 343 344 global $INPUT; 345 $plugin = null; 346 $class = $INPUT->str('page'); 347 if (!empty($class)) { 348 349 $pluginlist = plugin_list('admin'); 350 351 if (in_array($class, $pluginlist)) { 352 // attempt to load the plugin 353 /** @var $plugin DokuWiki_Admin_Plugin */ 354 $plugin = plugin_load('admin', $class); 355 } 356 357 if ($plugin !== null) { 358 global $TOC; 359 if (!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet 360 if (!is_array($TOC)) { 361 $showToc = false; 362 } else { 363 $showToc = true; 364 } 365 366 } 367 368 } 369 370 } 371 372 // Default True 373 if ($showToc == null) { 374 $showToc = true; 375 } 376 377 378 return $showToc; 379 380 } 381 382 383} 384