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