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