1<?php 2 3namespace dokuwiki\template\sprintdoc; 4 5/** 6 * Class Template 7 * 8 * provides additional logic for the sprintdoc template 9 * 10 * @package dokuwiki\template\sprintdoc 11 */ 12class Template { 13 14 /** @var array loaded plugins */ 15 protected $plugins = array( 16 'sqlite' => null, 17 'tagging' => null, 18 'magicmatcher' => null, 19 'tplinc' => null, 20 'sitemapnavi' => null, 21 ); 22 23 /** @var string the type of special navigation to use */ 24 protected $nav = ''; 25 26 27 /** 28 * Get the singleton instance 29 * 30 * @return Template 31 */ 32 public static function getInstance() { 33 static $instance = null; 34 if($instance === null) $instance = new Template(); 35 return $instance; 36 } 37 38 /** 39 * Template constructor. 40 */ 41 protected function __construct() { 42 $this->initializePlugins(); 43 $this->initNavigationCookie(); 44 45 /** @var \Doku_Event_Handler */ 46 global $EVENT_HANDLER; 47 $EVENT_HANDLER->register_hook('PLUGIN_TPLINC_LOCATIONS_SET', 'BEFORE', $this, 'registerIncludes'); 48 } 49 50 /** 51 * Load all the plugins we support directly 52 */ 53 protected function initializePlugins() { 54 $this->plugins['sqlite'] = plugin_load('helper', 'sqlite'); 55 if($this->plugins['sqlite']) { 56 $this->plugins['tagging'] = plugin_load('helper', 'tagging'); 57 $this->plugins['magicmatcher'] = plugin_load('syntax', 'magicmatcher_issuelist'); 58 } 59 $this->plugins['tplinc'] = plugin_load('helper', 'tplinc'); 60 $this->plugins['sitemapnavi'] = plugin_load('helper', 'sitemapnavi'); 61 } 62 63 /** 64 * Makes include position info available to the tplinc plugin 65 * 66 * @param \Doku_Event $event 67 */ 68 public function registerIncludes(\Doku_Event $event) { 69 $event->data['footer'] = 'Footer below the page content'; 70 $event->data['sidebarfooter'] = 'Footer below the sidebar'; 71 $event->data['sidebarheader'] = 'Header above the sidebar'; 72 $event->data['navtop'] = 'Additional navigation items at the top'; 73 $event->data['navbottom'] = 'Additional navigation items at the bottom'; 74 } 75 76 /** 77 * Get the content to include from the tplinc plugin 78 * 79 * prefix and postfix are only added when there actually is any content 80 * 81 * @param string $location 82 * @param string $pre prepend this before the content 83 * @param string $post append this to the content 84 * @return string 85 */ 86 public function getInclude($location, $pre = '', $post = '') { 87 if(!$this->plugins['tplinc']) return ''; 88 $content = $this->plugins['tplinc']->renderIncludes($location); 89 if($content === '') return ''; 90 return $pre . $content . $post; 91 } 92 93 /** 94 * Sets a cookie to remember the requested special navigation 95 */ 96 protected function initNavigationCookie() { 97 if ($this->plugins['sitemapnavi'] === null) return; 98 global $INPUT; 99 100 $nav = $INPUT->str('nav'); 101 if($nav) { 102 set_doku_pref('nav', $nav); 103 $this->nav = $INPUT->str('nav'); 104 } else { 105 $this->nav = get_doku_pref('nav', 'sidebar'); 106 } 107 } 108 109 /** 110 * Return the navigation for the sidebar 111 * 112 * Defaults to the standard sidebar mechanism, but supports also the sitemapnavi plugin 113 * 114 * @return string 115 */ 116 public function getNavigation() { 117 global $ID; 118 global $conf; 119 120 // id of the current sidebar, each sidebar must have its own state 121 $header = sprintf('<div id="sidebarId" class="%s"></div>', md5(page_findnearest($conf['sidebar']))); 122 // add tabs if multiple navigation types available 123 if ($this->plugins['sitemapnavi'] !== null) { 124 $header .= '<ul class="sidebar-tabs">'; 125 $header .= '<li class="' . ($this->nav === 'sidebar' ? 'active' : '') . '">' . 126 '<a href="' . wl($ID, ['nav' => 'sidebar']) . '">'.tpl_getLang('nav_sidebar').'</a></li>'; 127 $header .= '<li class="' . ($this->nav === 'sitemap' ? 'active' : '') . '">' . 128 '<a href="' . wl($ID, ['nav' => 'sitemap']) . '">'.tpl_getLang('nav_sitemap').'</a></li>'; 129 $header .= '</ul>'; 130 } 131 132 // decide what to show 133 if ($this->nav === 'sitemap') { 134 // site tree created by sitemapnavi plugin 135 $nav = '<nav class="nav-sitemapnavi" id="plugin__sitemapnavi">'; 136 $nav .= $this->plugins['sitemapnavi']->getSiteMap(':'); 137 $nav .= '</nav>'; 138 } else { 139 // main navigation, loaded from standard sidebar, fixed up by javascript 140 $nav = '<nav class="nav-main">'; 141 // immeadiately hide the navigation (if javascript available) 142 // it will be restyled and made visible again by our script later 143 $nav .= '<script type="application/javascript"> 144 document.getElementsByClassName("nav-main")[0].style.visibility = "hidden"; 145 </script>'; 146 147 $nav .= $this->getInclude('navtop'); 148 $nav .= tpl_include_page($conf['sidebar'], false, true); 149 $nav .= $this->getInclude('navbottom'); 150 $nav .= '</nav>'; 151 } 152 153 return $header . $nav; 154 } 155 156 /** 157 * Default class defining is the sidebar should collapse 158 * 159 * @return string 160 */ 161 public function fullWidthClass() { 162 global $ACT; 163 // no auto collapsing? empty class 164 if (!tpl_getConf('autocollapse')) return ''; 165 // mode show? empty class 166 if ($ACT === "show") return ''; 167 // anything else? wide content 168 return 'wide-content '; 169 } 170 171 /** 172 * Get all the tabs to display 173 * 174 * @return array 175 */ 176 public function getMetaBoxTabs() { 177 global $lang, $INFO; 178 $tabs = array(); 179 180 $toc = tpl_toc(true); 181 if($toc) { 182 $tabs[] = array( 183 'id' => 'spr__tab-toc', 184 'label' => $lang['toc'], 185 'tab' => $toc, 186 'count' => null, 187 ); 188 } 189 190 if($this->plugins['tagging']) { 191 $tabs[] = array( 192 'id' => 'spr__tab-tags', 193 'label' => tpl_getLang('tab_tags'), 194 'tab' => $this->plugins['tagging']->tpl_tags(false), 195 'count' => count($this->plugins['tagging']->findItems(array('pid' => $INFO['id']), 'tag')), 196 ); 197 } 198 199 if ($this->plugins['magicmatcher']) { 200 $tabs[] = array( 201 'id' => 'spr__tab-issues', 202 'label' => tpl_getLang('tab_issues'), 203 'tab' => $this->plugins['magicmatcher']->getIssueListHTML(), 204 'count' => $this->plugins['magicmatcher']->getCountIssues(), 205 ); 206 } 207 208 return $tabs; 209 } 210 211 /** 212 * Creates an image tag and includes the first found image correctly resized 213 * 214 * @param string $tag 215 * @param array $attributes 216 * @param int $w 217 * @param int $h 218 * @param bool $crop 219 * @return string 220 */ 221 public static function getResizedImgTag($tag, $attributes, $w, $h, $crop = true) { 222 $attr = ''; 223 $medias = array(); 224 225 // the attribute having an array defines where the image goes 226 foreach($attributes as $attribute => $data) { 227 if(is_array($data)) { 228 $medias = $data; 229 $attr = $attribute; 230 } 231 } 232 // if the image attribute could not be found return 233 if(!$attr || !$medias) return ''; 234 235 // try all medias until an existing one is found 236 $media = ''; 237 foreach($medias as $media) { 238 if(file_exists(mediaFN($media))) break; 239 $media = ''; 240 } 241 if($media === '') return ''; 242 243 // replace the array 244 $media = ml($media, array('w' => $w, 'h' => $h, 'crop' => (int) $crop), true, '&'); 245 $attributes[$attr] = $media; 246 247 // return the full tag 248 return '<' . $tag . ' ' . buildAttributes($attributes) . ' />' . "\n"; 249 } 250 251 /** 252 * Embed the main logo 253 * 254 * Tries a few different locations 255 */ 256 public function mainLogo() { 257 global $conf; 258 259 // homepage logo should not link to itself (BITV accessibility requirement) 260 $linkit = (strcmp(wl(), $_SERVER['REQUEST_URI']) !== 0); 261 if($linkit) { 262 $title = $conf['title'] . tpl_getLang('adjunct_linked_logo_text'); 263 } else { 264 $title = tpl_getLang('adjunct_start_logo_text') . $conf['title']; 265 } 266 267 $desktop = self::getResizedImgTag( 268 'img', 269 array( 270 'class' => 'mobile-hide', 271 'src' => array('wiki:logo-wide.svg', 'wiki:logo.svg', 'wiki:logo-wide.png', 'wiki:logo.png'), 272 'alt' => $title, 273 ), 274 0, 250, false 275 ); 276 $mobile = self::getResizedImgTag( 277 'img', 278 array( 279 'class' => 'mobile-only', 280 'src' => array( 281 'wiki:logo-32x32.svg', 'wiki:favicon.svg', 'wiki:logo-square.svg', 'wiki:logo.svg', 282 'wiki:logo-32x32.png', 'wiki:favicon.png', 'wiki:logo-square.png', 'wiki:logo.png' 283 ), 284 'alt' => $title, 285 ), 286 32, 32 287 ); 288 289 // homepage logo should not link to itself (BITV accessibility requirement) 290 if($linkit) { 291 tpl_link(wl(), $desktop, 'accesskey="h" title="[H]"'); 292 tpl_link(wl(), $mobile, 'accesskey="h" title="[H]"'); 293 } else { 294 echo $desktop; 295 echo $mobile; 296 } 297 } 298 299 /** 300 * Add the current mode information to the hierarchical breadcrumbs 301 */ 302 public function breadcrumbSuffix() { 303 global $ACT; 304 global $lang; 305 global $INPUT; 306 global $ID; 307 global $conf; 308 global $IMG; 309 if($ACT == 'show') return; 310 311 // find an apropriate label for the current mode 312 if($ACT) { 313 $label = tpl_getLang('mode_' . $ACT); 314 if(!$label) { 315 if(isset($lang['btn_' . $ACT])) { 316 $label = $lang['btn_' . $ACT]; 317 } else { 318 $label = $ACT; 319 } 320 } 321 } else { 322 // actually we would need to create a proper namespace breadcrumb path here, 323 // but this is the most simplest thing we can do for now 324 if(defined('DOKU_MEDIADETAIL')) { 325 $label = hsc(noNS($IMG)); 326 } else { 327 return; 328 } 329 } 330 331 if($ACT == 'admin' && $INPUT->has('page')) { 332 $link = wl($ID, array('do' => 'admin')); 333 echo '<bdi> : <a href="' . $link . '"><strong>' . $label . '</strong></a></bdi>'; 334 335 /** @var \DokuWiki_Admin_Plugin $plugin */ 336 $plugin = plugin_load('admin', $INPUT->str('page')); 337 if(!$plugin) return; 338 339 $label = $plugin->getMenuText($conf['lang']); 340 } 341 342 echo '<bdi><span class="curid"> : <strong>' . $label . '</strong></span></bdi>'; 343 } 344} 345