1<?php
2/**
3 * DokuWiki Congrid Template: template functions
4 *
5 * @author  LarsDW223
6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 */
8
9// must be run from within DokuWiki
10if (!defined('DOKU_INC')) die();
11
12require_once(dirname(__FILE__).'/tpl_default.php');
13
14/* The type is well-known and by it's name it is clear what to do,
15   e.g. 'title', 'content', 'sitetools'... */
16define(TEMPLATE_KNOWN_TYPE, 1);
17/* The type is unknown and it is not clear what to do.
18   An empty cell will be rendered with some error text. */
19define(TEMPLATE_INVALID_TYPE, 2);
20/* The type is not known but is a container for other items
21   which could be pages or well-known types. */
22define(TEMPLATE_CONTAINER_ITEMS, 3);
23/* The type is not known but defines a page which shall be rendered.
24   This can e.g. be used to render the sidebar. */
25define(TEMPLATE_CONTAINER_PAGES, 4);
26
27/**
28 * Check if the given selector matches the current requests context.
29 *
30 * The selector may include the following simple comparisons:
31 * - "do==value":
32 *   value must match the 'do' parameter of the current request URL
33 * - "do!=value":
34 *   value must NOT match the 'do' parameter of the current request URL
35 * - "ID==value":
36 *   value must match the current page ID
37 * - "ID!=value":
38 *   value must NOT match the current page ID
39 * - "page==value":
40 *   value must match the 'page' parameter of the current request URL
41 * - "page!=value":
42 *   value must NOT match the 'page' parameter of the current request URL
43 * - "ACT==value":
44 *   value must match the current action ($ACT)
45 * - "ACT!=value":
46 *   value must NOT match the current action ($ACT)
47 *
48 * Multiple comparisons can be given separated by spaces. In this case all
49 * comparisons must be matched to let the whole selector match (logical and).
50 *
51 * The return value 0 means no match. Numbers higher than 0 means a match.
52 * A higher number means a more specific match.
53 *
54 * @param string $selector
55 * @return integer
56 */
57function tpl_selector_matches($selector) {
58    global $INPUT;
59    global $ID;
60    global $ACT;
61
62    $parts = explode(' ', $selector);
63    $match = 0;
64    $match_count = 0;
65    foreach ($parts as $part) {
66        if ($part == '*') {
67            $match += 1;
68            $match_count++;
69        } else {
70            $part = str_replace(' ', '', $part);
71            if (strncmp($part, 'do==', 4) == 0) {
72                $value = substr($part, 4);
73                if ($INPUT->str('do') == $value) {
74                    $match += 2;
75                    $match_count++;
76                }
77            } else if (strncmp($part, 'do!=', 4) == 0) {
78                $value = substr($part, 4);
79                if ($INPUT->str('do') != $value) {
80                    $match += 2;
81                    $match_count++;
82                }
83            } else if (strncmp($part, 'ID==', 4) == 0) {
84                $value = substr($part, 4);
85                if ($ID == $value) {
86                    $match += 2;
87                    $match_count++;
88                }
89            } else if (strncmp($part, 'ID!=', 4) == 0) {
90                $value = substr($part, 4);
91                if ($ID != $value) {
92                    $match += 2;
93                    $match_count++;
94                }
95            } else if (strncmp($part, 'page==', 6) == 0) {
96                $value = substr($part, 6);
97                if ($INPUT->str('page') == $value) {
98                    $match += 2;
99                    $match_count++;
100                }
101            } else if (strncmp($part, 'page!=', 6) == 0) {
102                $value = substr($part, 6);
103                if ($INPUT->str('page') != $value) {
104                    $match += 2;
105                    $match_count++;
106                }
107            } else if (strncmp($part, 'ACT==', 5) == 0) {
108                $value = substr($part, 5);
109                if ($ACT == $value) {
110                    $match += 2;
111                    $match_count++;
112                }
113            } else if (strncmp($part, 'ACT!=', 5) == 0) {
114                $value = substr($part, 5);
115                if ($ACT != $value) {
116                    $match += 2;
117                    $match_count++;
118                }
119            }
120        }
121    }
122
123    if ($match_count == count($parts)) {
124        // All parts matched
125        return $match;
126    }
127
128    // No match or only partial match
129    return 0;
130}
131/**
132 * Select the layout to use as specified in the template's configuration.
133 *
134 * The function JSON decodes the config parameter 'Layouts', selects
135 * the best match and returns the array (Layouts[x]).
136 *
137 * @return array|NULL
138 */
139function tpl_get_layout() {
140    global $default_layout;
141    global $conf;
142
143    $config = tpl_getConf('Layouts', NULL);
144    if (empty($config)) {
145        $config = $default_layout;
146    }
147
148    $layouts = json_decode($config, true);
149    if ($layouts === NULL) {
150        $layouts = json_decode($default_layout, true);
151    }
152    $layouts = $layouts['layouts'];
153
154    // Go through all selectors and return the best match
155    $best = 0;
156    $best_layout = NULL;
157    for ($index = 0 ; $index < count($layouts) ; $index++) {
158        foreach ($layouts[$index]['select'] as $select) {
159            $match = tpl_selector_matches($select);
160            if ($match > $best) {
161                $best = $match;
162                $best_layout = &$layouts[$index];
163            }
164        }
165    }
166
167    if ($best > 0) {
168        return $best_layout;
169    }
170
171    // Nothing found!
172    return NULL;
173}
174/**
175 * Check if $name refers to a build-in background and return the
176 * corresponding CSS class name. If $name is unknown, NULL will be returned.
177 *
178 * @param string $name Config-name of the background
179 * @return string|NULL
180 */
181function tpl_get_background_class($name) {
182    /* Add backgrounds here.
183       For the class name '-' will be replaced with '_'! */
184    $backgrounds = array('weave', 'upholstery', 'bricks', 'diagonal-stripes',
185                         'tablecloth', 'waves', 'lined-paper',
186                         'blueprint-grid', 'cicada-stripes', 'honey-comb',
187                         'cross-dots', 'cross', 'tartan', 'japanese-cube');
188
189    if (in_array($name, $backgrounds)) {
190        return str_replace('-', '_', $name);
191    }
192    return NULL;
193}
194/**
195 * Print the opening of the <body> element as specified by @$layout.
196 */
197function tpl_print_body(array $layout) {
198    $body_class = tpl_get_background_class($layout['background']);
199    if (!empty($body_class)) {
200        print('<body class="'.$body_class.'">');
201    } else {
202        print('<body>');
203    }
204}
205/**
206 * Print/generate the 'title' section.
207 */
208function tpl_generate_title() {
209    global $conf;
210
211    // Get logo either out of the template images folder or data/media folder
212    $logo      = tpl_getMediaFile(array(':wiki:logo.png', ':logo.png', 'images/logo.png'), false, $logoSize);
213    $title     = $conf['title'];
214    //$tagline   = ($conf['tagline']) ? '<span id="dw__tagline">'.$conf['tagline'].'</span>' : '';
215
216    // Display logo and wiki title in a link to the home page
217    $home = wl();
218    tpl_link($home,
219        '<img src="'.$logo.'" alt="'.$title.'" id="dw__logo" /><span id="dw__title">'.$title.'</span>',
220        'accesskey="h" title="[H]"');
221    tpl_flush();
222}
223/**
224 * Print/generate the 'tagline' section.
225 */
226function tpl_generate_tagline() {
227    global $conf;
228
229    if ($conf['tagline']) {
230        print('<span id="dw__tagline">'.$conf['tagline'].'</span>');
231    }
232    tpl_flush();
233}
234/**
235 * Print/generate the 'trace' section.
236 */
237function tpl_generate_trace() {
238    global $conf;
239
240    if ($conf['breadcrumbs']) {
241        $sep = tpl_getConf('BreadcrumbsSep', NULL);
242        tpl_breadcrumbs($sep);
243    }
244    tpl_flush();
245}
246/**
247 * Print/generate the 'youarehere' section.
248 */
249function tpl_generate_youarehere() {
250    global $conf;
251
252    if ($conf['youarehere']) {
253        $sep = tpl_getConf('YouAreHereSep', NULL);
254        tpl_youarehere($sep);
255    }
256    tpl_flush();
257}
258/**
259 * Print/generate the 'search' section.
260 */
261function tpl_generate_search() {
262    tpl_searchform();
263    tpl_flush();
264}
265/**
266 * Print/generate the 'sitetools' section.
267 */
268function tpl_generate_sitetools() {
269    print('<h3 class="a11y">'.$lang['site_tools'].'</h3>');
270
271    // ToDo: for mobile display as drop down
272    //$mobile = (new \dokuwiki\Menu\MobileMenu())->getDropdown($lang['tools']);
273    //print('<div class="mobileTools">'.$mobile.'</div>');
274
275    $site = (new \dokuwiki\Menu\SiteMenu())->getListItems('action ', false);
276    print ('<ul>'.$site.'</ul>');
277    tpl_flush();
278}
279/**
280 * Print/generate the 'usertools' section.
281 */
282function tpl_generate_usertools() {
283    global $conf;
284
285    if ($conf['useacl']) {
286        print('<h3 class="a11y">'.$lang['user_tools'].'</h3>');
287        print('<ul>');
288        if (!empty($_SERVER['REMOTE_USER'])) {
289            print('<li class="user">');
290
291            /* 'Logged in as ...' */
292            tpl_userinfo();
293
294            print('</li>');
295        }
296        print((new \dokuwiki\Menu\UserMenu())->getListItems('action '));
297        print('</ul>');
298    }
299    tpl_flush();
300}
301/**
302 * Print/generate the 'pageid' section.
303 *
304 * @param $inside true=render page ID inside of content section,
305 *                false=render page ID in extra div/section,
306 */
307function tpl_generate_pageid($inside=true) {
308    global $ID;
309
310    if ($inside == true) {
311        print('<div class="pageId inside"><span>'.hsc($ID).'</span></div>');
312    } else {
313        print('<div class="pageId"><span>'.hsc($ID).'</span></div>');
314    }
315    tpl_flush();
316}
317/**
318 * Print/generate the 'docinfo' section.
319 *
320 * @param boolean $inside true=render doc-info inside of content section,
321 *                        false=render doc-info in extra div/section,
322 */
323function tpl_generate_docinfo($inside=true) {
324    if ($inside == true) {
325        print('<div class="docInfo inside">');
326    } else {
327        print('<div class="docInfo">');
328    }
329    tpl_pageinfo();
330    print('</div>');
331    tpl_flush();
332}
333/**
334 * Print/generate the 'toc' section.
335 *
336 * If this is called then there is an extra div containing the toc.
337 * Most likely 'tpl_generate_content()' was called with $toc == false.
338 */
339function tpl_generate_toc() {
340    tpl_toc();
341    tpl_flush();
342}
343/**
344 * Print/generate the 'content' section.
345 *
346 * If this is called then there is an extra div containing the toc.
347 * Most likely 'tpl_generate_content()' was called with $toc == false.
348 *
349 * @param boolean $page_id  Render the page ID section
350 * @param boolean $doc_info Render the doc-info section
351 * @param boolean $toc      Render the toc section
352 */
353function tpl_generate_content($page_id=true, $doc_info=true, $toc=true) {
354
355    // Output any messages created by 'msg(...)' calls
356    html_msgarea();
357
358    if ($page_id == true) {
359        tpl_generate_pageid();
360    }
361
362    print('<div id="dokuwiki__page" class="page group">');
363    tpl_flush();
364    tpl_includeFile('pageheader.html');
365
366    // Render the real content/the wiki page
367    print('<div id="dokuwiki__top"></div>');
368    tpl_content($toc);
369    print('<div id="dokuwiki__bottom"></div>');
370
371    tpl_includeFile('pagefooter.html');
372    print('</div>');
373
374    if ($doc_info == true) {
375        tpl_generate_docinfo();
376    }
377
378    tpl_flush();
379}
380/**
381 * Print/generate a 'page' section.
382 *
383 * A page section includes a specific wiki page or HTML page and could e.g.
384 * be used to genertae the sidebar.
385 *
386 * @param array  $layout Layout to be used
387 * @param string $page   Page name
388 * @param array  $params Cell params to apply
389 */
390function tpl_generate_page(array $layout, $page, $params) {
391    if (!empty($params['headline-string-name'])) {
392        print('<h3>'.$lang[$params['headline-string-name']].'</h3>');
393    }
394    print ('<div class="content">');
395    tpl_flush();
396    if (strpos($page, '.html') !== false) {
397        tpl_includeFile($page);
398    } else {
399        tpl_include_page($page, true, true);
400    }
401    print('</div>');
402    tpl_flush();
403}
404/**
405 * Print/generate the 'pagetools' section.
406 */
407function tpl_generate_pagetools() {
408    print('<h3 class="a11y">'.$lang['page_tools'].'</h3>');
409    print('<div class="tools">');
410    print('    <ul>');
411    print((new \dokuwiki\Menu\PageMenu())->getListItems());
412    print('    </ul>');
413    print('</div>');
414    tpl_flush();
415}
416/**
417 * Print/generate the 'footer' section.
418 */
419function tpl_generate_footer() {
420    global $conf;
421
422    /* Generate license text */
423    tpl_license('');
424
425    print('<div class="buttons">');
426    /* license button, no wrapper */
427    tpl_license('button', true, false, false);
428    $target = ($conf['target']['extern']) ? 'target="'.$conf['target']['extern'].'"' : '';
429    $basedir = tpl_basedir();
430    print('<a href="https://www.dokuwiki.org/donate" title="Donate" '.$target.'>
431               <img src="'.$basedir.'images/button-donate.gif" width="80" height="15" alt="Donate" /></a>
432           <a href="https://php.net" title="Powered by PHP" '.$target.'>
433               <img src="'.$basedir.'images/button-php.gif" width="80" height="15" alt="Powered by PHP" /></a>
434           <a href="//validator.w3.org/check/referer" title="Valid HTML5" '.$target.'>
435               <img src="'.$basedir.'images/button-html5.png" width="80" height="15" alt="Valid HTML5" /></a>
436           <a href="//jigsaw.w3.org/css-validator/check/referer?profile=css3" title="Valid CSS" '.$target.'>
437               <img src="'.$basedir.'images/button-css.png" width="80" height="15" alt="Valid CSS" /></a>
438           <a href="https://dokuwiki.org/" title="Driven by DokuWiki" '.$target.'>
439               <img src="'.$basedir.'images/button-dw.png" width="80" height="15" alt="Driven by DokuWiki" /></a>');
440    print('</div>');
441
442    tpl_includeFile('footer.html');
443}
444/**
445 * Create the grid.
446 *
447 * This function validates the 'grid' array contained in @$layout and
448 * performs adjustment if necessary:
449 * - guarantee an equal amount of columns in each row
450 * - rename 'space' to 'empty'
451 */
452function tpl_create_grid(&$layout) {
453    // The JSON decoding gives us the grid already as an array.
454    // We just do some checks and adjust the array if necessary
455
456    // Get number of max. columns
457    $max_columns = 0;
458    foreach ($layout['grid'] as $row) {
459        $columns = count($row);
460        if ($columns > 0) {
461            if ($columns > $max_columns) {
462                $max_columns = $columns;
463            }
464        }
465    }
466
467    // Rename 'space' to 'empty'
468    $row = 0;
469    for ($row = 0 ; $row < count($layout['grid']) ; $row++) {
470        $columns = count($layout['grid'][$row]);
471        for ($column = 0 ; $column < $columns ; $column++) {
472            if ($layout['grid'][$row][$column] == 'space') {
473                $layout['grid'][$row][$column] = 'empty';
474            }
475        }
476    }
477
478    // Validate grid: if there are any rows which do not have a number
479    // of columns equal to $max_columns then fill the row up with 'empty'
480    $index = 0;
481    for ($index = 0 ; $index < count($layout['grid']) ; $index++) {
482        $columns = count($layout['grid'][$index]);
483        if ($columns < $max_columns) {
484            for (;$columns < $max_columns ; $columns++) {
485                $layout['grid'][$index][] = 'empty';
486            }
487        }
488    }
489}
490/**
491 * Returns the CSS params in @params as an CSS formated string.
492 *
493 * @return string
494 */
495function tpl_get_css_props(array $params) {
496    // Generate CSS props from cell parameters
497    $css_props = '';
498    if (is_array($params['css'])) {
499        foreach ($params['css'] as $key => $value) {
500            if ($value !== NULL) {
501                $css_props .= '    '.$key.': '.$value.";\n";
502            }
503        }
504    }
505    return $css_props;
506}
507/**
508 * Print the grid area and CSS params for @$item.
509 *
510 * $item can be the name of a well-known build-in section like 'title'
511 * or 'content'. Or it can be the name of a user-defined container
512 * which then includes well-known items or pages.
513 *
514 * @param array $layout Layout to use
515 * @param string $item  Item type or name to render
516 */
517function tpl_print_grid_area($layout, $item) {
518    $params = tpl_get_cell_params($layout, $item);
519
520    // Generate CSS props from cell parameters
521    $css_props = tpl_get_css_props($params);
522
523    switch ($item) {
524        case 'sitetools':
525            print("#dokuwiki__site div.dokuwiki__sitetools {\n    grid-area: sitetools;\n");
526        break;
527        case 'usertools':
528            print("#dokuwiki__site div.dokuwiki__usertools {\n    grid-area: usertools;\n");
529        break;
530        case 'pagetools':
531            print("#dokuwiki__site div.dokuwiki__pagetools {\n    grid-area: pagetools;\n");
532        break;
533        case 'title':
534            print("#dokuwiki__site div.dokuwiki__title {\n    grid-area: title;\n");
535        break;
536        case 'tagline':
537            print("#dokuwiki__site div.dokuwiki__tagline {\n    grid-area: tagline;\n");
538        break;
539        case 'trace':
540            print("#dokuwiki__site div.trace { grid-area:\n    trace;\n");
541        break;
542        case 'youarehere':
543            print("#dokuwiki__site div.youarehere {\n    grid-area: youarehere;\n");
544        break;
545        case 'toc':
546            print("#dokuwiki__site div.dokuwiki__toc {\n    grid-area: toc;\n");
547        break;
548        case 'content':
549            print("#dokuwiki__site div.dokuwiki__content {\n    grid-area: content;\n");
550        break;
551        case 'empty':
552            print("#dokuwiki__site div.grid-empty {\n    grid-area: empty;\n");
553        break;
554        case 'search':
555            print("#dokuwiki__site div.search {\n    grid-area: search;\n");
556        break;
557        case 'footer':
558            print("#dokuwiki__site #dokuwiki__footer {\n    grid-area: footer;\n");
559        break;
560        case 'scroll-up-area':
561            print("#dokuwiki__site div.scroll_up_area {\n    grid-area: scroll-up-area;\n");
562        break;
563        case 'scroll-down-area':
564            print("#dokuwiki__site div.scroll_down_area {\n    grid-area: scroll-down-area;\n");
565        break;
566
567        default:
568            if ($params['id'] != 'default') {
569                print("#dokuwiki__site div.".$item." {\n    grid-area: ".$item.";\n");
570            } else {
571                print('<!-- INVALID: div.'.$item.' { grid-area: '.$item.'; } -->');
572            }
573        break;
574    }
575    if (!empty($css_props)) {
576        print($css_props);
577    }
578    print("}\n");
579
580    // Also add css props for included items or pages
581    $todo = array();
582    if (is_array($params['items'])) {
583        $todo = array_merge($todo, $params['items']);
584    } else if (is_array($params['pages'])) {
585        $todo = array_merge($todo, $params['pages']);
586    }
587    foreach ($todo as $name) {
588        $params = tpl_get_cell_params($layout, $name);
589        $css_props = tpl_get_css_props($params);
590        if (!empty($css_props)) {
591            print("#dokuwiki__site div.".$name." {\n".$css_props."}\n");
592        }
593    }
594}
595/**
596 * Print the main grid definition.
597 *
598 * @param array $layout Layout to use
599 */
600function tpl_print_grid(array $layout) {
601    $max_rows = count($layout['grid']);
602    $total_vert_space = $layout['grid-vert-space'];
603    if ($max_rows > 1) {
604        $vert_space = round($total_vert_space / ($max_rows - 1));
605        $row_size = round((100 - $total_vert_space) / $max_rows);
606    } else {
607        $vert_space = 0;
608        $row_size = 100;
609    }
610
611    $max_columns = count($layout['grid'][0]);
612    $total_horiz_space = 10;
613    if ($max_columns > 1) {
614        $horiz_space = round($total_horiz_space / ($max_columns - 1));
615        $column_size = round((100 - $total_horiz_space) / $max_columns);
616    } else {
617        $horiz_space = 0;
618        $column_size = 100;
619    }
620
621    print("<style>\n");
622    print("#dokuwiki__site {\n");
623    print("    display: grid;\n");
624    print("    height: ".$layout['height'].";\n");
625    print("    position: relative;\n");
626    print("    top: ".$layout['top'].";\n");
627    print("    margin: 0 auto;\n");
628    print("    grid-column-gap: ".$horiz_space."%;\n");
629    print("    grid-template-columns:");
630    for ($column = 0 ; $column < $max_columns ; $column++) {
631        print(" ".$column_size."%");
632    }
633    print(";\n");
634    print("    grid-template-rows:");
635    for ($row = 0 ; $row < $max_rows ; $row++) {
636        print(" ".$row_size."%");
637    }
638    print(";\n");
639    print("    grid-row-gap: ".$vert_space."%;\n");
640    print("    justify-content: center;\n");
641    print("    grid-template-areas:\n");
642
643    for ($row = 0 ; $row < count($layout['grid']) ; $row++) {
644        print("        '");
645        for ($column = 0 ; $column < count($layout['grid'][$row]) ; $column++) {
646            $item = $layout['grid'][$row][$column];
647            if ($item != 'empty') {
648                print($item);
649            } else {
650                print('.');
651            }
652            if ($column+1 < count($layout['grid'][$row])) {
653                print(' ');
654            }
655        }
656        if ($row+1 < count($layout['grid'])) {
657            print("'\n");
658        } else {
659            print("';\n");
660        }
661    }
662    print("    }\n");
663
664    $done = array();
665    for ($row = 0 ; $row < count($layout['grid']) ; $row++) {
666        foreach ($layout['grid'][$row] as $item) {
667            if (array_search($item, $done) === false) {
668                $done[] = $item;
669                tpl_print_grid_area($layout, $item);
670            }
671        }
672    }
673
674    print("</style>\n");
675    tpl_flush();
676}
677/**
678 * Print a div/cell's content of the grid.
679 *
680 * This prints the surrounding div and then calls the appropriate
681 * function to generate the content.
682 *
683 * @param array  $layout Layout to use
684 * @param string $type   Type or name to render
685 * @param string $params Cell params to use
686 * @param $level FIXME: unused for now? Remove it?
687 */
688function tpl_generate_div(array &$layout, $type, array $params, $level=1) {
689    $divclass = '';
690
691    if ($params['flex']['direction'] == 'column') {
692        $divclass .= 'flex-column ';
693        if ($params['flex']['mode'] == 'same-size') {
694            $divclass .= ' same_height ';
695        }
696    } else if ($params['flex']['direction'] == 'row') {
697        $divclass .= ' flex-row ';
698        if ($params['flex']['mode'] == 'same-size') {
699            $divclass .= ' same_width ';
700        }
701    }
702
703    // Assign class for item
704    $scroll = '';
705    $invalid = false;
706    $item_type = TEMPLATE_KNOWN_TYPE;
707    switch ($type)
708    {
709        case 'title':
710            $divclass .= 'dokuwiki__title';
711        break;
712
713        case 'tagline':
714            $divclass .= 'dokuwiki__tagline';
715        break;
716
717        case 'toc':
718            $divclass .= 'dokuwiki__toc';
719        break;
720
721        case 'content':
722            $divclass .= 'dokuwiki__content';
723        break;
724
725        case 'space':
726            $divclass .= 'grid-empty';
727        break;
728
729        case 'trace':
730            $divclass .= 'trace';
731        break;
732
733        case 'youarehere':
734            $divclass .= 'youarehere';
735        break;
736
737        case 'sitetools':
738            $divclass .= 'dokuwiki__sitetools toolslist';
739        break;
740
741        case 'usertools':
742            $divclass .= 'dokuwiki__usertools toolslist';
743        break;
744
745        case 'pagetools':
746            $divclass .= 'dokuwiki__pagetools toolslist';
747        break;
748
749        case 'scroll-up-area':
750            $divclass .= 'scroll_up_area';
751            $scroll = ' onmouseover="scroll_up();" onmouseout="stop_scroll();"';
752        break;
753
754        case 'scroll-down-area':
755            $divclass .= 'scroll_down_area';
756            $scroll = ' onmouseover="scroll_down();" onmouseout="stop_scroll();"';
757        break;
758
759        default:
760            if ($params['id'] == 'default' && empty($params['items']) &&
761                empty($params['pages'])) {
762                /* The type is not known and points to the default cell or
763                   it points do a different cell but it does not define
764                   items or pages to include. */
765                $item_type = TEMPLATE_INVALID_TYPE;
766                $divclass .= 'grid-invalid';
767            } else {
768                if (!empty($params['items'])) {
769                    $childs = count($params['items']);
770                    $item_type = TEMPLATE_CONTAINER_ITEMS;
771                    $divclass .= 'container_items '.$params['id'];
772                } else {
773                    $childs = count($params['pages']);
774                    $item_type = TEMPLATE_CONTAINER_PAGES;
775                    $divclass .= 'container_pages '.$params['id'];
776                }
777                $divclass .= ' childs'.$childs;
778            }
779        break;
780    }
781
782    // Assign class for border
783    switch ($params['border']) {
784        case 'user':
785            $divclass .= ' border_TSS';
786        break;
787        case 'semi-transparent';
788            $divclass .= ' border_semi_transparent';
789        break;
790    }
791
792    // Assign class for corners
793    switch ($params['corners']) {
794        case 'round':
795            $divclass .= ' corners_round';
796        break;
797    }
798
799    // Remove text or icons (e.g. for pagetools)
800    switch ($params['list-type']) {
801        case 'no-text':
802            $divclass .= ' no_text';
803        break;
804        case 'no-icons':
805            $divclass .= ' no_icons';
806        break;
807    }
808
809    // Add known background class if set
810    if (!empty($params['background'])) {
811        $background = tpl_get_background_class($params['background']);
812        $divclass .= ' '.$background;
813    }
814
815    if ($type == 'content') {
816        print('<div id="dokuwiki__content" class="'.$divclass.'">'."\n");
817    } else if ($type == 'footer') {
818        print('<div id="dokuwiki__footer" class="'.$divclass.'">'."\n");
819    } else {
820        print('<div class="'.$divclass.'"'.$scroll.'>'."\n");
821    }
822
823    switch ($type)
824    {
825        case 'toc':
826            tpl_generate_toc();
827        break;
828
829        case 'content':
830            $toc = false;
831            if (empty($layout['toc']) || $layout['toc'] == 'on-page') {
832                $toc = true;
833            }
834            tpl_generate_content(true, true, $toc);
835        break;
836
837        case 'title':
838            tpl_generate_title();
839        break;
840
841        case 'youarehere':
842            tpl_generate_youarehere();
843        break;
844
845        case 'trace':
846            tpl_generate_trace();
847        break;
848
849        case 'tagline':
850            tpl_generate_tagline();
851        break;
852
853        case 'search':
854            tpl_generate_search();
855        break;
856
857        case 'sitetools':
858            tpl_generate_sitetools();
859        break;
860
861        case 'usertools':
862            tpl_generate_usertools();
863        break;
864
865        case 'pagetools':
866            tpl_generate_pagetools();
867        break;
868
869        case 'footer':
870            tpl_generate_footer();
871        break;
872
873        case 'scroll-up-area':
874            print('<img src="'.tpl_basedir().'/images/baseline-arrow_upward-24px.svg" alt="Up" />');
875        break;
876
877        case 'scroll-down-area':
878            print('<img src="'.tpl_basedir().'/images/baseline-arrow_downward-24px.svg" alt="Down" />');
879        break;
880
881        case 'space':
882        case 'empty':
883        case '.':
884            print('empty');
885        break;
886
887        default:
888            switch ($item_type) {
889                case TEMPLATE_INVALID_TYPE:
890                    print('<div>Invalid cell type ("'.$type.'")</div>');
891                    print('<div>Cell id ("'.$params['id'].'")</div>');
892                break;
893                case TEMPLATE_CONTAINER_ITEMS:
894                    foreach ($params['items'] as $item) {
895                        $params = tpl_get_cell_params($layout, $item);
896                        tpl_generate_div($layout, $item, $params, $level+1);
897                    }
898                break;
899                case TEMPLATE_CONTAINER_PAGES:
900                    foreach ($params['pages'] as $page) {
901                        $params = tpl_get_cell_params($layout, $page);
902                        tpl_generate_page($layout, $page, $params);
903                    }
904                break;
905            }
906        break;
907    }
908
909    print('</div>'."\n");
910}
911/**
912 * Return params set for @$cell in @$layout.
913 *
914 * If no specific params are found for $cell the nthe default params
915 * are returned (from the cell with ID 'default').
916 *
917 * @param array  $layout Layout to use
918 * @param string $cell   Type or name to render
919 */
920function tpl_get_cell_params(array $layout, $cell) {
921    $default = NULL;
922    foreach ($layout['cells'] as $params) {
923        if ($params['id'] == $cell) {
924            // Found params/match
925            return $params;
926        } else if ($params['id'] == 'default') {
927            // Remember default
928            $default = $params;
929        }
930    }
931
932    // No match, return default
933    return $default;
934}
935/**
936 * Generate all cells/divs.
937 *
938 * @param array  $layout Layout to use
939 */
940function tpl_generate_grid_cells(array $layout) {
941    $done = array();
942    for ($row = 0 ; $row < count($layout['grid']) ; $row++) {
943        foreach ($layout['grid'][$row] as $item) {
944            if (array_search($item, $done) === false) {
945                $done[] = $item;
946                if ($item != 'empty' && $item != 'space') {
947                    $params = tpl_get_cell_params($layout, $item);
948                    tpl_generate_div($layout, $item, $params);
949                } else {
950                    print('<div class="grid-empty"></div>');
951                }
952            }
953        }
954    }
955}
956/**
957 * Print class attribute for 'dokuwiki__site'.
958 *
959 * @param array $layout Layout to use
960 */
961function tpl_print_site_class($layout)
962{
963    $classes = 'dokuwiki';
964    if (empty($layout['theme'])) {
965        $classes .= ' white';
966    } else {
967        switch ($layout['theme']) {
968            case 'template-style-settings':
969                $classes .= ' TSS';
970            break;
971
972            case 'white':
973                $classes .= ' '.$layout['theme'];
974            break;
975
976            default:
977                $classes .= ' white';
978            break;
979        }
980    }
981    print('class="'.$classes.'"');
982}
983