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.
 
 
 
 
 

443 lines
17 KiB

  1. <?php
  2. namespace dokuwiki\template\bootstrap3;
  3. /**
  4. * DokuWiki Bootstrap3 Template: Event Handlers Class
  5. *
  6. * @link http://dokuwiki.org/template:bootstrap3
  7. * @author Giuseppe Di Terlizzi <giuseppe.diterlizzi@gmail.com>
  8. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  9. */
  10. class EventHandlers
  11. {
  12. protected $template;
  13. public function __construct(Template $template)
  14. {
  15. $this->template = $template;
  16. /** @var \Doku_Event_Handler */
  17. global $EVENT_HANDLER;
  18. # Event => [ ADVISDE, METHOD ]
  19. $events_dispatcher = [
  20. 'FORM_QUICKSEARCH_OUTPUT' => ['BEFORE', ['search']],
  21. 'FORM_SEARCH_OUTPUT' => ['BEFORE', ['search']],
  22. 'HTML_DRAFTFORM_OUTPUT' => ['BEFORE', ['htmlDraftForm']], # Deprecated (2018-07-29)
  23. 'HTML_EDITFORM_OUTPUT' => ['BEFORE', ['htmlEditForm']], # use FORM_EDIT_OUTPUT in DokuWiki next
  24. 'HTML_LOGINFORM_OUTPUT' => ['BEFORE', ['htmlAccountFormOutput']],
  25. 'HTML_RESENDPWDFORM_OUTPUT' => ['BEFORE', ['htmlAccountFormOutput']],
  26. 'HTML_PROFILEDELETEFORM_OUTPUT' => ['BEFORE', ['htmlAccountFormOutput']],
  27. 'HTML_RECENTFORM_OUTPUT' => ['BEFORE', ['htmlRevisionsFormOutput']],
  28. 'HTML_REGISTERFORM_OUTPUT' => ['BEFORE', ['htmlAccountFormOutput']],
  29. 'HTML_REVISIONSFORM_OUTPUT' => ['BEFORE', ['htmlRevisionsFormOutput']],
  30. 'HTML_SECEDIT_BUTTON' => ['AFTER', ['htmlSecEditButton']],
  31. 'HTML_SUBSCRIBEFORM_OUTPUT' => ['BEFORE', ['htmlAccountFormOutput']],
  32. 'HTML_UPDATEPROFILEFORM_OUTPUT' => ['BEFORE', ['htmlAccountFormOutput']],
  33. 'PLUGIN_TAG_LINK' => ['AFTER', ['pluginTagLink']],
  34. 'PLUGIN_TPLINC_LOCATIONS_SET' => ['BEFORE', ['tplIncPlugin']],
  35. 'SEARCH_QUERY_FULLPAGE' => ['BEFORE', ['search']],
  36. 'SEARCH_QUERY_PAGELOOKUP' => ['BEFORE', ['search']],
  37. 'SEARCH_RESULT_FULLPAGE' => ['BEFORE', ['search']],
  38. 'SEARCH_RESULT_PAGELOOKUP' => ['BEFORE', ['search']],
  39. 'TPL_CONTENT_DISPLAY' => ['BEFORE', ['tplContent']],
  40. 'TPL_METAHEADER_OUTPUT' => ['BEFORE', ['tplMetaHeaderOutput']],
  41. 'FORM_CONFLICT_OUTPUT' => ['BEFORE', ['commonStyles']],
  42. 'FORM_DRAFT_OUTPUT' => ['BEFORE', ['commonStyles']],
  43. 'FORM_EDIT_OUTPUT' => ['BEFORE', ['commonStyles', 'formEditOutput']],
  44. 'FORM_LOGIN_OUTPUT' => ['BEFORE', ['commonStyles', 'formLoginOutput']],
  45. 'FORM_PROFILEDELETE_OUTPUT' => ['BEFORE', ['commonStyles', 'formProfileDeleteOutput']],
  46. 'FORM_RECENT_OUTPUT' => ['BEFORE', ['commonStyles', 'formRevisionsOutput']],
  47. 'FORM_REGISTER_OUTPUT' => ['BEFORE', ['commonStyles', 'formRegisterOutput']],
  48. 'FORM_RESENDPWD_OUTPUT' => ['BEFORE', ['commonStyles', 'formResendPwdOutput']],
  49. 'FORM_REVISIONS_OUTPUT' => ['BEFORE', ['commonStyles', 'formRevisionsOutput']],
  50. 'FORM_SEARCHMEDIA_OUTPUT' => ['BEFORE', ['commonStyles']],
  51. 'FORM_SUBSCRIBE_OUTPUT' => ['BEFORE', ['commonStyles']],
  52. 'FORM_UPDATEPROFILE_OUTPUT' => ['BEFORE', ['commonStyles', 'formUpdateProfileOutput']],
  53. 'FORM_UPLOAD_OUTPUT' => ['BEFORE', ['commonStyles']],
  54. ];
  55. foreach ($events_dispatcher as $event => $data) {
  56. list($advise, $methods) = $data;
  57. foreach ($methods as $method) {
  58. $EVENT_HANDLER->register_hook($event, $advise, $this, $method);
  59. }
  60. }
  61. }
  62. public function test(\Doku_Event $event)
  63. {
  64. msg('<pre>' . hsc(print_r($event, 1)) . '</pre>');
  65. }
  66. public function formLoginOutput(\Doku_Event $event)
  67. {
  68. /** @var dokuwiki\Form\Form $form */
  69. $form = $event->data;
  70. $form->getElementAt($form->findPositionByType('fieldsetopen'))
  71. ->attrs(['data-dw-icon' => 'mdi:account', 'data-dw-icon-target' => 'legend']);
  72. $form->getElementAt($form->findPositionByAttribute('type', 'submit'))
  73. ->addClass('btn-success')->attr('data-dw-icon', 'mdi:lock');
  74. }
  75. public function formResendPwdOutput(\Doku_Event $event)
  76. {
  77. /** @var dokuwiki\Form\Form $form */
  78. $form = $event->data;
  79. $form->getElementAt($form->findPositionByType('fieldsetopen'))
  80. ->attrs(['data-dw-icon' => 'mdi:lock-reset', 'data-dw-icon-target' => 'legend']);
  81. $form->getElementAt($form->findPositionByAttribute('type', 'submit'))
  82. ->addClass('btn-success')->attr('data-dw-icon', 'mdi:arrow-right');
  83. }
  84. public function formRegisterOutput(\Doku_Event $event)
  85. {
  86. /** @var dokuwiki\Form\Form $form */
  87. $form = $event->data;
  88. $form->getElementAt($form->findPositionByType('fieldsetopen'))
  89. ->attrs(['data-dw-icon' => 'mdi:account-plus', 'data-dw-icon-target' => 'legend']);
  90. $form->getElementAt($form->findPositionByAttribute('type', 'submit'))
  91. ->addClass('btn-success')->attr('data-dw-icon', 'mdi:arrow-right');
  92. }
  93. public function formRevisionsOutput(\Doku_Event $event)
  94. {
  95. /** @var dokuwiki\Form\Form $form */
  96. $form = $event->data;
  97. for ($pos = 0; $pos < $form->elementCount(); $pos++) {
  98. $element = $form->getElementAt($pos);
  99. $type = $element->getType();
  100. if ($type == 'html') {
  101. $value = $element->val();
  102. $value = str_replace(['positive', 'negative'], ['positive label label-success', 'negative label label-danger'], $value);
  103. $element->val($value);
  104. }
  105. }
  106. }
  107. public function commonStyles(\Doku_Event $event)
  108. {
  109. /** @var dokuwiki\Form\Form $form */
  110. $form = $event->data;
  111. for ($pos = 0; $pos < $form->elementCount(); $pos++) {
  112. $element = $form->getElementAt($pos);
  113. $type = $element->getType();
  114. if ($type == 'button') {
  115. $element->addClass('btn btn-default mr-2');
  116. }
  117. }
  118. }
  119. public function formUpdateProfileOutput(\Doku_Event $event)
  120. {
  121. /** @var dokuwiki\Form\Form $form */
  122. $form = $event->data;
  123. $form->getElementAt($form->findPositionByAttribute('type', 'submit'))
  124. ->addClass('btn-success')->attr('data-dw-icon', 'mdi:arrow-right');
  125. $form->getElementAt($form->findPositionByType('fieldsetopen'))
  126. ->attrs(['data-dw-icon' => 'mdi:account-card-details-outline', 'data-dw-icon-target' => 'legend']);
  127. }
  128. public function formProfileDeleteOutput(\Doku_Event $event)
  129. {
  130. /** @var dokuwiki\Form\Form $form */
  131. $form = $event->data;
  132. $form->getElementAt($form->findPositionByAttribute('type', 'submit'))
  133. ->addClass('btn-danger')->attr('data-dw-icon', 'mdi:arrow-right');
  134. $form->getElementAt($form->findPositionByType('fieldsetopen'))
  135. ->attrs(['data-dw-icon' => 'mdi:account-remove', 'data-dw-icon-target' => 'legend']);
  136. }
  137. public function formEditOutput(\Doku_Event $event)
  138. {
  139. global $lang;
  140. /** @var dokuwiki\Form\Form $form */
  141. $form = $event->data;
  142. $form->getElementAt($form->findPositionByAttribute('name', 'do[save]'))
  143. ->addClass('btn btn-success mr-2')->attr('data-dw-icon', 'mdi:content-save');
  144. $form->getElementAt($form->findPositionByAttribute('name', 'do[preview]'))
  145. ->addClass('btn btn-default mr-2')->attr('data-dw-icon', 'mdi:file-document-outline');
  146. $form->getElementAt($form->findPositionByAttribute('name', 'do[cancel]'))
  147. ->addClass('btn btn-default mr-2')->attr('data-dw-icon', 'mdi:arrow-left');
  148. }
  149. public function htmlSecEditButton(\Doku_Event $event)
  150. {
  151. $html = new \simple_html_dom;
  152. $html->load($event->result, true, false);
  153. # Section Edit Button
  154. foreach ($html->find('[type=submit]') as $elm) {
  155. $elm->class .= ' btn btn-xs btn-default';
  156. }
  157. # Section Edit icons
  158. foreach ($html->find('.editbutton_section button') as $elm) {
  159. $elm->innertext = iconify('mdi:pencil') . ' ' . $elm->innertext;
  160. }
  161. foreach ($html->find('.editbutton_table button') as $elm) {
  162. $elm->innertext = iconify('mdi:table') . ' ' . $elm->innertext;
  163. }
  164. $event->result = $html->save();
  165. $html->clear();
  166. unset($html);
  167. }
  168. public function htmlAccountFormOutput(\Doku_Event $event)
  169. {
  170. foreach ($event->data->_content as $key => $item) {
  171. if (is_array($item) && isset($item['_elem'])) {
  172. $title_icon = 'account';
  173. $button_class = 'btn btn-success';
  174. $button_icon = 'arrow-right';
  175. switch ($event->name) {
  176. case 'HTML_LOGINFORM_OUTPUT':
  177. $title_icon = 'account';
  178. $button_icon = 'lock';
  179. break;
  180. case 'HTML_UPDATEPROFILEFORM_OUTPUT':
  181. $title_icon = 'account-card-details-outline';
  182. break;
  183. case 'HTML_PROFILEDELETEFORM_OUTPUT':
  184. $title_icon = 'account-remove';
  185. $button_class = 'btn btn-danger';
  186. break;
  187. case 'HTML_REGISTERFORM_OUTPUT':
  188. $title_icon = 'account-plus';
  189. break;
  190. case 'HTML_SUBSCRIBEFORM_OUTPUT':
  191. $title_icon = null;
  192. break;
  193. case 'HTML_RESENDPWDFORM_OUTPUT':
  194. $title_icon = 'lock-reset';
  195. break;
  196. }
  197. // Legend
  198. if ($item['_elem'] == 'openfieldset') {
  199. $event->data->_content[$key]['_legend'] = (($title_icon) ? iconify("mdi:$title_icon") : '') . ' ' . $event->data->_content[$key]['_legend'];
  200. }
  201. // Save button
  202. if (isset($item['type']) && $item['type'] == 'submit') {
  203. $event->data->_content[$key]['class'] = " $button_class";
  204. $event->data->_content[$key]['value'] = (($button_icon) ? iconify("mdi:$button_icon") : '') . ' ' . $event->data->_content[$key]['value'];
  205. }
  206. }
  207. }
  208. }
  209. /**
  210. * Handle HTML_DRAFTFORM_OUTPUT event
  211. *
  212. * @param \Doku_Event $event Event handler
  213. *
  214. * @return void
  215. **/
  216. public function htmlDraftForm(\Doku_Event $event)
  217. {
  218. foreach ($event->data->_content as $key => $item) {
  219. if (is_array($item) && isset($item['_elem'])) {
  220. if ($item['_action'] == 'draftdel') {
  221. $event->data->_content[$key]['class'] = ' btn btn-danger';
  222. $event->data->_content[$key]['value'] = iconify('mdi:close') . ' ' . $event->data->_content[$key]['value'];
  223. }
  224. if ($item['_action'] == 'recover') {
  225. $event->data->_content[$key]['value'] = iconify('mdi:refresh') . ' ' . $event->data->_content[$key]['value'];
  226. }
  227. if ($item['_action'] == 'show') {
  228. $event->data->_content[$key]['value'] = iconify('mdi:arrow-left') . ' ' . $event->data->_content[$key]['value'];
  229. }
  230. }
  231. }
  232. }
  233. /**
  234. * Handle HTML_EDITFORM_OUTPUT and HTML_DRAFTFORM_OUTPUT event
  235. *
  236. * @param \Doku_Event $event Event handler
  237. *
  238. * @return void
  239. **/
  240. public function htmlEditForm(\Doku_Event $event)
  241. {
  242. foreach ($event->data->_content as $key => $item) {
  243. if (is_array($item) && isset($item['_elem'])) {
  244. // Save button
  245. if ($item['_action'] == 'save') {
  246. $event->data->_content[$key]['class'] = ' btn btn-success';
  247. $event->data->_content[$key]['value'] = iconify('mdi:content-save') . ' ' . $event->data->_content[$key]['value'];
  248. }
  249. // Preview and Show buttons
  250. if ($item['_action'] == 'preview' || $item['_action'] == 'show') {
  251. $event->data->_content[$key]['value'] = iconify('mdi:file-document-outline') . ' ' . $event->data->_content[$key]['value'];
  252. }
  253. // Cancel button
  254. if ($item['_action'] == 'cancel') {
  255. $event->data->_content[$key]['value'] = iconify('mdi:arrow-left') . ' ' . $event->data->_content[$key]['value'];
  256. }
  257. }
  258. }
  259. }
  260. /**
  261. * Handle HTML_REVISIONSFORM_OUTPUT and HTML_RECENTFORM_OUTPUT events
  262. *
  263. * @param \Doku_Event $event Event handler
  264. *
  265. * @return void
  266. **/
  267. public function htmlRevisionsFormOutput(\Doku_Event $event)
  268. {
  269. foreach ($event->data->_content as $key => $item) {
  270. // Revision form
  271. if (is_array($item) && isset($item['_elem'])) {
  272. if ($item['_elem'] == 'opentag' && $item['_tag'] == 'span' && strstr($item['class'], 'sizechange')) {
  273. if (strstr($item['class'], 'positive')) {
  274. $event->data->_content[$key]['class'] .= ' label label-success';
  275. }
  276. if (strstr($item['class'], 'negative')) {
  277. $event->data->_content[$key]['class'] .= ' label label-danger';
  278. }
  279. }
  280. // Recent form
  281. if ($item['_elem'] == 'opentag' && $item['_tag'] == 'li' && strstr($item['class'], 'minor')) {
  282. $event->data->_content[$key]['class'] .= ' text-muted';
  283. }
  284. }
  285. }
  286. }
  287. public function tplContent(\Doku_Event $event)
  288. {
  289. $event->data = $this->template->normalizeContent($event->data);
  290. }
  291. public function search(\Doku_Event $event)
  292. {
  293. if ($event->name == 'SEARCH_RESULT_PAGELOOKUP') {
  294. array_unshift($event->data['listItemContent'], iconify('mdi:file-document-outline', ['title' => hsc($event->data['page'])]) . ' ');
  295. }
  296. if ($event->name == 'SEARCH_RESULT_FULLPAGE') {
  297. $event->data['resultBody']['meta'] = str_replace(
  298. ['<span class="lastmod">', '<span class="hits">'],
  299. ['<span class="lastmod">' . iconify('mdi:calendar') . ' ', '<span class="hits"' . iconify('mdi:poll') . ' '],
  300. '<small>' . $event->data['resultBody']['meta'] . '</small>'
  301. );
  302. }
  303. }
  304. /**
  305. * Load the template assets (Bootstrap, AnchorJS, etc)
  306. *
  307. * @author Giuseppe Di Terlizzi <giuseppe.diterlizzi@gmail.com>
  308. * @todo Move the specific-padding size of Bootswatch template in template.less
  309. *
  310. * @param \Doku_Event $event
  311. */
  312. public function tplMetaHeaderOutput(\Doku_Event $event)
  313. {
  314. global $ACT;
  315. global $INPUT;
  316. $fixed_top_navbar = $this->template->getConf('fixedTopNavbar');
  317. if ($google_analitycs = $this->template->getGoogleAnalitycs()) {
  318. $event->data['script'][] = [
  319. 'type' => 'text/javascript',
  320. '_data' => $google_analitycs,
  321. ];
  322. }
  323. // Apply some FIX
  324. if ($ACT || defined('DOKU_MEDIADETAIL')) {
  325. // Default Padding
  326. $navbar_padding = 20;
  327. if ($fixed_top_navbar) {
  328. $navbar_height = $this->template->getNavbarHeight();
  329. $navbar_padding += $navbar_height;
  330. }
  331. $styles = [];
  332. // TODO implement in css.php dispatcher
  333. $styles[] = "body { margin-top: {$navbar_padding}px; }";
  334. $styles[] = ' #dw__toc.affix { top: ' . ($navbar_padding - 10) . 'px; position: fixed !important; }';
  335. if ($this->template->getConf('tocCollapseSubSections')) {
  336. $styles[] = ' #dw__toc .nav .nav .nav { display: none; }';
  337. }
  338. $event->data['style'][] = [
  339. 'type' => 'text/css',
  340. '_data' => '@media screen { ' . implode(" ", $styles) . ' }',
  341. ];
  342. }
  343. }
  344. public function pluginTagLink(\Doku_Event $event)
  345. {
  346. $event->data['class'] .= ' tag label label-default mx-1';
  347. $event->data['title'] = iconify('mdi:tag-text-outline') . ' ' . $event->data['title'];
  348. }
  349. public function tplIncPlugin(\Doku_Event $event)
  350. {
  351. $event->data['header'] = 'Header of page below the navbar (header)';
  352. $event->data['topheader'] = 'Top Header of page (topheader)';
  353. $event->data['pagefooter'] = 'Footer below the page content (pagefooter)';
  354. $event->data['pageheader'] = 'Header above the page content (pageheader)';
  355. $event->data['sidebarfooter'] = 'Footer below the sidebar (sidebarfooter)';
  356. $event->data['sidebarheader'] = 'Header above the sidebar (sidebarheader)';
  357. $event->data['rightsidebarfooter'] = 'Footer below the right-sidebar (rightsidebarfooter)';
  358. $event->data['rightsidebarheader'] = 'Header above the right-sidebar (rightsidebarheader)';
  359. }
  360. }