1<?php 2 3namespace dokuwiki\template\mikio; 4 5/** 6 * DokuWiki Mikio Template 7 * 8 * @link http://dokuwiki.org/template:mikio 9 * @author James Collins <james.collins@outlook.com.au> 10 * @license MIT License (https://raw.githubusercontent.com/nomadjimbob/Mikio/master/LICENSE) 11 */ 12 13if (!defined('DOKU_INC')) die(); 14 15require_once('inc/simple_html_dom.php'); 16 17class Template { 18 public $tplDir = ''; 19 public $baseDir = ''; 20 21 22 /** 23 * Class constructor 24 * 25 * @author James Collins <james.collins@outlook.com.au> 26 */ 27 public function __construct() { 28 $this->tplDir = tpl_incdir(); 29 $this->baseDir = tpl_basedir(); 30 31 $this->_registerHooks(); 32 } 33 34 35 /** 36 * Get the singleton instance 37 * 38 * @return Template 39 */ 40 public static function getInstance() 41 { 42 43 static $instance = null; 44 45 if ($instance === null) { 46 $instance = new Template(); 47 } 48 49 return $instance; 50 51 } 52 53 /** 54 * Register themes DokuWiki hooks 55 * 56 * @author James Collins <james.collins@outlook.com.au> 57 */ 58 private function _registerHooks() { 59 global $EVENT_HANDLER; 60 61 $events_dispatcher = array( 62 'TPL_METAHEADER_OUTPUT' => 'metaheadersHandler', 63 'TPL_CONTENT_DISPLAY' => 'contentHandler', 64 ); 65 66 foreach ($events_dispatcher as $event => $method) { 67 $EVENT_HANDLER->register_hook($event, 'BEFORE', $this, $method); 68 } 69 } 70 71 72 /** 73 * DokuWiki META Header event handler 74 * 75 * @author James Collins <james.collins@outlook.com.au> 76 */ 77 public function metaHeadersHandler(\Doku_Event $event) { 78 $stylesheets = array(); 79 $scripts = array(); 80 81 if($this->getConf('useTheme') != '') { 82 if(file_exists($this->tplDir . 'themes/' . $this->getConf('useTheme') . '/style.less')) { 83 $stylesheets[] = $this->baseDir . 'themes/' . $this->getConf('useTheme') . '/style.less'; 84 } 85 } 86 87 // $stylesheets[] = $this->baseDir . 'css/mikio.less'; 88 // $stylesheets[] = $this->baseDir . 'css/bootstrap.min.css'; 89 90 if($this->getConf('includeFontAwesome') == true) $stylesheets[] = $this->baseDir . 'assets/fontawesome/css/all.min.css'; 91 92 $scripts[] = $this->baseDir . 'js/bootstrap.min.js'; 93 94 foreach ($stylesheets as $style) { 95 array_unshift($event->data['link'], array( 96 'type' => 'text/css', 97 'rel' => 'stylesheet', 98 'href' => $style 99 )); 100 } 101 102 foreach ($scripts as $script) { 103 $event->data['script'][] = array( 104 'type' => 'text/javascript', 105 '_data' => '', 106 'src' => $script 107 ); 108 } 109 } 110 111 112 /** 113 * DokuWiki content event handler 114 * 115 * @author James Collins <james.collins@outlook.com.au> 116 */ 117 public function contentHandler(\Doku_Event $event) 118 { 119 $event->data = $this->parseContent($event->data); 120 } 121 122 123 /** 124 * Parse configuration options 125 * 126 * @author James Collins <james.collins@outlook.com.au> 127 * 128 * @param string $key The configuration key to retreive 129 * @param mixed $default If key doesn't exist, return this value 130 * @return mixed Parsed value of configuration 131 */ 132 public function getConf($key, $default = false) { 133 global $ACT, $conf; 134 135 $value = tpl_getConf($key, $default); 136 137 switch($key) { 138 139 case 'navbar': // TODO is this needed? 140 $value = explode(',', $value); 141 break; 142 143 case 'showSidebar': 144 if ($ACT !== 'show') { 145 return false; 146 } 147 148 return page_findnearest($conf['sidebar'], $this->getConf('useACL')); 149 150 case 'navbarMenuStyle': 151 if($value != 'text') { 152 if(!$this->getConf('useFontAwesome')) { 153 return 'text'; 154 } 155 } 156 157 break; 158 159 case 'navbarMenuPosition': 160 if($value == 'right') { 161 return 'ml-md-auto'; 162 } 163 164 return ''; 165 166 case 'breadcrumbsLoc': 167 if(!$this->getConf('useHeroTitle') && $value == 'hero') { 168 return 'top'; 169 } 170 171 if($value != 'top' && $value != 'hero' && $value != 'page') { 172 return 'page'; 173 } 174 175 break; 176 } 177 178 return $value; 179 } 180 181 182 /** 183 * Icon 184 * 185 * @author James Collins <james.collins@outlook.com.au> 186 * 187 * @param string $type The type of icon to return 188 * @return string HTML for icon element 189 */ 190 public function icon($type) { 191 if($this->getConf('useFontAwesome')) { 192 return '<i class="fa fa-' . $type . '" aria-hidden="true"></i>'; 193 } 194 195 return ''; 196 } 197 198 199 /** 200 * Print the Navbar menu title/icon 201 * 202 * @author James Collins <james.collins@outlook.com.au> 203 * 204 * @param string $type The type of icon to return 205 * @return string HTML for icon element 206 */ 207 public function navbarMenuTitle($title, $icon) { 208 global $lang; 209 210 $title = ''; 211 212 if($this->getConf('navbarMenuStyle') != 'text') { 213 $title .= $this->icon($icon); 214 } 215 216 if($this->getConf('navbarMenuStyle') != 'icon') { 217 $title .= $lang['user_tools']; 218 } 219 220 echo $title; 221 } 222 223 224 /** 225 * Add class to first DOM element 226 * 227 * @author James Collins <james.collins@outlook.com.au> 228 * 229 * @param string $content HTML DOM 230 * @param string $class Class to add DOM elements 231 * @return string HTML DOM with class added 232 */ 233 public function elementAddClass($html, $class) { 234 preg_match('/class.*?".*?"/', $html, $matches); 235 if(count($matches) > 0) { 236 preg_match('/[" ]'.$class.'[" ]/', $matches[0], $matches); 237 if(count($matches) == 0) { 238 return preg_replace('/(class.*?=.*?")/', '${1}'.$class.' ', $html, 1); 239 } 240 } else { 241 return preg_replace('/>/', 'class="'.$class.'">', $html, 1); 242 } 243 244 return $html; 245 } 246 247 248 /** 249 * Include Sidebar 250 * 251 * @author James Collins <james.collins@outlook.com.au> 252 * 253 * @param string $type Sidebar type 254 * @return boolean If sidebar was added 255 */ 256 public function includeSidebar($type) { 257 global $conf; 258 259 switch($type) { 260 case 'left': 261 if($this->getConf('showSidebar')) { 262 echo '<aside>'; 263 tpl_includeFile('sidebarheader.html'); 264 tpl_include_page($conf['sidebar'], 1, 1); 265 tpl_includeFile('sidebarfooter.html'); 266 echo '</aside>'; 267 268 return true; 269 } 270 271 return false; 272 } 273 274 return false; 275 } 276 277 278 /** 279 * Print out breadcrumbs 280 * 281 * @author James Collins <james.collins@outlook.com.au> 282 * 283 * @param string $location Location of breadcrumbs 284 */ 285 public function includeBreadcrumbs($location) { 286 if($location == $this->getConf('breadcrumbsLoc')) { 287 global $conf; 288 289 print '<div class="mikio-breadcrumbs">'; 290 291 if($conf['breadcrumbs']) { 292 tpl_breadcrumbs(); 293 } 294 295 if($conf['youarehere']) { 296 tpl_youarehere(); 297 } 298 299 print '</div>'; 300 } 301 } 302 303 304 /** 305 * Print out hero 306 * 307 * @author James Collins <james.collins@outlook.com.au> 308 */ 309 public function includeHero() { 310 global $ACT; 311 312 if($ACT === 'show') { 313 if($this->getConf('useHeroTitle')) { 314 print '<div class="mikio-hero d-flex flex-row">'; 315 print '<div class="mikio-hero-text flex-grow-1">'; 316 $this->includeBreadcrumbs('hero'); 317 print '<h1 id="mikio-hero-title">'; 318 tpl_pagetitle(); 319 print '</h1>'; 320 print '<h2 id="mikio-hero-subtext">'; 321 print ''; // TODO Find subtext in page? 322 print '</h2>'; 323 print '</div>'; 324 325 $hero_image = tpl_getMediaFile(array(':hero.png', ':hero.jpg', ':wiki:hero.png', ':wiki:hero.jpg', 'images/hero.png', 'images/hero.jpg'), false); 326 if($hero_image != '') $hero_image = ' style="background-image:url(\''.$hero_image.'\');"'; 327 328 print '<div class="mikio-hero-image"' . $hero_image . '></div>'; 329 print '</div>'; 330 } 331 } 332 } 333 334 335 /** 336 * Print out TOC 337 * 338 * @author James Collins <james.collins@outlook.com.au> 339 */ 340 public function includeTOC($location) { 341 if($this->getConf('tocfullheight') && $location === 'full') { 342 print '<div class="mikio-toc mikio-toc-full">'; 343 tpl_toc(); 344 print '</div>'; 345 } else if(!$this->getConf('tocfullheight') && $location === 'float') { 346 print '<div class="mikio-toc mikio-toc-float">'; 347 tpl_toc(); 348 print '</div>'; 349 } 350 } 351 352 353 /** 354 * Parse HTML for bootstrap 355 * 356 * @author James Collins <james.collins@outlook.com.au> 357 * 358 * @param string $content HTML content to parse 359 * @return string Parsed HTML for bootstrap 360 */ 361 public function parseContent($content) { 362 $html = new \simple_html_dom; 363 $html->load($content, true, false); 364 365 # Return original content if Simple HTML DOM fail or exceeded page size (default MAX_FILE_SIZE => 600KB) 366 if (!$html) { 367 return $content; 368 } 369 370 371 # Hide page title if hero is enabled 372 if($this->getConf('useHeroTitle')) { 373 $pageTitle = tpl_pagetitle(null, true); 374 375 foreach($html->find('h1,h2,h3,h4') as $elm) { 376 if($elm->innertext == $pageTitle) { 377 $elm->innertext = ''; 378 break; 379 } 380 } 381 } 382 383 # Buttons 384 foreach ($html->find('.button') as $elm) { 385 if ($elm->tag == 'form') { 386 continue; 387 } 388 $elm->class .= ' btn'; 389 } 390 391 foreach ($html->find('[type=button], [type=submit], [type=reset]') as $elm) { 392 $elm->class .= ' btn btn-outline-secondary'; 393 } 394 395 # Section Edit Button 396 foreach ($html->find('.btn_secedit [type=submit]') as $elm) { 397 $elm->class .= ' btn-sm'; 398 } 399 400 # Section Edit icons 401 foreach ($html->find('.secedit.editbutton_section button') as $elm) { 402 $elm->innertext = '<i class="fa fa-edit" aria-hidden="true"></i> ' . $elm->innertext; 403 } 404 405 $content = $html->save(); 406 407 $html->clear(); 408 unset($html); 409 410 return $content; 411 } 412} 413 414global $TEMPLATE; 415 416$TEMPLATE = \dokuwiki\template\mikio\Template::getInstance();