You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

345 lines
11 KiB

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