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        $form->getElementAt($form->findPositionByAttribute('name', 'do[save]'))
187            ->addClass('btn btn-success mr-2')->attr('data-dw-icon', 'mdi:content-save');
188
189        $form->getElementAt($form->findPositionByAttribute('name', 'do[preview]'))
190            ->addClass('btn btn-default mr-2')->attr('data-dw-icon', 'mdi:file-document-outline');
191
192        $form->getElementAt($form->findPositionByAttribute('name', 'do[cancel]'))
193            ->addClass('btn btn-default mr-2')->attr('data-dw-icon', 'mdi:arrow-left');
194
195    }
196
197    public function htmlSecEditButton(\Doku_Event $event)
198    {
199        $html = new \simple_html_dom;
200        $html->load($event->result, true, false);
201
202        # Section Edit Button
203        foreach ($html->find('[type=submit]') as $elm) {
204            $elm->class .= ' btn btn-xs btn-default';
205        }
206
207        # Section Edit icons
208        foreach ($html->find('.editbutton_section button') as $elm) {
209            $elm->innertext = iconify('mdi:pencil') . ' ' . $elm->innertext;
210        }
211
212        foreach ($html->find('.editbutton_table button') as $elm) {
213            $elm->innertext = iconify('mdi:table') . ' ' . $elm->innertext;
214        }
215
216        $event->result = $html->save();
217        $html->clear();
218        unset($html);
219    }
220
221    public function htmlAccountFormOutput(\Doku_Event $event)
222    {
223        foreach ($event->data->_content as $key => $item) {
224            if (is_array($item) && isset($item['_elem'])) {
225                $title_icon   = 'account';
226                $button_class = 'btn btn-success';
227                $button_icon  = 'arrow-right';
228
229                switch ($event->name) {
230                    case 'HTML_LOGINFORM_OUTPUT':
231                        $title_icon  = 'account';
232                        $button_icon = 'lock';
233                        break;
234                    case 'HTML_UPDATEPROFILEFORM_OUTPUT':
235                        $title_icon = 'account-card-details-outline';
236                        break;
237                    case 'HTML_PROFILEDELETEFORM_OUTPUT':
238                        $title_icon   = 'account-remove';
239                        $button_class = 'btn btn-danger';
240                        break;
241                    case 'HTML_REGISTERFORM_OUTPUT':
242                        $title_icon = 'account-plus';
243                        break;
244                    case 'HTML_SUBSCRIBEFORM_OUTPUT':
245                        $title_icon = null;
246                        break;
247                    case 'HTML_RESENDPWDFORM_OUTPUT':
248                        $title_icon = 'lock-reset';
249                        break;
250                }
251
252                // Legend
253                if ($item['_elem'] == 'openfieldset') {
254                    $event->data->_content[$key]['_legend'] = (($title_icon) ? iconify("mdi:$title_icon") : '') . ' ' . $event->data->_content[$key]['_legend'];
255                }
256
257                // Save button
258                if (isset($item['type']) && $item['type'] == 'submit') {
259                    $event->data->_content[$key]['class'] = " $button_class";
260                    $event->data->_content[$key]['value'] = (($button_icon) ? iconify("mdi:$button_icon") : '') . ' ' . $event->data->_content[$key]['value'];
261                }
262            }
263        }
264    }
265
266    /**
267     * Handle HTML_DRAFTFORM_OUTPUT event
268     *
269     * @param \Doku_Event $event Event handler
270     *
271     * @return void
272     **/
273    public function htmlDraftForm(\Doku_Event $event)
274    {
275        foreach ($event->data->_content as $key => $item) {
276            if (is_array($item) && isset($item['_elem'])) {
277                if ($item['_action'] == 'draftdel') {
278                    $event->data->_content[$key]['class'] = ' btn btn-danger';
279                    $event->data->_content[$key]['value'] = iconify('mdi:close') . ' ' . $event->data->_content[$key]['value'];
280                }
281
282                if ($item['_action'] == 'recover') {
283                    $event->data->_content[$key]['value'] = iconify('mdi:refresh') . ' ' . $event->data->_content[$key]['value'];
284                }
285
286                if ($item['_action'] == 'show') {
287                    $event->data->_content[$key]['value'] = iconify('mdi:arrow-left') . ' ' . $event->data->_content[$key]['value'];
288                }
289            }
290        }
291    }
292
293    /**
294     * Handle HTML_EDITFORM_OUTPUT and HTML_DRAFTFORM_OUTPUT event
295     *
296     * @param \Doku_Event $event Event handler
297     *
298     * @return void
299     **/
300    public function htmlEditForm(\Doku_Event $event)
301    {
302        foreach ($event->data->_content as $key => $item) {
303            if (is_array($item) && isset($item['_elem'])) {
304                // Save button
305                if ($item['_action'] == 'save') {
306                    $event->data->_content[$key]['class'] = ' btn btn-success';
307                    $event->data->_content[$key]['value'] = iconify('mdi:content-save') . ' ' . $event->data->_content[$key]['value'];
308                }
309
310                // Preview and Show buttons
311                if ($item['_action'] == 'preview' || $item['_action'] == 'show') {
312                    $event->data->_content[$key]['value'] = iconify('mdi:file-document-outline') . ' ' . $event->data->_content[$key]['value'];
313                }
314
315                // Cancel button
316                if ($item['_action'] == 'cancel') {
317                    $event->data->_content[$key]['value'] = iconify('mdi:arrow-left') . ' ' . $event->data->_content[$key]['value'];
318                }
319            }
320        }
321    }
322
323    /**
324     * Handle HTML_REVISIONSFORM_OUTPUT and HTML_RECENTFORM_OUTPUT events
325     *
326     * @param \Doku_Event $event Event handler
327     *
328     * @return void
329     **/
330    public function htmlRevisionsFormOutput(\Doku_Event $event)
331    {
332        foreach ($event->data->_content as $key => $item) {
333            // Revision form
334            if (is_array($item) && isset($item['_elem'])) {
335                if ($item['_elem'] == 'opentag' && $item['_tag'] == 'span' && strstr($item['class'], 'sizechange')) {
336                    if (strstr($item['class'], 'positive')) {
337                        $event->data->_content[$key]['class'] .= ' label label-success';
338                    }
339
340                    if (strstr($item['class'], 'negative')) {
341                        $event->data->_content[$key]['class'] .= ' label label-danger';
342                    }
343                }
344
345                // Recent form
346                if ($item['_elem'] == 'opentag' && $item['_tag'] == 'li' && strstr($item['class'], 'minor')) {
347                    $event->data->_content[$key]['class'] .= ' text-muted';
348                }
349            }
350        }
351    }
352
353    public function tplContent(\Doku_Event $event)
354    {
355        $event->data = $this->template->normalizeContent($event->data);
356    }
357
358    public function search(\Doku_Event $event)
359    {
360        if ($event->name == 'SEARCH_RESULT_PAGELOOKUP') {
361            array_unshift($event->data['listItemContent'], iconify('mdi:file-document-outline', ['title' => hsc($event->data['page'])]) . ' ');
362        }
363
364        if ($event->name == 'SEARCH_RESULT_FULLPAGE') {
365            $event->data['resultBody']['meta'] = str_replace(
366                ['<span class="lastmod">', '<span class="hits">'],
367                ['<span class="lastmod">' . iconify('mdi:calendar') . ' ', '<span class="hits"' . iconify('mdi:poll') . ' '],
368                '<small>' . $event->data['resultBody']['meta'] . '</small>'
369            );
370        }
371    }
372
373    /**
374     * Load the template assets (Bootstrap, AnchorJS, etc)
375     *
376     * @author  Giuseppe Di Terlizzi <giuseppe.diterlizzi@gmail.com>
377     * @todo    Move the specific-padding size of Bootswatch template in template.less
378     *
379     * @param  \Doku_Event $event
380     */
381    public function tplMetaHeaderOutput(\Doku_Event $event)
382    {
383
384        global $ACT;
385        global $INPUT;
386
387        $fixed_top_navbar = $this->template->getConf('fixedTopNavbar');
388
389        if ($google_analitycs = $this->template->getGoogleAnalitycs()) {
390            $event->data['script'][] = [
391                'type'  => 'text/javascript',
392                '_data' => $google_analitycs,
393            ];
394        }
395
396        // Apply some FIX
397        if ($ACT || defined('DOKU_MEDIADETAIL')) {
398            // Default Padding
399            $navbar_padding = 20;
400
401            if ($fixed_top_navbar) {
402                $navbar_height = $this->template->getNavbarHeight();
403                $navbar_padding += $navbar_height;
404            }
405
406            $styles = [];
407
408            // TODO implement in css.php dispatcher
409
410            $styles[] = "body { margin-top: {$navbar_padding}px; }";
411            $styles[] = ' #dw__toc.affix { top: ' . ($navbar_padding - 10) . 'px; position: fixed !important; }';
412
413            if ($this->template->getConf('tocCollapseSubSections')) {
414                $styles[] = ' #dw__toc .nav .nav .nav { display: none; }';
415            }
416
417            $event->data['style'][] = [
418                'type'  => 'text/css',
419                '_data' => '@media screen { ' . implode(" ", $styles) . ' }',
420            ];
421        }
422    }
423
424    public function pluginTagLink(\Doku_Event $event)
425    {
426        $event->data['class'] .= ' tag label label-default mx-1';
427        $event->data['title'] = iconify('mdi:tag-text-outline') . ' ' . $event->data['title'];
428    }
429
430    public function tplIncPlugin(\Doku_Event $event)
431    {
432        $event->data['header']             = 'Header of page below the navbar (header)';
433        $event->data['topheader']          = 'Top Header of page (topheader)';
434        $event->data['pagefooter']         = 'Footer below the page content (pagefooter)';
435        $event->data['pageheader']         = 'Header above the page content (pageheader)';
436        $event->data['sidebarfooter']      = 'Footer below the sidebar (sidebarfooter)';
437        $event->data['sidebarheader']      = 'Header above the sidebar (sidebarheader)';
438        $event->data['rightsidebarfooter'] = 'Footer below the right-sidebar (rightsidebarfooter)';
439        $event->data['rightsidebarheader'] = 'Header above the right-sidebar (rightsidebarheader)';
440    }
441
442}
443