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
10 if (!defined('DOKU_INC')) die();
11 
12 require_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'... */
16 define(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. */
19 define(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. */
22 define(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. */
25 define(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  */
57 function 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  */
139 function 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  */
181 function 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  */
197 function 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  */
208 function 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  */
226 function 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  */
237 function 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  */
249 function 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  */
261 function tpl_generate_search() {
262     tpl_searchform();
263     tpl_flush();
264 }
265 /**
266  * Print/generate the 'sitetools' section.
267  */
268 function 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  */
282 function 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  */
307 function 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  */
323 function 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  */
339 function 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  */
353 function 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  */
390 function 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  */
407 function 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  */
419 function 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  */
452 function 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  */
495 function 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  */
517 function 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  */
600 function 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  */
688 function 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  */
920 function 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  */
940 function 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  */
961 function 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