1<?php
2/**
3 * Template Functions
4 *
5 * This file provides template specific custom functions that are
6 * not provided by the DokuWiki core.
7 * It is common practice to start each function with an underscore
8 * to make sure it won't interfere with future core functions.
9 */
10
11// must be run from within DokuWiki
12if (!defined('DOKU_INC')) die();
13
14use dokuwiki\Extension\Event;
15
16/**
17 * Modified version of tpl_breadcrumbs() that adds Bulma classes
18 */
19function _tpl_breadcrumbs() {
20    $out='';
21    $out .= '<nav class="breadcrumb has-bullet-separator is-small" aria-label="breadcrumbs">';
22    $out .= '<ul>';
23    $out .= '<li class="is-active"><a>Trace</a></li>';
24    $crumbs = breadcrumbs(); //setup crumb trace
25
26    //render crumbs, highlight the last one
27    $last = count($crumbs);
28    $i    = 0;
29    foreach($crumbs as $id => $name) {
30        $i++;
31        if($i == $last) {
32            $out .= '<li class="is-active">';
33        } else {
34            $out .= '<li>';
35        }
36        $out .= tpl_link(wl($id), hsc($name), 'aria-current="page" title="'.$id.'"', true);
37        $out .= '</li>';
38    }
39    $out .= '</ul>';
40    $out .= '</nav>';
41    echo $out;
42}
43
44/**
45 * Modified version of tpl_content() that adds Bulma classes to basic
46 * elements
47 */
48function _tpl_content($prependTOC = false) {
49    global $ACT;
50    global $INFO;
51    $INFO['prependTOC'] = $prependTOC;
52
53    ob_start();
54    Event::createAndTrigger('TPL_ACT_RENDER', $ACT, 'tpl_content_core');
55    $html_output = ob_get_clean();
56    $libxml_errors = libxml_use_internal_errors(true);
57    $dom = new DOMDocument();
58    //$dom->loadHTML($html_output);
59    $dom->loadHTML(mb_convert_encoding($html_output, 'HTML-ENTITIES', 'UTF-8'));
60    libxml_clear_errors();
61    libxml_use_internal_errors($libxml_errors);
62    // add button class to buttons, reset, and submit
63    foreach ($dom->getElementsByTagName('button') as $ele) {
64        $ele->setAttribute('class', 'button is-small');
65    }
66    foreach ($dom->getElementsByTagName('reset') as $ele) {
67        $ele->setAttribute('class', 'button is-small');
68    }
69    foreach ($dom->getElementsByTagName('submit') as $ele) {
70        $ele->setAttribute('class', 'button is-small');
71    }
72    // add select class to selects
73    foreach ($dom->getElementsByTagName('select') as $ele) {
74        // skip a select on the acl page because it looks weird
75        $name = $ele->getAttribute('name');
76        if ($name == 'acl_t') continue;
77        $ele->parentNode->setAttribute('class', 'select is-small');
78    }
79    // add checkbox, radio, and input classes
80    foreach ($dom->getElementsByTagName('input') as $ele) {
81        $type = $ele->getAttribute('type');
82        switch ($type) {
83            case 'checkbox':
84                $label = $ele->parentNode;
85                $label->setAttribute('class', $label->getAttribute('class') . ' checkbox');
86                break;
87            case 'radio':
88                $label = $ele->parentNode;
89                $label->setAttribute('class', $label->getAttribute('class') . ' radio');
90                break;
91            default:
92                $ele->setAttribute('class', $ele->getAttribute('class') . ' input is-small');
93                break;
94        }
95        //if ($type != 'checkbox') {
96        //    $ele->setAttribute('class', $ele->getAttribute('class') . ' input is-small');
97        //} else {
98        //    $label = $ele->parentNode;
99        //    $label->setAttribute('class', $label->getAttribute('class') . ' checkbox');
100        //}
101    }
102    // add proper classes to odered lists
103    foreach ($dom->getElementsByTagName('ol') as $ele) {
104        foreach ($ele->childNodes as $i) {
105            // skip non DOMNode elements
106            if ($i->nodeType != 1) continue;
107            // skip non li elements
108            if ($i->nodeName != 'li') continue;
109            // apply proper class to ordered list based on what level# the
110            // first li element is
111            switch (substr($i->getAttribute('class'), 5, 1)) {
112                case '1':
113                    break;
114                case '2':
115                    $ele->setAttribute('class', 'is-lower-alpha');
116                    break;
117                case '3':
118                    $ele->setAttribute('class', 'is-upper-roman');
119                    break;
120                case '4':
121                    $ele->setAttribute('class', 'is-upper-alpha');
122                    break;
123                default:
124                    $ele->setAttribute('class', 'is-lower-roman');
125                    break;
126            }
127            // break because we only need to evaluate the very first one
128            // to get the level
129            break;
130        }
131    }
132    // add table class to tables
133    foreach ($dom->getElementsByTagName('table') as $ele) {
134        $ele->setAttribute('class', 'table inline is-bordered is-striped is-narrow is-hoverable');
135        // get parent div and add table-container class
136        $div = $ele->parentNode;
137        $classes = $div->getAttribute('class');
138        $div->setAttribute('class', $classes . ' table-container');
139    }
140    // fix centered table data
141    foreach ($dom->getElementsByTagName('td') as $ele) {
142        $classes = $ele->getAttribute('class');
143        $classes = str_replace('centeralign', 'has-text-centered', $classes);
144        $classes = str_replace('leftalign', 'has-text-left', $classes);
145        $classes = str_replace('rightalign', 'has-text-right', $classes);
146        $ele->setAttribute('class', $classes);
147    }
148    // fix centered table data and make table headers nicer
149    foreach ($dom->getElementsByTagName('th') as $ele) {
150        $classes = $ele->getAttribute('class');
151        $classes = $classes . ' has-background-white-ter has-text-weight-bold';
152        $classes = str_replace('centeralign', 'has-text-centered', $classes);
153        $classes = str_replace('leftalign', 'has-text-left', $classes);
154        $classes = str_replace('rightalign', 'has-text-right', $classes);
155        $ele->setAttribute('class', $classes);
156    }
157    foreach ($dom->getElementsByTagName('thead') as $ele) {
158        $ele->setAttribute('class', 'has-background-white-ter has-text-weight-bold');
159    }
160    // add textarea class to textareas
161    foreach ($dom->getElementsByTagName('textarea') as $ele) {
162        $ele->setAttribute('class', $ele->getAttribute('class') .' textarea');
163    }
164    $html_output = $dom->saveHTML($dom->documentElement);
165    Event::createAndTrigger('TPL_CONTENT_DISPLAY', $html_output, 'ptln');
166
167    return !empty($html_output);
168}
169
170/**
171 * Modified version of tpl_page_tools() that adds Bulma classes and custom formatting
172 */
173function _tpl_page_tools() {
174    $items = (new \dokuwiki\Menu\PageMenu())->getItems();
175    $out = '';
176    $out .= '<ul class="page-tools">';
177    foreach ($items as $item) {
178        $out .= '<li> ';
179        $out .= '<a ';
180        $out .= buildAttributes($item->getLinkAttributes('button is-light is-small '));
181        $out .= '>';
182        //$out .= inlineSVG($item->getSvg());
183        $out .= $item->getLabel();
184        $out .= '</a>';
185        $out .= '</li>';
186    }
187    $out .= '</ul>';
188    echo $out;
189}
190
191/**
192 * Custom search form that excludes the button.
193 */
194function _tpl_searchform($ajax = true, $autocomplete = true) {
195    global $lang;
196    global $ACT;
197    global $QUERY;
198    global $ID;
199
200    // don't print the search form if search action has been disabled
201    if(!actionOK('search')) return false;
202
203    $searchForm = new dokuwiki\Form\Form([
204        'action' => wl(),
205        'method' => 'get',
206        'role' => 'search',
207        'class' => 'field has-addons is-horizontal pb-2 search',
208        'id' => 'dokuwiki__search',
209    ], true);
210    $searchForm->setHiddenField('do', 'search');
211    $searchForm->setHiddenField('id', $ID);
212    $searchForm->addTextInput('q')
213        ->addClass('edit input is-small')
214        ->attrs([
215            'title' => '[F]',
216            'accesskey' => 'f',
217            'placeholder' => $lang['btn_search'],
218            'autocomplete' => $autocomplete ? 'on' : 'off',
219        ])
220        ->id('qsearch__in')
221        ->val($ACT === 'search' ? $QUERY : '')
222        ->useInput(false)
223    ;
224    if ($ajax) {
225        $searchForm->addTagOpen('div')->id('qsearch__out')->addClass('ajax_qsearch JSpopup');
226        $searchForm->addTagClose('div');
227    }
228    Event::createAndTrigger('FORM_QUICKSEARCH_OUTPUT', $searchForm);
229
230    echo $searchForm->toHTML();
231
232    return true;
233}
234
235/**
236 * Modified version of tpl_sidebar() that adds Bulma classes and custom formatting
237 */
238function _tpl_sidebar() {
239    $sb = strval(tpl_include_page($conf['sidebar'], false, true));
240    $dom = new DOMDocument();
241    //$dom->loadHTML($sb);
242    $dom->loadHTML(mb_convert_encoding($sb, 'HTML-ENTITIES', 'UTF-8'));
243    $uls = $dom->getElementsByTagName('ul');
244    foreach ($uls as $ul) {
245        $ul->setAttribute('class', 'menu-list');
246    }
247    echo $dom->saveHTML($dom->documentElement);
248}
249
250/**
251 * Modified version of tpl_toc() that adds Bulma classes and custom formatting
252 */
253function _tpl_toc() {
254    $t = strval(tpl_toc(true));
255    $dom = new DOMDocument();
256    //$dom->loadHTML($t);
257    $dom->loadHTML(mb_convert_encoding($t, 'HTML-ENTITIES', 'UTF-8'));
258    $dw__toc = $dom->getElementById('dw__toc');
259    $dw__toc->setAttribute('id', 'bulma-toc');
260    $dw__toc->setAttribute('class', 'is-size-7');
261    $h3s = $dom->getElementsByTagName('h3');
262    foreach ($h3s as $h3) {
263        $h3->setAttribute('class', 'has-text-grey-light');
264        $h3->nodeValue = 'On this page';
265    }
266    $lis = $dom->getElementsByTagName('li');
267    foreach ($lis as $li) {
268        if ($li->getAttribute('class') == 'level2') {
269            $li->setAttribute('class', 'level2 pl-2');
270        }
271        if ($li->getAttribute('class') == 'level3') {
272            $li->setAttribute('class', 'level2 pl-4');
273        }
274    }
275    $as = $dom->getElementsByTagName('a');
276    foreach ($as as $a) {
277        $a->setAttribute('class', 'button is-light is-small');
278    }
279    echo $dom->saveHTML($dom->documentElement);
280}
281
282/**
283 * Modified version of tpl_tools_menu() that adds Bulma classes and custom formatting
284 */
285function _tpl_tools_menu() {
286    $out = '';
287    if (!empty($_SERVER['REMOTE_USER'])) {
288        $out .= '<div class="navbar-item has-dropdown is-hoverable">';
289        $out .= '<a class="navbar-link">Tools</a>';
290        $out .= '<div class="navbar-dropdown">';
291        try{
292            $items = (new \dokuwiki\Menu\SiteMenu())->getItems();
293            foreach ($items as $item) {
294                $out .= $item->asHtmlLink('navbar-item ', false);
295            }
296        } catch(\RuntimeException $ignored) {
297            // item not available
298        }
299        $out .= '</div>';
300        $out .= '</div>';
301    }
302    echo $out;
303}
304
305/**
306 * Modified version of tpl_user_menu() that adds Bulma classes and custom formatting
307 */
308function _tpl_user_menu() {
309    $out = '';
310    if (!empty($_SERVER['REMOTE_USER'])) {
311        $out .= '<div class="navbar-item has-dropdown is-hoverable">';
312        $out .= '<a class="navbar-link">Account</a>';
313        $out .= '<div class="navbar-dropdown">';
314        try{
315            $out .= (new \dokuwiki\Menu\Item\Admin())->asHtmlLink('navbar-item ', false);
316        } catch(\RuntimeException $ignored) {
317            // item not available
318        }
319        try{
320            $out .= (new \dokuwiki\Menu\Item\Register())->asHtmlLink('navbar-item ', false);
321        } catch(\RuntimeException $ignored) {
322            // item not available
323        }
324        $out .= '<hr class="navbar-divider">';
325        $out .= (new \dokuwiki\Menu\Item\Login())->asHtmlLink('navbar-item ', false);
326        $out .= '</div>';
327        $out .= '</div>';
328    }
329    else {
330        $out .= (new \dokuwiki\Menu\Item\Login())->asHtmlLink('navbar-item ', false);
331    }
332    echo $out;
333}
334