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