12387fd46SAndreas Gohr<?php 22387fd46SAndreas Gohr 32387fd46SAndreas Gohrnamespace dokuwiki\template\sprintdoc; 42387fd46SAndreas Gohr 52387fd46SAndreas Gohr/** 62387fd46SAndreas Gohr * Class Template 72387fd46SAndreas Gohr * 82387fd46SAndreas Gohr * provides additional logic for the sprintdoc template 92387fd46SAndreas Gohr * 102387fd46SAndreas Gohr * @package dokuwiki\template\sprintdoc 112387fd46SAndreas Gohr */ 122387fd46SAndreas Gohrclass Template { 132387fd46SAndreas Gohr 14c1e0eaa8SAndreas Gohr /** @var array loaded plugins */ 152387fd46SAndreas Gohr protected $plugins = array( 162387fd46SAndreas Gohr 'sqlite' => null, 172387fd46SAndreas Gohr 'tagging' => null, 181f3641a8SMichael Große 'magicmatcher' => null, 19c1e0eaa8SAndreas Gohr 'tplinc' => null, 20c1e0eaa8SAndreas Gohr 'sitemapnavi' => null, 212387fd46SAndreas Gohr ); 222387fd46SAndreas Gohr 23c1e0eaa8SAndreas Gohr /** @var string the type of special navigation to use */ 24c1e0eaa8SAndreas Gohr protected $nav = ''; 25c1e0eaa8SAndreas Gohr 26c1e0eaa8SAndreas Gohr 272387fd46SAndreas Gohr /** 282387fd46SAndreas Gohr * Get the singleton instance 292387fd46SAndreas Gohr * 302387fd46SAndreas Gohr * @return Template 312387fd46SAndreas Gohr */ 322387fd46SAndreas Gohr public static function getInstance() { 332387fd46SAndreas Gohr static $instance = null; 342387fd46SAndreas Gohr if($instance === null) $instance = new Template(); 352387fd46SAndreas Gohr return $instance; 362387fd46SAndreas Gohr } 372387fd46SAndreas Gohr 382387fd46SAndreas Gohr /** 392387fd46SAndreas Gohr * Template constructor. 402387fd46SAndreas Gohr */ 412387fd46SAndreas Gohr protected function __construct() { 422387fd46SAndreas Gohr $this->initializePlugins(); 43c1e0eaa8SAndreas Gohr $this->initNavigationCookie(); 44cad2e674SAndreas Gohr 45cad2e674SAndreas Gohr /** @var \Doku_Event_Handler */ 46cad2e674SAndreas Gohr global $EVENT_HANDLER; 47cad2e674SAndreas Gohr $EVENT_HANDLER->register_hook('PLUGIN_TPLINC_LOCATIONS_SET', 'BEFORE', $this, 'registerIncludes'); 48cad2e674SAndreas Gohr } 49cad2e674SAndreas Gohr 50cad2e674SAndreas Gohr /** 51c1e0eaa8SAndreas Gohr * Load all the plugins we support directly 52c1e0eaa8SAndreas Gohr */ 53c1e0eaa8SAndreas Gohr protected function initializePlugins() { 54c1e0eaa8SAndreas Gohr $this->plugins['sqlite'] = plugin_load('helper', 'sqlite'); 55c1e0eaa8SAndreas Gohr if($this->plugins['sqlite']) { 56c1e0eaa8SAndreas Gohr $this->plugins['tagging'] = plugin_load('helper', 'tagging'); 57c1e0eaa8SAndreas Gohr $this->plugins['magicmatcher'] = plugin_load('syntax', 'magicmatcher_issuelist'); 58c1e0eaa8SAndreas Gohr } 59c1e0eaa8SAndreas Gohr $this->plugins['tplinc'] = plugin_load('helper', 'tplinc'); 60c1e0eaa8SAndreas Gohr $this->plugins['sitemapnavi'] = plugin_load('helper', 'sitemapnavi'); 61c1e0eaa8SAndreas Gohr } 62c1e0eaa8SAndreas Gohr 63c1e0eaa8SAndreas Gohr /** 64cad2e674SAndreas Gohr * Makes include position info available to the tplinc plugin 65cad2e674SAndreas Gohr * 66cad2e674SAndreas Gohr * @param \Doku_Event $event 67cad2e674SAndreas Gohr */ 68cad2e674SAndreas Gohr public function registerIncludes(\Doku_Event $event) { 69cad2e674SAndreas Gohr $event->data['footer'] = 'Footer below the page content'; 70485e7ff4SMichael Große $event->data['sidebarfooter'] = 'Footer below the sidebar'; 71485e7ff4SMichael Große $event->data['sidebarheader'] = 'Header above the sidebar'; 72*9510c080SAndreas Gohr $event->data['navtop'] = 'Additional navigation items at the top'; 73*9510c080SAndreas Gohr $event->data['navbottom'] = 'Additional navigation items at the bottom'; 74cad2e674SAndreas Gohr } 75cad2e674SAndreas Gohr 76cad2e674SAndreas Gohr /** 77cad2e674SAndreas Gohr * Get the content to include from the tplinc plugin 78cad2e674SAndreas Gohr * 79cad2e674SAndreas Gohr * prefix and postfix are only added when there actually is any content 80cad2e674SAndreas Gohr * 81cad2e674SAndreas Gohr * @param string $location 82cad2e674SAndreas Gohr * @param string $pre prepend this before the content 83cad2e674SAndreas Gohr * @param string $post append this to the content 84cad2e674SAndreas Gohr * @return string 85cad2e674SAndreas Gohr */ 86cad2e674SAndreas Gohr public function getInclude($location, $pre = '', $post = '') { 87cad2e674SAndreas Gohr if(!$this->plugins['tplinc']) return ''; 88cad2e674SAndreas Gohr $content = $this->plugins['tplinc']->renderIncludes($location); 89cad2e674SAndreas Gohr if($content === '') return ''; 90cad2e674SAndreas Gohr return $pre . $content . $post; 912387fd46SAndreas Gohr } 922387fd46SAndreas Gohr 932387fd46SAndreas Gohr /** 94c1e0eaa8SAndreas Gohr * Sets a cookie to remember the requested special navigation 952387fd46SAndreas Gohr */ 96c1e0eaa8SAndreas Gohr protected function initNavigationCookie() { 97c1e0eaa8SAndreas Gohr if ($this->plugins['sitemapnavi'] === null) return; 98c1e0eaa8SAndreas Gohr global $INPUT; 99c1e0eaa8SAndreas Gohr 100c1e0eaa8SAndreas Gohr $nav = $INPUT->str('nav'); 101c1e0eaa8SAndreas Gohr if($nav) { 102c1e0eaa8SAndreas Gohr set_doku_pref('nav', $nav); 103c1e0eaa8SAndreas Gohr $this->nav = $INPUT->str('nav'); 104c1e0eaa8SAndreas Gohr } else { 105c1e0eaa8SAndreas Gohr $this->nav = get_doku_pref('nav', 'sidebar'); 1062387fd46SAndreas Gohr } 107c1e0eaa8SAndreas Gohr } 108c1e0eaa8SAndreas Gohr 109c1e0eaa8SAndreas Gohr /** 110c1e0eaa8SAndreas Gohr * Return the navigation for the sidebar 111c1e0eaa8SAndreas Gohr * 112c1e0eaa8SAndreas Gohr * Defaults to the standard sidebar mechanism, but supports also the sitemapnavi plugin 113c1e0eaa8SAndreas Gohr * 114c1e0eaa8SAndreas Gohr * @return string 115c1e0eaa8SAndreas Gohr */ 116c1e0eaa8SAndreas Gohr public function getNavigation() { 117c1e0eaa8SAndreas Gohr global $ID; 118c1e0eaa8SAndreas Gohr global $conf; 119c1e0eaa8SAndreas Gohr 120e78ffc6cSAnna Dabrowska // id of the current sidebar, each sidebar must have its own state 12175a0a8e4SAnna Dabrowska $header = sprintf('<div id="sidebarId" class="%s"></div>', md5(page_findnearest($conf['sidebar']))); 122c1e0eaa8SAndreas Gohr // add tabs if multiple navigation types available 123c1e0eaa8SAndreas Gohr if ($this->plugins['sitemapnavi'] !== null) { 124e78ffc6cSAnna Dabrowska $header .= '<ul class="sidebar-tabs">'; 125c1e0eaa8SAndreas Gohr $header .= '<li class="' . ($this->nav === 'sidebar' ? 'active' : '') . '">' . 126c1e0eaa8SAndreas Gohr '<a href="' . wl($ID, ['nav' => 'sidebar']) . '">'.tpl_getLang('nav_sidebar').'</a></li>'; 127c1e0eaa8SAndreas Gohr $header .= '<li class="' . ($this->nav === 'sitemap' ? 'active' : '') . '">' . 128c1e0eaa8SAndreas Gohr '<a href="' . wl($ID, ['nav' => 'sitemap']) . '">'.tpl_getLang('nav_sitemap').'</a></li>'; 129c1e0eaa8SAndreas Gohr $header .= '</ul>'; 130c1e0eaa8SAndreas Gohr } 131c1e0eaa8SAndreas Gohr 132c1e0eaa8SAndreas Gohr // decide what to show 133046583e2SAndreas Gohr if ($this->nav === 'sitemap') { 134c1e0eaa8SAndreas Gohr // site tree created by sitemapnavi plugin 135c1e0eaa8SAndreas Gohr $nav = '<nav class="nav-sitemapnavi" id="plugin__sitemapnavi">'; 136c1e0eaa8SAndreas Gohr $nav .= $this->plugins['sitemapnavi']->getSiteMap(':'); 137c1e0eaa8SAndreas Gohr $nav .= '</nav>'; 138c1e0eaa8SAndreas Gohr } else { 139c1e0eaa8SAndreas Gohr // main navigation, loaded from standard sidebar, fixed up by javascript 140c1e0eaa8SAndreas Gohr $nav = '<nav class="nav-main">'; 1414ac10cf3SAndreas Gohr // immeadiately hide the navigation (if javascript available) 1424ac10cf3SAndreas Gohr // it will be restyled and made visible again by our script later 1434ac10cf3SAndreas Gohr $nav .= '<script type="application/javascript"> 1444ac10cf3SAndreas Gohr document.getElementsByClassName("nav-main")[0].style.visibility = "hidden"; 1454ac10cf3SAndreas Gohr </script>'; 146*9510c080SAndreas Gohr 147*9510c080SAndreas Gohr $nav .= $this->getInclude('navtop'); 148c1e0eaa8SAndreas Gohr $nav .= tpl_include_page($conf['sidebar'], false, true); 149*9510c080SAndreas Gohr $nav .= $this->getInclude('navbottom'); 150c1e0eaa8SAndreas Gohr $nav .= '</nav>'; 151c1e0eaa8SAndreas Gohr } 152c1e0eaa8SAndreas Gohr 153c1e0eaa8SAndreas Gohr return $header . $nav; 1542387fd46SAndreas Gohr } 1552387fd46SAndreas Gohr 1562387fd46SAndreas Gohr /** 1573e1e2a1fSAndreas Gohr * Default class defining is the sidebar should collapse 1583e1e2a1fSAndreas Gohr * 1593e1e2a1fSAndreas Gohr * @return string 1603e1e2a1fSAndreas Gohr */ 1613e1e2a1fSAndreas Gohr public function fullWidthClass() { 1623e1e2a1fSAndreas Gohr global $ACT; 1633e1e2a1fSAndreas Gohr // no auto collapsing? empty class 1643e1e2a1fSAndreas Gohr if (!tpl_getConf('autocollapse')) return ''; 1653e1e2a1fSAndreas Gohr // mode show? empty class 1663e1e2a1fSAndreas Gohr if ($ACT === "show") return ''; 1673e1e2a1fSAndreas Gohr // anything else? wide content 1683e1e2a1fSAndreas Gohr return 'wide-content '; 1693e1e2a1fSAndreas Gohr } 1703e1e2a1fSAndreas Gohr 1713e1e2a1fSAndreas Gohr /** 1722387fd46SAndreas Gohr * Get all the tabs to display 1732387fd46SAndreas Gohr * 1742387fd46SAndreas Gohr * @return array 1752387fd46SAndreas Gohr */ 1762387fd46SAndreas Gohr public function getMetaBoxTabs() { 17767d7dea5SMichael Große global $lang, $INFO; 1782387fd46SAndreas Gohr $tabs = array(); 1792387fd46SAndreas Gohr 1802387fd46SAndreas Gohr $toc = tpl_toc(true); 1812387fd46SAndreas Gohr if($toc) { 1822387fd46SAndreas Gohr $tabs[] = array( 1832387fd46SAndreas Gohr 'id' => 'spr__tab-toc', 1842387fd46SAndreas Gohr 'label' => $lang['toc'], 1852387fd46SAndreas Gohr 'tab' => $toc, 1862387fd46SAndreas Gohr 'count' => null, 1872387fd46SAndreas Gohr ); 1882387fd46SAndreas Gohr } 1892387fd46SAndreas Gohr 1902387fd46SAndreas Gohr if($this->plugins['tagging']) { 1912387fd46SAndreas Gohr $tabs[] = array( 1922387fd46SAndreas Gohr 'id' => 'spr__tab-tags', 1932387fd46SAndreas Gohr 'label' => tpl_getLang('tab_tags'), 1942387fd46SAndreas Gohr 'tab' => $this->plugins['tagging']->tpl_tags(false), 19567d7dea5SMichael Große 'count' => count($this->plugins['tagging']->findItems(array('pid' => $INFO['id']), 'tag')), 1962387fd46SAndreas Gohr ); 1972387fd46SAndreas Gohr } 1982387fd46SAndreas Gohr 1991f3641a8SMichael Große if ($this->plugins['magicmatcher']) { 2001f3641a8SMichael Große $tabs[] = array( 2011f3641a8SMichael Große 'id' => 'spr__tab-issues', 2029cae5e77SMichael Große 'label' => tpl_getLang('tab_issues'), 2031f3641a8SMichael Große 'tab' => $this->plugins['magicmatcher']->getIssueListHTML(), 2041f3641a8SMichael Große 'count' => $this->plugins['magicmatcher']->getCountIssues(), 2051f3641a8SMichael Große ); 2061f3641a8SMichael Große } 2072387fd46SAndreas Gohr 2082387fd46SAndreas Gohr return $tabs; 2092387fd46SAndreas Gohr } 21006cdf148SAndreas Gohr 21106cdf148SAndreas Gohr /** 21206cdf148SAndreas Gohr * Creates an image tag and includes the first found image correctly resized 21306cdf148SAndreas Gohr * 21406cdf148SAndreas Gohr * @param string $tag 21506cdf148SAndreas Gohr * @param array $attributes 21606cdf148SAndreas Gohr * @param int $w 21706cdf148SAndreas Gohr * @param int $h 21819958800SAndreas Gohr * @param bool $crop 21906cdf148SAndreas Gohr * @return string 22006cdf148SAndreas Gohr */ 22119958800SAndreas Gohr public static function getResizedImgTag($tag, $attributes, $w, $h, $crop = true) { 22206cdf148SAndreas Gohr $attr = ''; 22306cdf148SAndreas Gohr $medias = array(); 22406cdf148SAndreas Gohr 22506cdf148SAndreas Gohr // the attribute having an array defines where the image goes 22606cdf148SAndreas Gohr foreach($attributes as $attribute => $data) { 22706cdf148SAndreas Gohr if(is_array($data)) { 22806cdf148SAndreas Gohr $medias = $data; 22906cdf148SAndreas Gohr $attr = $attribute; 23006cdf148SAndreas Gohr } 23106cdf148SAndreas Gohr } 23206cdf148SAndreas Gohr // if the image attribute could not be found return 23306cdf148SAndreas Gohr if(!$attr || !$medias) return ''; 23406cdf148SAndreas Gohr 23506cdf148SAndreas Gohr // try all medias until an existing one is found 23606cdf148SAndreas Gohr $media = ''; 23706cdf148SAndreas Gohr foreach($medias as $media) { 23806cdf148SAndreas Gohr if(file_exists(mediaFN($media))) break; 23906cdf148SAndreas Gohr $media = ''; 24006cdf148SAndreas Gohr } 24106cdf148SAndreas Gohr if($media === '') return ''; 24206cdf148SAndreas Gohr 24306cdf148SAndreas Gohr // replace the array 24419958800SAndreas Gohr $media = ml($media, array('w' => $w, 'h' => $h, 'crop' => (int) $crop), true, '&'); 24506cdf148SAndreas Gohr $attributes[$attr] = $media; 24606cdf148SAndreas Gohr 24706cdf148SAndreas Gohr // return the full tag 2489dbc42beSAndreas Gohr return '<' . $tag . ' ' . buildAttributes($attributes) . ' />' . "\n"; 24906cdf148SAndreas Gohr } 2503a6eaa0bSAndreas Gohr 2513a6eaa0bSAndreas Gohr /** 2523a6eaa0bSAndreas Gohr * Embed the main logo 2533a6eaa0bSAndreas Gohr * 2543a6eaa0bSAndreas Gohr * Tries a few different locations 2553a6eaa0bSAndreas Gohr */ 2563a6eaa0bSAndreas Gohr public function mainLogo() { 2573a6eaa0bSAndreas Gohr global $conf; 2583a6eaa0bSAndreas Gohr 259e17d84d6SAndreas Gohr // homepage logo should not link to itself (BITV accessibility requirement) 260e17d84d6SAndreas Gohr $linkit = (strcmp(wl(), $_SERVER['REQUEST_URI']) !== 0); 261e17d84d6SAndreas Gohr if($linkit) { 262e17d84d6SAndreas Gohr $title = $conf['title'] . tpl_getLang('adjunct_linked_logo_text'); 263e17d84d6SAndreas Gohr } else { 264e17d84d6SAndreas Gohr $title = tpl_getLang('adjunct_start_logo_text') . $conf['title']; 265e17d84d6SAndreas Gohr } 266e17d84d6SAndreas Gohr 2673a6eaa0bSAndreas Gohr $desktop = self::getResizedImgTag( 2683a6eaa0bSAndreas Gohr 'img', 2693a6eaa0bSAndreas Gohr array( 2703a6eaa0bSAndreas Gohr 'class' => 'mobile-hide', 271f9746258SAndreas Gohr 'src' => array('wiki:logo-wide.svg', 'wiki:logo.svg', 'wiki:logo-wide.png', 'wiki:logo.png'), 272e17d84d6SAndreas Gohr 'alt' => $title, 2733a6eaa0bSAndreas Gohr ), 27499cb0c43SAndreas Gohr 0, 250, false 2753a6eaa0bSAndreas Gohr ); 2763a6eaa0bSAndreas Gohr $mobile = self::getResizedImgTag( 2773a6eaa0bSAndreas Gohr 'img', 2783a6eaa0bSAndreas Gohr array( 2793a6eaa0bSAndreas Gohr 'class' => 'mobile-only', 280f9746258SAndreas Gohr 'src' => array( 281f9746258SAndreas Gohr 'wiki:logo-32x32.svg', 'wiki:favicon.svg', 'wiki:logo-square.svg', 'wiki:logo.svg', 282f9746258SAndreas Gohr 'wiki:logo-32x32.png', 'wiki:favicon.png', 'wiki:logo-square.png', 'wiki:logo.png' 283f9746258SAndreas Gohr ), 284e17d84d6SAndreas Gohr 'alt' => $title, 2853a6eaa0bSAndreas Gohr ), 2863a6eaa0bSAndreas Gohr 32, 32 2873a6eaa0bSAndreas Gohr ); 2883a6eaa0bSAndreas Gohr 2893a6eaa0bSAndreas Gohr // homepage logo should not link to itself (BITV accessibility requirement) 290e17d84d6SAndreas Gohr if($linkit) { 2913a6eaa0bSAndreas Gohr tpl_link(wl(), $desktop, 'accesskey="h" title="[H]"'); 2923a6eaa0bSAndreas Gohr tpl_link(wl(), $mobile, 'accesskey="h" title="[H]"'); 293e17d84d6SAndreas Gohr } else { 294e17d84d6SAndreas Gohr echo $desktop; 295e17d84d6SAndreas Gohr echo $mobile; 2963a6eaa0bSAndreas Gohr } 2973a6eaa0bSAndreas Gohr } 29884f94641SAndreas Gohr 29984f94641SAndreas Gohr /** 30084f94641SAndreas Gohr * Add the current mode information to the hierarchical breadcrumbs 30184f94641SAndreas Gohr */ 30284f94641SAndreas Gohr public function breadcrumbSuffix() { 30384f94641SAndreas Gohr global $ACT; 30484f94641SAndreas Gohr global $lang; 30584f94641SAndreas Gohr global $INPUT; 30684f94641SAndreas Gohr global $ID; 30784f94641SAndreas Gohr global $conf; 30884f94641SAndreas Gohr global $IMG; 30984f94641SAndreas Gohr if($ACT == 'show') return; 31084f94641SAndreas Gohr 31184f94641SAndreas Gohr // find an apropriate label for the current mode 31284f94641SAndreas Gohr if($ACT) { 31384f94641SAndreas Gohr $label = tpl_getLang('mode_' . $ACT); 31484f94641SAndreas Gohr if(!$label) { 31584f94641SAndreas Gohr if(isset($lang['btn_' . $ACT])) { 31684f94641SAndreas Gohr $label = $lang['btn_' . $ACT]; 31784f94641SAndreas Gohr } else { 31884f94641SAndreas Gohr $label = $ACT; 31984f94641SAndreas Gohr } 32084f94641SAndreas Gohr } 32184f94641SAndreas Gohr } else { 32284f94641SAndreas Gohr // actually we would need to create a proper namespace breadcrumb path here, 32384f94641SAndreas Gohr // but this is the most simplest thing we can do for now 32484f94641SAndreas Gohr if(defined('DOKU_MEDIADETAIL')) { 32584f94641SAndreas Gohr $label = hsc(noNS($IMG)); 32684f94641SAndreas Gohr } else { 32784f94641SAndreas Gohr return; 32884f94641SAndreas Gohr } 32984f94641SAndreas Gohr } 33084f94641SAndreas Gohr 33184f94641SAndreas Gohr if($ACT == 'admin' && $INPUT->has('page')) { 33284f94641SAndreas Gohr $link = wl($ID, array('do' => 'admin')); 33384f94641SAndreas Gohr echo '<bdi> : <a href="' . $link . '"><strong>' . $label . '</strong></a></bdi>'; 33484f94641SAndreas Gohr 33584f94641SAndreas Gohr /** @var \DokuWiki_Admin_Plugin $plugin */ 33684f94641SAndreas Gohr $plugin = plugin_load('admin', $INPUT->str('page')); 33784f94641SAndreas Gohr if(!$plugin) return; 33884f94641SAndreas Gohr 33984f94641SAndreas Gohr $label = $plugin->getMenuText($conf['lang']); 34084f94641SAndreas Gohr } 34184f94641SAndreas Gohr 34284f94641SAndreas Gohr echo '<bdi><span class="curid"> : <strong>' . $label . '</strong></span></bdi>'; 34384f94641SAndreas Gohr } 3442387fd46SAndreas Gohr} 345