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 * Get all the tabs to display 153 * 154 * @return array 155 */ 156 public function getMetaBoxTabs() { 157 global $lang, $INFO; 158 $tabs = array(); 159 160 $toc = tpl_toc(true); 161 if($toc) { 162 $tabs[] = array( 163 'id' => 'spr__tab-toc', 164 'label' => $lang['toc'], 165 'tab' => $toc, 166 'count' => null, 167 ); 168 } 169 170 if($this->plugins['tagging']) { 171 $tabs[] = array( 172 'id' => 'spr__tab-tags', 173 'label' => tpl_getLang('tab_tags'), 174 'tab' => $this->plugins['tagging']->tpl_tags(false), 175 'count' => count($this->plugins['tagging']->findItems(array('pid' => $INFO['id']), 'tag')), 176 ); 177 } 178 179 if ($this->plugins['magicmatcher']) { 180 $tabs[] = array( 181 'id' => 'spr__tab-issues', 182 'label' => tpl_getLang('tab_issues'), 183 'tab' => $this->plugins['magicmatcher']->getIssueListHTML(), 184 'count' => $this->plugins['magicmatcher']->getCountIssues(), 185 ); 186 } 187 188 return $tabs; 189 } 190 191 /** 192 * Creates an image tag and includes the first found image correctly resized 193 * 194 * @param string $tag 195 * @param array $attributes 196 * @param int $w 197 * @param int $h 198 * @param bool $crop 199 * @return string 200 */ 201 public static function getResizedImgTag($tag, $attributes, $w, $h, $crop = true) { 202 $attr = ''; 203 $medias = array(); 204 205 // the attribute having an array defines where the image goes 206 foreach($attributes as $attribute => $data) { 207 if(is_array($data)) { 208 $medias = $data; 209 $attr = $attribute; 210 } 211 } 212 // if the image attribute could not be found return 213 if(!$attr || !$medias) return ''; 214 215 // try all medias until an existing one is found 216 $media = ''; 217 foreach($medias as $media) { 218 if(file_exists(mediaFN($media))) break; 219 $media = ''; 220 } 221 if($media === '') return ''; 222 223 // replace the array 224 $media = ml($media, array('w' => $w, 'h' => $h, 'crop' => (int) $crop), true, '&'); 225 $attributes[$attr] = $media; 226 227 // return the full tag 228 return '<' . $tag . ' ' . buildAttributes($attributes) . ' />' . "\n"; 229 } 230 231 /** 232 * Embed the main logo 233 * 234 * Tries a few different locations 235 */ 236 public function mainLogo() { 237 global $conf; 238 239 // homepage logo should not link to itself (BITV accessibility requirement) 240 $linkit = (strcmp(wl(), $_SERVER['REQUEST_URI']) !== 0); 241 if($linkit) { 242 $title = $conf['title'] . tpl_getLang('adjunct_linked_logo_text'); 243 } else { 244 $title = tpl_getLang('adjunct_start_logo_text') . $conf['title']; 245 } 246 247 $desktop = self::getResizedImgTag( 248 'img', 249 array( 250 'class' => 'mobile-hide', 251 'src' => array('wiki:logo-wide.png', 'wiki:logo.png'), 252 'alt' => $title, 253 ), 254 0, 50, false 255 ); 256 $mobile = self::getResizedImgTag( 257 'img', 258 array( 259 'class' => 'mobile-only', 260 'src' => array('wiki:logo-32x32.png', 'wiki:favicon.png', 'wiki:logo-square.png', 'wiki:logo.png'), 261 'alt' => $title, 262 ), 263 32, 32 264 ); 265 266 // homepage logo should not link to itself (BITV accessibility requirement) 267 if($linkit) { 268 tpl_link(wl(), $desktop, 'accesskey="h" title="[H]"'); 269 tpl_link(wl(), $mobile, 'accesskey="h" title="[H]"'); 270 } else { 271 echo $desktop; 272 echo $mobile; 273 } 274 } 275 276 /** 277 * Add the current mode information to the hierarchical breadcrumbs 278 */ 279 public function breadcrumbSuffix() { 280 global $ACT; 281 global $lang; 282 global $INPUT; 283 global $ID; 284 global $conf; 285 global $IMG; 286 if($ACT == 'show') return; 287 288 // find an apropriate label for the current mode 289 if($ACT) { 290 $label = tpl_getLang('mode_' . $ACT); 291 if(!$label) { 292 if(isset($lang['btn_' . $ACT])) { 293 $label = $lang['btn_' . $ACT]; 294 } else { 295 $label = $ACT; 296 } 297 } 298 } else { 299 // actually we would need to create a proper namespace breadcrumb path here, 300 // but this is the most simplest thing we can do for now 301 if(defined('DOKU_MEDIADETAIL')) { 302 $label = hsc(noNS($IMG)); 303 } else { 304 return; 305 } 306 } 307 308 if($ACT == 'admin' && $INPUT->has('page')) { 309 $link = wl($ID, array('do' => 'admin')); 310 echo '<bdi> : <a href="' . $link . '"><strong>' . $label . '</strong></a></bdi>'; 311 312 /** @var \DokuWiki_Admin_Plugin $plugin */ 313 $plugin = plugin_load('admin', $INPUT->str('page')); 314 if(!$plugin) return; 315 316 $label = $plugin->getMenuText($conf['lang']); 317 } 318 319 echo '<bdi><span class="curid"> : <strong>' . $label . '</strong></span></bdi>'; 320 } 321} 322