Completed
Push — authpdo ( 7f89f0...388201 )
by Andreas
18:44 queued 12:59
created

template.php ➔ tpl_metaheaders()   F

Complexity

Conditions 25
Paths 11088

Size

Total Lines 141
Code Lines 89

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 89
nc 11088
nop 1
dl 0
loc 141
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * DokuWiki template functions
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
if(!defined('DOKU_INC')) die('meh.');
10
11
/**
12
 * Access a template file
13
 *
14
 * Returns the path to the given file inside the current template, uses
15
 * default template if the custom version doesn't exist.
16
 *
17
 * @author Andreas Gohr <[email protected]>
18
 * @param string $file
19
 * @return string
20
 */
21
function template($file) {
22
    global $conf;
23
24
    if(@is_readable(DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$file))
25
        return DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$file;
26
27
    return DOKU_INC.'lib/tpl/dokuwiki/'.$file;
28
}
29
30
/**
31
 * Convenience function to access template dir from local FS
32
 *
33
 * This replaces the deprecated DOKU_TPLINC constant
34
 *
35
 * @author Andreas Gohr <[email protected]>
36
 * @param string $tpl The template to use, default to current one
37
 * @return string
38
 */
39
function tpl_incdir($tpl='') {
40
    global $conf;
41
    if(!$tpl) $tpl = $conf['template'];
42
    return DOKU_INC.'lib/tpl/'.$tpl.'/';
43
}
44
45
/**
46
 * Convenience function to access template dir from web
47
 *
48
 * This replaces the deprecated DOKU_TPL constant
49
 *
50
 * @author Andreas Gohr <[email protected]>
51
 * @param string $tpl The template to use, default to current one
52
 * @return string
53
 */
54
function tpl_basedir($tpl='') {
55
    global $conf;
56
    if(!$tpl) $tpl = $conf['template'];
57
    return DOKU_BASE.'lib/tpl/'.$tpl.'/';
58
}
59
60
/**
61
 * Print the content
62
 *
63
 * This function is used for printing all the usual content
64
 * (defined by the global $ACT var) by calling the appropriate
65
 * outputfunction(s) from html.php
66
 *
67
 * Everything that doesn't use the main template file isn't
68
 * handled by this function. ACL stuff is not done here either.
69
 *
70
 * @author Andreas Gohr <[email protected]>
71
 *
72
 * @triggers TPL_ACT_RENDER
73
 * @triggers TPL_CONTENT_DISPLAY
74
 * @param bool $prependTOC should the TOC be displayed here?
75
 * @return bool true if any output
76
 */
77
function tpl_content($prependTOC = true) {
78
    global $ACT;
79
    global $INFO;
80
    $INFO['prependTOC'] = $prependTOC;
81
82
    ob_start();
83
    trigger_event('TPL_ACT_RENDER', $ACT, 'tpl_content_core');
84
    $html_output = ob_get_clean();
85
    trigger_event('TPL_CONTENT_DISPLAY', $html_output, 'ptln');
86
87
    return !empty($html_output);
88
}
89
90
/**
91
 * Default Action of TPL_ACT_RENDER
92
 *
93
 * @return bool
94
 */
95
function tpl_content_core() {
96
    global $ACT;
97
    global $TEXT;
98
    global $PRE;
99
    global $SUF;
100
    global $SUM;
101
    global $IDX;
102
    global $INPUT;
103
104
    switch($ACT) {
105
        case 'show':
106
            html_show();
107
            break;
108
        /** @noinspection PhpMissingBreakStatementInspection */
109
        case 'locked':
110
            html_locked();
111
        case 'edit':
112
        case 'recover':
113
            html_edit();
114
            break;
115
        case 'preview':
116
            html_edit();
117
            html_show($TEXT);
118
            break;
119
        case 'draft':
120
            html_draft();
121
            break;
122
        case 'search':
123
            html_search();
124
            break;
125
        case 'revisions':
126
            html_revisions($INPUT->int('first'));
127
            break;
128
        case 'diff':
129
            html_diff();
130
            break;
131
        case 'recent':
132
            $show_changes = $INPUT->str('show_changes');
133
            if (empty($show_changes)) {
134
                $show_changes = get_doku_pref('show_changes', $show_changes);
135
            }
136
            html_recent($INPUT->extract('first')->int('first'), $show_changes);
137
            break;
138
        case 'index':
139
            html_index($IDX); #FIXME can this be pulled from globals? is it sanitized correctly?
140
            break;
141
        case 'backlink':
142
            html_backlinks();
143
            break;
144
        case 'conflict':
145
            html_conflict(con($PRE, $TEXT, $SUF), $SUM);
146
            html_diff(con($PRE, $TEXT, $SUF), false);
147
            break;
148
        case 'login':
149
            html_login();
150
            break;
151
        case 'register':
152
            html_register();
153
            break;
154
        case 'resendpwd':
155
            html_resendpwd();
156
            break;
157
        case 'denied':
158
            html_denied();
159
            break;
160
        case 'profile' :
161
            html_updateprofile();
162
            break;
163
        case 'admin':
164
            tpl_admin();
165
            break;
166
        case 'subscribe':
167
            tpl_subscribe();
168
            break;
169
        case 'media':
170
            tpl_media();
171
            break;
172
        default:
173
            $evt = new Doku_Event('TPL_ACT_UNKNOWN', $ACT);
174
            if($evt->advise_before()) {
175
                msg("Failed to handle command: ".hsc($ACT), -1);
176
            }
177
            $evt->advise_after();
178
            unset($evt);
179
            return false;
180
    }
181
    return true;
182
}
183
184
/**
185
 * Places the TOC where the function is called
186
 *
187
 * If you use this you most probably want to call tpl_content with
188
 * a false argument
189
 *
190
 * @author Andreas Gohr <[email protected]>
191
 *
192
 * @param bool $return Should the TOC be returned instead to be printed?
193
 * @return string
194
 */
195
function tpl_toc($return = false) {
196
    global $TOC;
197
    global $ACT;
198
    global $ID;
199
    global $REV;
200
    global $INFO;
201
    global $conf;
202
    global $INPUT;
203
    $toc = array();
204
205
    if(is_array($TOC)) {
206
        // if a TOC was prepared in global scope, always use it
207
        $toc = $TOC;
208
    } elseif(($ACT == 'show' || substr($ACT, 0, 6) == 'export') && !$REV && $INFO['exists']) {
209
        // get TOC from metadata, render if neccessary
210
        $meta = p_get_metadata($ID, '', METADATA_RENDER_USING_CACHE);
211
        if(isset($meta['internal']['toc'])) {
212
            $tocok = $meta['internal']['toc'];
213
        } else {
214
            $tocok = true;
215
        }
216
        $toc = isset($meta['description']['tableofcontents']) ? $meta['description']['tableofcontents'] : null;
217
        if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']) {
218
            $toc = array();
219
        }
220
    } elseif($ACT == 'admin') {
221
        // try to load admin plugin TOC
222
        /** @var $plugin DokuWiki_Admin_Plugin */
223
        if ($plugin = plugin_getRequestAdminPlugin()) {
224
            $toc = $plugin->getTOC();
225
            $TOC = $toc; // avoid later rebuild
226
        }
227
    }
228
229
    trigger_event('TPL_TOC_RENDER', $toc, null, false);
230
    $html = html_TOC($toc);
231
    if($return) return $html;
232
    echo $html;
233
    return '';
234
}
235
236
/**
237
 * Handle the admin page contents
238
 *
239
 * @author Andreas Gohr <[email protected]>
240
 *
241
 * @return bool
242
 */
243
function tpl_admin() {
244
    global $INFO;
245
    global $TOC;
246
    global $INPUT;
247
248
    $plugin = null;
249
    $class  = $INPUT->str('page');
250
    if(!empty($class)) {
251
        $pluginlist = plugin_list('admin');
252
253
        if(in_array($class, $pluginlist)) {
254
            // attempt to load the plugin
255
            /** @var $plugin DokuWiki_Admin_Plugin */
256
            $plugin = plugin_load('admin', $class);
257
        }
258
    }
259
260
    if($plugin !== null) {
261
        if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet
262
        if($INFO['prependTOC']) tpl_toc();
263
        $plugin->html();
264
    } else {
265
        html_admin();
266
    }
267
    return true;
268
}
269
270
/**
271
 * Print the correct HTML meta headers
272
 *
273
 * This has to go into the head section of your template.
274
 *
275
 * @author Andreas Gohr <[email protected]>
276
 *
277
 * @triggers TPL_METAHEADER_OUTPUT
278
 * @param  bool $alt Should feeds and alternative format links be added?
279
 * @return bool
280
 */
281
function tpl_metaheaders($alt = true) {
282
    global $ID;
283
    global $REV;
284
    global $INFO;
285
    global $JSINFO;
286
    global $ACT;
287
    global $QUERY;
288
    global $lang;
289
    global $conf;
290
    global $updateVersion;
291
    /** @var Input $INPUT */
292
    global $INPUT;
293
294
    // prepare the head array
295
    $head = array();
296
297
    // prepare seed for js and css
298
    $tseed   = $updateVersion;
299
    $depends = getConfigFiles('main');
300
    $depends[] = DOKU_CONF."tpl/".$conf['template']."/style.ini";
301
    foreach($depends as $f) $tseed .= @filemtime($f);
302
    $tseed   = md5($tseed);
303
304
    // the usual stuff
305
    $head['meta'][] = array('name'=> 'generator', 'content'=> 'DokuWiki');
306
    if(actionOK('search')) {
307
        $head['link'][] = array(
308
            'rel' => 'search', 'type'=> 'application/opensearchdescription+xml',
309
            'href'=> DOKU_BASE.'lib/exe/opensearch.php', 'title'=> $conf['title']
310
        );
311
    }
312
313
    $head['link'][] = array('rel'=> 'start', 'href'=> DOKU_BASE);
314
    if(actionOK('index')) {
315
        $head['link'][] = array(
316
            'rel'  => 'contents', 'href'=> wl($ID, 'do=index', false, '&'),
317
            'title'=> $lang['btn_index']
318
        );
319
    }
320
321
    if($alt) {
322
        if(actionOK('rss')) {
323
            $head['link'][] = array(
324
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
325
                'title'=> $lang['btn_recent'], 'href'=> DOKU_BASE.'feed.php'
326
            );
327
            $head['link'][] = array(
328
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
329
                'title'=> $lang['currentns'],
330
                'href' => DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']
331
            );
332
        }
333
        if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']) {
334
            $head['link'][] = array(
335
                'rel'  => 'edit',
336
                'title'=> $lang['btn_edit'],
337
                'href' => wl($ID, 'do=edit', false, '&')
338
            );
339
        }
340
341
        if(actionOK('rss') && $ACT == 'search') {
342
            $head['link'][] = array(
343
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
344
                'title'=> $lang['searchresult'],
345
                'href' => DOKU_BASE.'feed.php?mode=search&q='.$QUERY
346
            );
347
        }
348
349
        if(actionOK('export_xhtml')) {
350
            $head['link'][] = array(
351
                'rel' => 'alternate', 'type'=> 'text/html', 'title'=> $lang['plainhtml'],
352
                'href'=> exportlink($ID, 'xhtml', '', false, '&')
353
            );
354
        }
355
356
        if(actionOK('export_raw')) {
357
            $head['link'][] = array(
358
                'rel' => 'alternate', 'type'=> 'text/plain', 'title'=> $lang['wikimarkup'],
359
                'href'=> exportlink($ID, 'raw', '', false, '&')
360
            );
361
        }
362
    }
363
364
    // setup robot tags apropriate for different modes
365
    if(($ACT == 'show' || $ACT == 'export_xhtml') && !$REV) {
366
        if($INFO['exists']) {
367
            //delay indexing:
368
            if((time() - $INFO['lastmod']) >= $conf['indexdelay']) {
369
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
370
            } else {
371
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
372
            }
373
            $canonicalUrl = wl($ID, '', true, '&');
374
            if ($ID == $conf['start']) {
375
                $canonicalUrl = DOKU_URL;
376
            }
377
            $head['link'][] = array('rel'=> 'canonical', 'href'=> $canonicalUrl);
378
        } else {
379
            $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,follow');
380
        }
381
    } elseif(defined('DOKU_MEDIADETAIL')) {
382
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
383
    } else {
384
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
385
    }
386
387
    // set metadata
388
    if($ACT == 'show' || $ACT == 'export_xhtml') {
389
        // keywords (explicit or implicit)
390
        if(!empty($INFO['meta']['subject'])) {
391
            $head['meta'][] = array('name'=> 'keywords', 'content'=> join(',', $INFO['meta']['subject']));
392
        } else {
393
            $head['meta'][] = array('name'=> 'keywords', 'content'=> str_replace(':', ',', $ID));
394
        }
395
    }
396
397
    // load stylesheets
398
    $head['link'][] = array(
399
        'rel' => 'stylesheet', 'type'=> 'text/css',
400
        'href'=> DOKU_BASE.'lib/exe/css.php?t='.rawurlencode($conf['template']).'&tseed='.$tseed
401
    );
402
403
    // make $INFO and other vars available to JavaScripts
404
    $json   = new JSON();
405
    $script = "var NS='".$INFO['namespace']."';";
406
    if($conf['useacl'] && $INPUT->server->str('REMOTE_USER')) {
407
        $script .= "var SIG='".toolbar_signature()."';";
408
    }
409
    $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
410
    $head['script'][] = array('type'=> 'text/javascript', '_data'=> $script);
411
412
    // load external javascript
413
    $head['script'][] = array(
414
        'type'=> 'text/javascript', 'charset'=> 'utf-8', '_data'=> '',
415
        'src' => DOKU_BASE.'lib/exe/js.php'.'?t='.rawurlencode($conf['template']).'&tseed='.$tseed
416
    );
417
418
    // trigger event here
419
    trigger_event('TPL_METAHEADER_OUTPUT', $head, '_tpl_metaheaders_action', true);
420
    return true;
421
}
422
423
/**
424
 * prints the array build by tpl_metaheaders
425
 *
426
 * $data is an array of different header tags. Each tag can have multiple
427
 * instances. Attributes are given as key value pairs. Values will be HTML
428
 * encoded automatically so they should be provided as is in the $data array.
429
 *
430
 * For tags having a body attribute specify the body data in the special
431
 * attribute '_data'. This field will NOT BE ESCAPED automatically.
432
 *
433
 * @author Andreas Gohr <[email protected]>
434
 *
435
 * @param array $data
436
 */
437
function _tpl_metaheaders_action($data) {
438
    foreach($data as $tag => $inst) {
439
        foreach($inst as $attr) {
440
            echo '<', $tag, ' ', buildAttributes($attr);
441
            if(isset($attr['_data']) || $tag == 'script') {
442
                if($tag == 'script' && $attr['_data'])
443
                    $attr['_data'] = "/*<![CDATA[*/".
444
                        $attr['_data'].
445
                        "\n/*!]]>*/";
446
447
                echo '>', $attr['_data'], '</', $tag, '>';
448
            } else {
449
                echo '/>';
450
            }
451
            echo "\n";
452
        }
453
    }
454
}
455
456
/**
457
 * Print a link
458
 *
459
 * Just builds a link.
460
 *
461
 * @author Andreas Gohr <[email protected]>
462
 *
463
 * @param string $url
464
 * @param string $name
465
 * @param string $more
466
 * @param bool $return if true return the link html, otherwise print
467
 * @return bool|string html of the link, or true if printed
468
 */
469
function tpl_link($url, $name, $more = '', $return = false) {
470
    $out = '<a href="'.$url.'" ';
471
    if($more) $out .= ' '.$more;
472
    $out .= ">$name</a>";
473
    if($return) return $out;
474
    print $out;
475
    return true;
476
}
477
478
/**
479
 * Prints a link to a WikiPage
480
 *
481
 * Wrapper around html_wikilink
482
 *
483
 * @author Andreas Gohr <[email protected]>
484
 *
485
 * @param string      $id   page id
486
 * @param string|null $name the name of the link
487
 * @return bool true
488
 */
489
function tpl_pagelink($id, $name = null) {
490
    print '<bdi>'.html_wikilink($id, $name).'</bdi>';
491
    return true;
492
}
493
494
/**
495
 * get the parent page
496
 *
497
 * Tries to find out which page is parent.
498
 * returns false if none is available
499
 *
500
 * @author Andreas Gohr <[email protected]>
501
 *
502
 * @param string $id page id
503
 * @return false|string
504
 */
505
function tpl_getparent($id) {
506
    $parent = getNS($id).':';
507
    resolve_pageid('', $parent, $exists);
508
    if($parent == $id) {
509
        $pos    = strrpos(getNS($id), ':');
510
        $parent = substr($parent, 0, $pos).':';
511
        resolve_pageid('', $parent, $exists);
512
        if($parent == $id) return false;
513
    }
514
    return $parent;
515
}
516
517
/**
518
 * Print one of the buttons
519
 *
520
 * @author Adrian Lang <[email protected]>
521
 * @see    tpl_get_action
522
 *
523
 * @param string $type
524
 * @param bool $return
525
 * @return bool|string html, or false if no data, true if printed
526
 */
527
function tpl_button($type, $return = false) {
528
    $data = tpl_get_action($type);
529
    if($data === false) {
530
        return false;
531
    } elseif(!is_array($data)) {
532
        $out = sprintf($data, 'button');
533
    } else {
534
        /**
535
         * @var string $accesskey
536
         * @var string $id
537
         * @var string $method
538
         * @var array  $params
539
         */
540
        extract($data);
541
        if($id === '#dokuwiki__top') {
542
            $out = html_topbtn();
543
        } else {
544
            $out = html_btn($type, $id, $accesskey, $params, $method);
545
        }
546
    }
547
    if($return) return $out;
548
    echo $out;
549
    return true;
550
}
551
552
/**
553
 * Like the action buttons but links
554
 *
555
 * @author Adrian Lang <[email protected]>
556
 * @see    tpl_get_action
557
 *
558
 * @param string $type    action command
559
 * @param string $pre     prefix of link
560
 * @param string $suf     suffix of link
561
 * @param string $inner   innerHML of link
562
 * @param bool   $return  if true it returns html, otherwise prints
563
 * @return bool|string html or false if no data, true if printed
564
 */
565
function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = false) {
566
    global $lang;
567
    $data = tpl_get_action($type);
568
    if($data === false) {
569
        return false;
570
    } elseif(!is_array($data)) {
571
        $out = sprintf($data, 'link');
572
    } else {
573
        /**
574
         * @var string $accesskey
575
         * @var string $id
576
         * @var string $method
577
         * @var bool   $nofollow
578
         * @var array  $params
579
         * @var string $replacement
580
         */
581
        extract($data);
582
        if(strpos($id, '#') === 0) {
583
            $linktarget = $id;
584
        } else {
585
            $linktarget = wl($id, $params);
586
        }
587
        $caption = $lang['btn_'.$type];
588
        if(strpos($caption, '%s')){
589
            $caption = sprintf($caption, $replacement);
590
        }
591
        $akey    = $addTitle = '';
592
        if($accesskey) {
593
            $akey     = 'accesskey="'.$accesskey.'" ';
594
            $addTitle = ' ['.strtoupper($accesskey).']';
595
        }
596
        $rel = $nofollow ? 'rel="nofollow" ' : '';
597
        $out = tpl_link(
598
            $linktarget, $pre.(($inner) ? $inner : $caption).$suf,
599
            'class="action '.$type.'" '.
600
                $akey.$rel.
601
                'title="'.hsc($caption).$addTitle.'"', true
602
        );
603
    }
604
    if($return) return $out;
605
    echo $out;
606
    return true;
607
}
608
609
/**
610
 * Check the actions and get data for buttons and links
611
 *
612
 * Available actions are
613
 *
614
 *  edit        - edit/create/show/draft
615
 *  history     - old revisions
616
 *  recent      - recent changes
617
 *  login       - login/logout - if ACL enabled
618
 *  profile     - user profile (if logged in)
619
 *  index       - The index
620
 *  admin       - admin page - if enough rights
621
 *  top         - back to top
622
 *  back        - back to parent - if available
623
 *  backlink    - links to the list of backlinks
624
 *  subscribe/subscription- subscribe/unsubscribe
625
 *
626
 * @author Andreas Gohr <[email protected]>
627
 * @author Matthias Grimm <[email protected]>
628
 * @author Adrian Lang <[email protected]>
629
 *
630
 * @param string $type
631
 * @return array|bool|string
632
 */
633
function tpl_get_action($type) {
634
    global $ID;
635
    global $INFO;
636
    global $REV;
637
    global $ACT;
638
    global $conf;
639
    /** @var Input $INPUT */
640
    global $INPUT;
641
642
    // check disabled actions and fix the badly named ones
643
    if($type == 'history') $type = 'revisions';
644
    if ($type == 'subscription') $type = 'subscribe';
645
    if(!actionOK($type)) return false;
646
647
    $accesskey   = null;
648
    $id          = $ID;
649
    $method      = 'get';
650
    $params      = array('do' => $type);
651
    $nofollow    = true;
652
    $replacement = '';
653
654
    $unknown = false;
655
    switch($type) {
656
        case 'edit':
657
            // most complicated type - we need to decide on current action
658
            if($ACT == 'show' || $ACT == 'search') {
659
                $method = 'post';
660
                if($INFO['writable']) {
661
                    $accesskey = 'e';
662
                    if(!empty($INFO['draft'])) {
663
                        $type         = 'draft';
664
                        $params['do'] = 'draft';
665
                    } else {
666
                        $params['rev'] = $REV;
667
                        if(!$INFO['exists']) {
668
                            $type = 'create';
669
                        }
670
                    }
671
                } else {
672
                    if(!actionOK('source')) return false; //pseudo action
673
                    $params['rev'] = $REV;
674
                    $type          = 'source';
675
                    $accesskey     = 'v';
676
                }
677
            } else {
678
                $params    = array('do' => '');
679
                $type      = 'show';
680
                $accesskey = 'v';
681
            }
682
            break;
683
        case 'revisions':
684
            $type      = 'revs';
685
            $accesskey = 'o';
686
            break;
687
        case 'recent':
688
            $accesskey = 'r';
689
            break;
690
        case 'index':
691
            $accesskey = 'x';
692
            // allow searchbots to get to the sitemap from the homepage (when dokuwiki isn't providing a sitemap.xml)
693
            if ($conf['start'] == $ID && !$conf['sitemap']) {
694
                $nofollow = false;
695
            }
696
            break;
697
        case 'top':
698
            $accesskey = 't';
699
            $params    = array('do' => '');
700
            $id        = '#dokuwiki__top';
701
            break;
702
        case 'back':
703
            $parent = tpl_getparent($ID);
704
            if(!$parent) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parent of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
705
                return false;
706
            }
707
            $id        = $parent;
708
            $params    = array('do' => '');
709
            $accesskey = 'b';
710
            break;
711
        case 'img_backto':
712
            $params = array();
713
            $accesskey = 'b';
714
            $replacement = $ID;
715
            break;
716
        case 'login':
717
            $params['sectok'] = getSecurityToken();
718
            if($INPUT->server->has('REMOTE_USER')) {
719
                if(!actionOK('logout')) {
720
                    return false;
721
                }
722
                $params['do'] = 'logout';
723
                $type         = 'logout';
724
            }
725
            break;
726
        case 'register':
727
            if($INPUT->server->str('REMOTE_USER')) {
728
                return false;
729
            }
730
            break;
731
        case 'resendpwd':
732
            if($INPUT->server->str('REMOTE_USER')) {
733
                return false;
734
            }
735
            break;
736
        case 'admin':
737
            if(!$INFO['ismanager']) {
738
                return false;
739
            }
740
            break;
741
        case 'revert':
742
            if(!$INFO['ismanager'] || !$REV || !$INFO['writable']) {
743
                return false;
744
            }
745
            $params['rev']    = $REV;
746
            $params['sectok'] = getSecurityToken();
747
            break;
748
        case 'subscribe':
749
            if(!$INPUT->server->str('REMOTE_USER')) {
750
                return false;
751
            }
752
            break;
753
        case 'backlink':
754
            break;
755
        case 'profile':
756
            if(!$INPUT->server->has('REMOTE_USER')) {
757
                return false;
758
            }
759
            break;
760
        case 'media':
761
            $params['ns'] = getNS($ID);
762
            break;
763
        case 'mediaManager':
764
            // View image in media manager
765
            global $IMG;
766
            $imgNS = getNS($IMG);
767
            $authNS = auth_quickaclcheck("$imgNS:*");
768
            if ($authNS < AUTH_UPLOAD) {
769
                return false;
770
            }
771
            $params = array(
772
                'ns' => $imgNS,
773
                'image' => $IMG,
774
                'do' => 'media'
775
            );
776
            //$type = 'media';
777
            break;
778
        default:
779
            //unknown type
780
            $unknown = true;
781
    }
782
783
    $data = compact('accesskey', 'type', 'id', 'method', 'params', 'nofollow', 'replacement');
784
785
    $evt = new Doku_Event('TPL_ACTION_GET', $data);
786
    if($evt->advise_before()) {
787
        //handle unknown types
788
        if($unknown) {
789
            $data = '[unknown %s type]';
790
        }
791
    }
792
    $evt->advise_after();
793
    unset($evt);
794
795
    return $data;
796
}
797
798
/**
799
 * Wrapper around tpl_button() and tpl_actionlink()
800
 *
801
 * @author Anika Henke <[email protected]>
802
 *
803
 * @param string        $type action command
804
 * @param bool          $link link or form button?
805
 * @param string|bool   $wrapper HTML element wrapper
806
 * @param bool          $return return or print
807
 * @param string        $pre prefix for links
808
 * @param string        $suf suffix for links
809
 * @param string        $inner inner HTML for links
810
 * @return bool|string
811
 */
812
function tpl_action($type, $link = false, $wrapper = false, $return = false, $pre = '', $suf = '', $inner = '') {
813
    $out = '';
814
    if($link) {
815
        $out .= tpl_actionlink($type, $pre, $suf, $inner, true);
816
    } else {
817
        $out .= tpl_button($type, true);
818
    }
819
    if($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
820
821
    if($return) return $out;
822
    print $out;
823
    return $out ? true : false;
824
}
825
826
/**
827
 * Print the search form
828
 *
829
 * If the first parameter is given a div with the ID 'qsearch_out' will
830
 * be added which instructs the ajax pagequicksearch to kick in and place
831
 * its output into this div. The second parameter controls the propritary
832
 * attribute autocomplete. If set to false this attribute will be set with an
833
 * value of "off" to instruct the browser to disable it's own built in
834
 * autocompletion feature (MSIE and Firefox)
835
 *
836
 * @author Andreas Gohr <[email protected]>
837
 *
838
 * @param bool $ajax
839
 * @param bool $autocomplete
840
 * @return bool
841
 */
842
function tpl_searchform($ajax = true, $autocomplete = true) {
843
    global $lang;
844
    global $ACT;
845
    global $QUERY;
846
847
    // don't print the search form if search action has been disabled
848
    if(!actionOK('search')) return false;
849
850
    print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get" role="search"><div class="no">';
851
    print '<input type="hidden" name="do" value="search" />';
852
    print '<input type="text" ';
853
    if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" ';
854
    print 'placeholder="'.$lang['btn_search'].'" ';
855
    if(!$autocomplete) print 'autocomplete="off" ';
856
    print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
857
    print '<button type="submit" title="'.$lang['btn_search'].'">'.$lang['btn_search'].'</button>';
858
    if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
859
    print '</div></form>';
860
    return true;
861
}
862
863
/**
864
 * Print the breadcrumbs trace
865
 *
866
 * @author Andreas Gohr <[email protected]>
867
 *
868
 * @param string $sep Separator between entries
869
 * @return bool
870
 */
871
function tpl_breadcrumbs($sep = '•') {
872
    global $lang;
873
    global $conf;
874
875
    //check if enabled
876
    if(!$conf['breadcrumbs']) return false;
877
878
    $crumbs = breadcrumbs(); //setup crumb trace
879
880
    $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
881
882
    //render crumbs, highlight the last one
883
    print '<span class="bchead">'.$lang['breadcrumb'].'</span>';
884
    $last = count($crumbs);
885
    $i    = 0;
886
    foreach($crumbs as $id => $name) {
887
        $i++;
888
        echo $crumbs_sep;
889
        if($i == $last) print '<span class="curid">';
890
        print '<bdi>';
891
        tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"');
892
        print '</bdi>';
893
        if($i == $last) print '</span>';
894
    }
895
    return true;
896
}
897
898
/**
899
 * Hierarchical breadcrumbs
900
 *
901
 * This code was suggested as replacement for the usual breadcrumbs.
902
 * It only makes sense with a deep site structure.
903
 *
904
 * @author Andreas Gohr <[email protected]>
905
 * @author Nigel McNie <[email protected]>
906
 * @author Sean Coates <[email protected]>
907
 * @author <[email protected]>
908
 * @todo   May behave strangely in RTL languages
909
 *
910
 * @param string $sep Separator between entries
911
 * @return bool
912
 */
913
function tpl_youarehere($sep = ' » ') {
914
    global $conf;
915
    global $ID;
916
    global $lang;
917
918
    // check if enabled
919
    if(!$conf['youarehere']) return false;
920
921
    $parts = explode(':', $ID);
922
    $count = count($parts);
923
924
    echo '<span class="bchead">'.$lang['youarehere'].' </span>';
925
926
    // always print the startpage
927
    echo '<span class="home">';
928
    tpl_pagelink(':'.$conf['start']);
929
    echo '</span>';
930
931
    // print intermediate namespace links
932
    $part = '';
933
    for($i = 0; $i < $count - 1; $i++) {
934
        $part .= $parts[$i].':';
935
        $page = $part;
936
        if($page == $conf['start']) continue; // Skip startpage
937
938
        // output
939
        echo $sep;
940
        tpl_pagelink($page);
941
    }
942
943
    // print current page, skipping start page, skipping for namespace index
944
    resolve_pageid('', $page, $exists);
945
    if(isset($page) && $page == $part.$parts[$i]) return true;
946
    $page = $part.$parts[$i];
947
    if($page == $conf['start']) return true;
948
    echo $sep;
949
    tpl_pagelink($page);
950
    return true;
951
}
952
953
/**
954
 * Print info if the user is logged in
955
 * and show full name in that case
956
 *
957
 * Could be enhanced with a profile link in future?
958
 *
959
 * @author Andreas Gohr <[email protected]>
960
 *
961
 * @return bool
962
 */
963
function tpl_userinfo() {
964
    global $lang;
965
    /** @var Input $INPUT */
966
    global $INPUT;
967
968
    if($INPUT->server->str('REMOTE_USER')) {
969
        print $lang['loggedinas'].' '.userlink();
970
        return true;
971
    }
972
    return false;
973
}
974
975
/**
976
 * Print some info about the current page
977
 *
978
 * @author Andreas Gohr <[email protected]>
979
 *
980
 * @param bool $ret return content instead of printing it
981
 * @return bool|string
982
 */
983
function tpl_pageinfo($ret = false) {
984
    global $conf;
985
    global $lang;
986
    global $INFO;
987
    global $ID;
988
989
    // return if we are not allowed to view the page
990
    if(!auth_quickaclcheck($ID)) {
991
        return false;
992
    }
993
994
    // prepare date and path
995
    $fn = $INFO['filepath'];
996
    if(!$conf['fullpath']) {
997
        if($INFO['rev']) {
998
            $fn = str_replace(fullpath($conf['olddir']).'/', '', $fn);
999
        } else {
1000
            $fn = str_replace(fullpath($conf['datadir']).'/', '', $fn);
1001
        }
1002
    }
1003
    $fn   = utf8_decodeFN($fn);
1004
    $date = dformat($INFO['lastmod']);
1005
1006
    // print it
1007
    if($INFO['exists']) {
1008
        $out = '';
1009
        $out .= '<bdi>'.$fn.'</bdi>';
1010
        $out .= ' · ';
1011
        $out .= $lang['lastmod'];
1012
        $out .= ' ';
1013
        $out .= $date;
1014
        if($INFO['editor']) {
1015
            $out .= ' '.$lang['by'].' ';
1016
            $out .= '<bdi>'.editorinfo($INFO['editor']).'</bdi>';
1017
        } else {
1018
            $out .= ' ('.$lang['external_edit'].')';
1019
        }
1020
        if($INFO['locked']) {
1021
            $out .= ' · ';
1022
            $out .= $lang['lockedby'];
1023
            $out .= ' ';
1024
            $out .= '<bdi>'.editorinfo($INFO['locked']).'</bdi>';
1025
        }
1026
        if($ret) {
1027
            return $out;
1028
        } else {
1029
            echo $out;
1030
            return true;
1031
        }
1032
    }
1033
    return false;
1034
}
1035
1036
/**
1037
 * Prints or returns the name of the given page (current one if none given).
1038
 *
1039
 * If useheading is enabled this will use the first headline else
1040
 * the given ID is used.
1041
 *
1042
 * @author Andreas Gohr <[email protected]>
1043
 *
1044
 * @param string $id page id
1045
 * @param bool   $ret return content instead of printing
1046
 * @return bool|string
1047
 */
1048
function tpl_pagetitle($id = null, $ret = false) {
1049
    global $ACT, $INPUT, $conf, $lang;
1050
1051
    if(is_null($id)) {
1052
        global $ID;
1053
        $id = $ID;
1054
    }
1055
1056
    $name = $id;
1057
    if(useHeading('navigation')) {
1058
        $first_heading = p_get_first_heading($id);
1059
        if($first_heading) $name = $first_heading;
0 ignored issues
show
Bug Best Practice introduced by
The expression $first_heading of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1060
    }
1061
1062
    // default page title is the page name, modify with the current action
1063
    switch ($ACT) {
1064
        // admin functions
1065
        case 'admin' :
1066
            $page_title = $lang['btn_admin'];
1067
            // try to get the plugin name
1068
            /** @var $plugin DokuWiki_Admin_Plugin */
1069
            if ($plugin = plugin_getRequestAdminPlugin()){
1070
                $plugin_title = $plugin->getMenuText($conf['lang']);
1071
                $page_title = $plugin_title ? $plugin_title : $plugin->getPluginName();
1072
            }
1073
            break;
1074
1075
        // user functions
1076
        case 'login' :
1077
        case 'profile' :
1078
        case 'register' :
1079
        case 'resendpwd' :
1080
            $page_title = $lang['btn_'.$ACT];
1081
            break;
1082
1083
         // wiki functions
1084
        case 'search' :
1085
        case 'index' :
1086
            $page_title = $lang['btn_'.$ACT];
1087
            break;
1088
1089
        // page functions
1090
        case 'edit' :
1091
            $page_title = "✎ ".$name;
1092
            break;
1093
1094
        case 'revisions' :
1095
            $page_title = $name . ' - ' . $lang['btn_revs'];
1096
            break;
1097
1098
        case 'backlink' :
1099
        case 'recent' :
1100
        case 'subscribe' :
1101
            $page_title = $name . ' - ' . $lang['btn_'.$ACT];
1102
            break;
1103
1104
        default : // SHOW and anything else not included
1105
            $page_title = $name;
1106
    }
1107
1108
    if($ret) {
1109
        return hsc($page_title);
1110
    } else {
1111
        print hsc($page_title);
1112
        return true;
1113
    }
1114
}
1115
1116
/**
1117
 * Returns the requested EXIF/IPTC tag from the current image
1118
 *
1119
 * If $tags is an array all given tags are tried until a
1120
 * value is found. If no value is found $alt is returned.
1121
 *
1122
 * Which texts are known is defined in the functions _exifTagNames
1123
 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
1124
 * to the names of the latter one)
1125
 *
1126
 * Only allowed in: detail.php
1127
 *
1128
 * @author Andreas Gohr <[email protected]>
1129
 *
1130
 * @param array|string $tags tag or array of tags to try
1131
 * @param string       $alt  alternative output if no data was found
1132
 * @param null|string  $src  the image src, uses global $SRC if not given
1133
 * @return string
1134
 */
1135
function tpl_img_getTag($tags, $alt = '', $src = null) {
1136
    // Init Exif Reader
1137
    global $SRC;
1138
1139
    if(is_null($src)) $src = $SRC;
1140
1141
    static $meta = null;
1142
    if(is_null($meta)) $meta = new JpegMeta($src);
1143
    if($meta === false) return $alt;
1144
    $info = cleanText($meta->getField($tags));
1145
    if($info == false) return $alt;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $info of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
1146
    return $info;
1147
}
1148
1149
/**
1150
 * Returns a description list of the metatags of the current image
1151
 *
1152
 * @return string html of description list
1153
 */
1154
function tpl_img_meta() {
1155
    global $lang;
1156
1157
    $tags = tpl_get_img_meta();
1158
1159
    echo '<dl>';
1160
    foreach($tags as $tag) {
1161
        $label = $lang[$tag['langkey']];
1162
        if(!$label) $label = $tag['langkey'] . ':';
1163
1164
        echo '<dt>'.$label.'</dt><dd>';
1165
        if ($tag['type'] == 'date') {
1166
            echo dformat($tag['value']);
1167
        } else {
1168
            echo hsc($tag['value']);
1169
        }
1170
        echo '</dd>';
1171
    }
1172
    echo '</dl>';
1173
}
1174
1175
/**
1176
 * Returns metadata as configured in mediameta config file, ready for creating html
1177
 *
1178
 * @return array with arrays containing the entries:
1179
 *   - string langkey  key to lookup in the $lang var, if not found printed as is
1180
 *   - string type     type of value
1181
 *   - string value    tag value (unescaped)
1182
 */
1183
function tpl_get_img_meta() {
1184
1185
    $config_files = getConfigFiles('mediameta');
1186
    foreach ($config_files as $config_file) {
1187
        if(file_exists($config_file)) {
1188
            include($config_file);
1189
        }
1190
    }
1191
    /** @var array $fields the included array with metadata */
1192
1193
    $tags = array();
1194
    foreach($fields as $tag){
0 ignored issues
show
Bug introduced by
The variable $fields does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1195
        $t = array();
1196
        if (!empty($tag[0])) {
1197
            $t = array($tag[0]);
1198
        }
1199
        if(is_array($tag[3])) {
1200
            $t = array_merge($t,$tag[3]);
1201
        }
1202
        $value = tpl_img_getTag($t);
1203
        if ($value) {
1204
            $tags[] = array('langkey' => $tag[1], 'type' => $tag[2], 'value' => $value);
1205
        }
1206
    }
1207
    return $tags;
1208
}
1209
1210
/**
1211
 * Prints the image with a link to the full sized version
1212
 *
1213
 * Only allowed in: detail.php
1214
 *
1215
 * @triggers TPL_IMG_DISPLAY
1216
 * @param $maxwidth  int - maximal width of the image
1217
 * @param $maxheight int - maximal height of the image
1218
 * @param $link bool     - link to the orginal size?
1219
 * @param $params array  - additional image attributes
1220
 * @return bool Result of TPL_IMG_DISPLAY
1221
 */
1222
function tpl_img($maxwidth = 0, $maxheight = 0, $link = true, $params = null) {
1223
    global $IMG;
1224
    /** @var Input $INPUT */
1225
    global $INPUT;
1226
    global $REV;
1227
    $w = tpl_img_getTag('File.Width');
1228
    $h = tpl_img_getTag('File.Height');
1229
1230
    //resize to given max values
1231
    $ratio = 1;
1232
    if($w >= $h) {
1233
        if($maxwidth && $w >= $maxwidth) {
1234
            $ratio = $maxwidth / $w;
1235
        } elseif($maxheight && $h > $maxheight) {
1236
            $ratio = $maxheight / $h;
1237
        }
1238
    } else {
1239
        if($maxheight && $h >= $maxheight) {
1240
            $ratio = $maxheight / $h;
1241
        } elseif($maxwidth && $w > $maxwidth) {
1242
            $ratio = $maxwidth / $w;
1243
        }
1244
    }
1245
    if($ratio) {
1246
        $w = floor($ratio * $w);
1247
        $h = floor($ratio * $h);
1248
    }
1249
1250
    //prepare URLs
1251
    $url = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV), true, '&');
1252
    $src = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV, 'w'=> $w, 'h'=> $h), true, '&');
1253
1254
    //prepare attributes
1255
    $alt = tpl_img_getTag('Simple.Title');
1256
    if(is_null($params)) {
1257
        $p = array();
1258
    } else {
1259
        $p = $params;
1260
    }
1261
    if($w) $p['width'] = $w;
1262
    if($h) $p['height'] = $h;
1263
    $p['class'] = 'img_detail';
1264
    if($alt) {
1265
        $p['alt']   = $alt;
1266
        $p['title'] = $alt;
1267
    } else {
1268
        $p['alt'] = '';
1269
    }
1270
    $p['src'] = $src;
1271
1272
    $data = array('url'=> ($link ? $url : null), 'params'=> $p);
1273
    return trigger_event('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
1274
}
1275
1276
/**
1277
 * Default action for TPL_IMG_DISPLAY
1278
 *
1279
 * @param array $data
1280
 * @return bool
1281
 */
1282
function _tpl_img_action($data) {
1283
    global $lang;
1284
    $p = buildAttributes($data['params']);
1285
1286
    if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">';
1287
    print '<img '.$p.'/>';
1288
    if($data['url']) print '</a>';
1289
    return true;
1290
}
1291
1292
/**
1293
 * This function inserts a small gif which in reality is the indexer function.
1294
 *
1295
 * Should be called somewhere at the very end of the main.php
1296
 * template
1297
 *
1298
 * @return bool
1299
 */
1300
function tpl_indexerWebBug() {
1301
    global $ID;
1302
1303
    $p           = array();
1304
    $p['src']    = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID).
1305
        '&'.time();
1306
    $p['width']  = 2; //no more 1x1 px image because we live in times of ad blockers...
1307
    $p['height'] = 1;
1308
    $p['alt']    = '';
1309
    $att         = buildAttributes($p);
1310
    print "<img $att />";
1311
    return true;
1312
}
1313
1314
/**
1315
 * tpl_getConf($id)
1316
 *
1317
 * use this function to access template configuration variables
1318
 *
1319
 * @param string $id      name of the value to access
1320
 * @param mixed  $notset  what to return if the setting is not available
1321
 * @return mixed
1322
 */
1323
function tpl_getConf($id, $notset=false) {
1324
    global $conf;
1325
    static $tpl_configloaded = false;
1326
1327
    $tpl = $conf['template'];
1328
1329
    if(!$tpl_configloaded) {
1330
        $tconf = tpl_loadConfig();
1331
        if($tconf !== false) {
1332
            foreach($tconf as $key => $value) {
1333
                if(isset($conf['tpl'][$tpl][$key])) continue;
1334
                $conf['tpl'][$tpl][$key] = $value;
1335
            }
1336
            $tpl_configloaded = true;
1337
        }
1338
    }
1339
1340
    if(isset($conf['tpl'][$tpl][$id])){
1341
        return $conf['tpl'][$tpl][$id];
1342
    }
1343
1344
    return $notset;
1345
}
1346
1347
/**
1348
 * tpl_loadConfig()
1349
 *
1350
 * reads all template configuration variables
1351
 * this function is automatically called by tpl_getConf()
1352
 *
1353
 * @return array
1354
 */
1355
function tpl_loadConfig() {
1356
1357
    $file = tpl_incdir().'/conf/default.php';
1358
    $conf = array();
1359
1360
    if(!file_exists($file)) return false;
1361
1362
    // load default config file
1363
    include($file);
1364
1365
    return $conf;
1366
}
1367
1368
// language methods
1369
/**
1370
 * tpl_getLang($id)
1371
 *
1372
 * use this function to access template language variables
1373
 *
1374
 * @param string $id key of language string
1375
 * @return string
1376
 */
1377
function tpl_getLang($id) {
1378
    static $lang = array();
1379
1380
    if(count($lang) === 0) {
1381
        global $conf, $config_cascade; // definitely don't invoke "global $lang"
1382
1383
        $path = tpl_incdir() . 'lang/';
1384
1385
        $lang = array();
1386
1387
        // don't include once
1388
        @include($path . 'en/lang.php');
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1389
        foreach($config_cascade['lang']['template'] as $config_file) {
1390
            if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
1391
                include($config_file . $conf['template'] . '/en/lang.php');
1392
            }
1393
        }
1394
1395
        if($conf['lang'] != 'en') {
1396
            @include($path . $conf['lang'] . '/lang.php');
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1397
            foreach($config_cascade['lang']['template'] as $config_file) {
1398
                if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
1399
                    include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
1400
                }
1401
            }
1402
        }
1403
    }
1404
    return $lang[$id];
1405
}
1406
1407
/**
1408
 * Retrieve a language dependent file and pass to xhtml renderer for display
1409
 * template equivalent of p_locale_xhtml()
1410
 *
1411
 * @param   string $id id of language dependent wiki page
1412
 * @return  string     parsed contents of the wiki page in xhtml format
1413
 */
1414
function tpl_locale_xhtml($id) {
1415
    return p_cached_output(tpl_localeFN($id));
1416
}
1417
1418
/**
1419
 * Prepends appropriate path for a language dependent filename
1420
 *
1421
 * @param string $id id of localized text
1422
 * @return string wiki text
1423
 */
1424
function tpl_localeFN($id) {
1425
    $path = tpl_incdir().'lang/';
1426
    global $conf;
1427
    $file = DOKU_CONF.'template_lang/'.$conf['template'].'/'.$conf['lang'].'/'.$id.'.txt';
1428
    if (!file_exists($file)){
1429
        $file = $path.$conf['lang'].'/'.$id.'.txt';
1430
        if(!file_exists($file)){
1431
            //fall back to english
1432
            $file = $path.'en/'.$id.'.txt';
1433
        }
1434
    }
1435
    return $file;
1436
}
1437
1438
/**
1439
 * prints the "main content" in the mediamanager popup
1440
 *
1441
 * Depending on the user's actions this may be a list of
1442
 * files in a namespace, the meta editing dialog or
1443
 * a message of referencing pages
1444
 *
1445
 * Only allowed in mediamanager.php
1446
 *
1447
 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1448
 * @param bool $fromajax - set true when calling this function via ajax
1449
 * @param string $sort
1450
 *
1451
 * @author Andreas Gohr <[email protected]>
1452
 */
1453
function tpl_mediaContent($fromajax = false, $sort='natural') {
1454
    global $IMG;
1455
    global $AUTH;
1456
    global $INUSE;
1457
    global $NS;
1458
    global $JUMPTO;
1459
    /** @var Input $INPUT */
1460
    global $INPUT;
1461
1462
    $do = $INPUT->extract('do')->str('do');
1463
    if(in_array($do, array('save', 'cancel'))) $do = '';
1464
1465
    if(!$do) {
1466
        if($INPUT->bool('edit')) {
1467
            $do = 'metaform';
1468
        } elseif(is_array($INUSE)) {
1469
            $do = 'filesinuse';
1470
        } else {
1471
            $do = 'filelist';
1472
        }
1473
    }
1474
1475
    // output the content pane, wrapped in an event.
1476
    if(!$fromajax) ptln('<div id="media__content">');
1477
    $data = array('do' => $do);
1478
    $evt  = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1479
    if($evt->advise_before()) {
1480
        $do = $data['do'];
1481
        if($do == 'filesinuse') {
1482
            media_filesinuse($INUSE, $IMG);
1483
        } elseif($do == 'filelist') {
1484
            media_filelist($NS, $AUTH, $JUMPTO,false,$sort);
1485
        } elseif($do == 'searchlist') {
1486
            media_searchlist($INPUT->str('q'), $NS, $AUTH);
1487
        } else {
1488
            msg('Unknown action '.hsc($do), -1);
1489
        }
1490
    }
1491
    $evt->advise_after();
1492
    unset($evt);
1493
    if(!$fromajax) ptln('</div>');
1494
1495
}
1496
1497
/**
1498
 * Prints the central column in full-screen media manager
1499
 * Depending on the opened tab this may be a list of
1500
 * files in a namespace, upload form or search form
1501
 *
1502
 * @author Kate Arzamastseva <[email protected]>
1503
 */
1504
function tpl_mediaFileList() {
1505
    global $AUTH;
1506
    global $NS;
1507
    global $JUMPTO;
1508
    global $lang;
1509
    /** @var Input $INPUT */
1510
    global $INPUT;
1511
1512
    $opened_tab = $INPUT->str('tab_files');
1513
    if(!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files';
1514
    if($INPUT->str('mediado') == 'update') $opened_tab = 'upload';
1515
1516
    echo '<h2 class="a11y">'.$lang['mediaselect'].'</h2>'.NL;
1517
1518
    media_tabs_files($opened_tab);
1519
1520
    echo '<div class="panelHeader">'.NL;
1521
    echo '<h3>';
1522
    $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']';
1523
    printf($lang['media_'.$opened_tab], '<strong>'.hsc($tabTitle).'</strong>');
1524
    echo '</h3>'.NL;
1525
    if($opened_tab === 'search' || $opened_tab === 'files') {
1526
        media_tab_files_options();
1527
    }
1528
    echo '</div>'.NL;
1529
1530
    echo '<div class="panelContent">'.NL;
1531
    if($opened_tab == 'files') {
1532
        media_tab_files($NS, $AUTH, $JUMPTO);
1533
    } elseif($opened_tab == 'upload') {
1534
        media_tab_upload($NS, $AUTH, $JUMPTO);
1535
    } elseif($opened_tab == 'search') {
1536
        media_tab_search($NS, $AUTH);
1537
    }
1538
    echo '</div>'.NL;
1539
}
1540
1541
/**
1542
 * Prints the third column in full-screen media manager
1543
 * Depending on the opened tab this may be details of the
1544
 * selected file, the meta editing dialog or
1545
 * list of file revisions
1546
 *
1547
 * @author Kate Arzamastseva <[email protected]>
1548
 */
1549
function tpl_mediaFileDetails($image, $rev) {
1550
    global $conf, $DEL, $lang;
1551
    /** @var Input $INPUT */
1552
    global $INPUT;
1553
1554
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')) && $conf['mediarevisions']);
1555
    if(!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return;
1556
    if($rev && !file_exists(mediaFN($image, $rev))) $rev = false;
1557
    $ns = getNS($image);
1558
    $do = $INPUT->str('mediado');
1559
1560
    $opened_tab = $INPUT->str('tab_details');
1561
1562
    $tab_array = array('view');
1563
    list(, $mime) = mimetype($image);
1564
    if($mime == 'image/jpeg') {
1565
        $tab_array[] = 'edit';
1566
    }
1567
    if($conf['mediarevisions']) {
1568
        $tab_array[] = 'history';
1569
    }
1570
1571
    if(!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view';
1572
    if($INPUT->bool('edit')) $opened_tab = 'edit';
1573
    if($do == 'restore') $opened_tab = 'view';
1574
1575
    media_tabs_details($image, $opened_tab);
1576
1577
    echo '<div class="panelHeader"><h3>';
1578
    list($ext) = mimetype($image, false);
1579
    $class    = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1580
    $class    = 'select mediafile mf_'.$class;
1581
    $tabTitle = '<strong><a href="'.ml($image).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>';
1582
    if($opened_tab === 'view' && $rev) {
1583
        printf($lang['media_viewold'], $tabTitle, dformat($rev));
1584
    } else {
1585
        printf($lang['media_'.$opened_tab], $tabTitle);
1586
    }
1587
1588
    echo '</h3></div>'.NL;
1589
1590
    echo '<div class="panelContent">'.NL;
1591
1592
    if($opened_tab == 'view') {
1593
        media_tab_view($image, $ns, null, $rev);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1557 can also be of type false; however, media_tab_view() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1594
1595
    } elseif($opened_tab == 'edit' && !$removed) {
1596
        media_tab_edit($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1557 can also be of type false; however, media_tab_edit() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1597
1598
    } elseif($opened_tab == 'history' && $conf['mediarevisions']) {
1599
        media_tab_history($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1557 can also be of type false; however, media_tab_history() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1600
    }
1601
1602
    echo '</div>'.NL;
1603
}
1604
1605
/**
1606
 * prints the namespace tree in the mediamanager popup
1607
 *
1608
 * Only allowed in mediamanager.php
1609
 *
1610
 * @author Andreas Gohr <[email protected]>
1611
 */
1612
function tpl_mediaTree() {
1613
    global $NS;
1614
    ptln('<div id="media__tree">');
1615
    media_nstree($NS);
1616
    ptln('</div>');
1617
}
1618
1619
/**
1620
 * Print a dropdown menu with all DokuWiki actions
1621
 *
1622
 * Note: this will not use any pretty URLs
1623
 *
1624
 * @author Andreas Gohr <[email protected]>
1625
 *
1626
 * @param string $empty empty option label
1627
 * @param string $button submit button label
1628
 */
1629
function tpl_actiondropdown($empty = '', $button = '&gt;') {
1630
    global $ID;
1631
    global $REV;
1632
    global $lang;
1633
    /** @var Input $INPUT */
1634
    global $INPUT;
1635
1636
    $action_structure = array(
1637
        'page_tools' => array('edit', 'revert', 'revisions', 'backlink', 'subscribe'),
1638
        'site_tools' => array('recent', 'media', 'index'),
1639
        'user_tools' => array('login', 'register', 'profile', 'admin'),
1640
    );
1641
1642
    echo '<form action="'.script().'" method="get" accept-charset="utf-8">';
1643
    echo '<div class="no">';
1644
    echo '<input type="hidden" name="id" value="'.$ID.'" />';
1645
    if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />';
1646
    if ($INPUT->server->str('REMOTE_USER')) {
1647
        echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
1648
    }
1649
1650
    echo '<select name="do" class="edit quickselect" title="'.$lang['tools'].'">';
1651
    echo '<option value="">'.$empty.'</option>';
1652
1653
    foreach($action_structure as $tools => $actions) {
1654
        echo '<optgroup label="'.$lang[$tools].'">';
1655
        foreach($actions as $action) {
1656
            $act = tpl_get_action($action);
1657
            if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1658
        }
1659
        echo '</optgroup>';
1660
    }
1661
1662
    echo '</select>';
1663
    echo '<button type="submit">'.$button.'</button>';
1664
    echo '</div>';
1665
    echo '</form>';
1666
}
1667
1668
/**
1669
 * Print a informational line about the used license
1670
 *
1671
 * @author Andreas Gohr <[email protected]>
1672
 * @param  string $img     print image? (|button|badge)
1673
 * @param  bool   $imgonly skip the textual description?
1674
 * @param  bool   $return  when true don't print, but return HTML
1675
 * @param  bool   $wrap    wrap in div with class="license"?
1676
 * @return string
1677
 */
1678
function tpl_license($img = 'badge', $imgonly = false, $return = false, $wrap = true) {
1679
    global $license;
1680
    global $conf;
1681
    global $lang;
1682
    if(!$conf['license']) return '';
1683
    if(!is_array($license[$conf['license']])) return '';
1684
    $lic    = $license[$conf['license']];
1685
    $target = ($conf['target']['extern']) ? ' target="'.$conf['target']['extern'].'"' : '';
1686
1687
    $out = '';
1688
    if($wrap) $out .= '<div class="license">';
1689
    if($img) {
1690
        $src = license_img($img);
1691
        if($src) {
1692
            $out .= '<a href="'.$lic['url'].'" rel="license"'.$target;
1693
            $out .= '><img src="'.DOKU_BASE.$src.'" alt="'.$lic['name'].'" /></a>';
1694
            if(!$imgonly) $out .= ' ';
1695
        }
1696
    }
1697
    if(!$imgonly) {
1698
        $out .= $lang['license'].' ';
1699
        $out .= '<bdi><a href="'.$lic['url'].'" rel="license" class="urlextern"'.$target;
1700
        $out .= '>'.$lic['name'].'</a></bdi>';
1701
    }
1702
    if($wrap) $out .= '</div>';
1703
1704
    if($return) return $out;
1705
    echo $out;
1706
    return '';
1707
}
1708
1709
/**
1710
 * Includes the rendered HTML of a given page
1711
 *
1712
 * This function is useful to populate sidebars or similar features in a
1713
 * template
1714
 *
1715
 * @param string $pageid The page name you want to include
1716
 * @param bool $print Should the content be printed or returned only
1717
 * @param bool $propagate Search higher namespaces, too?
1718
 * @param bool $useacl Include the page only if the ACLs check out?
1719
 * @return bool|null|string
1720
 */
1721
function tpl_include_page($pageid, $print = true, $propagate = false, $useacl = true) {
1722
    if($propagate) {
1723
        $pageid = page_findnearest($pageid, $useacl);
1724
    } elseif($useacl && auth_quickaclcheck($pageid) == AUTH_NONE) {
1725
        return false;
1726
    }
1727
    if(!$pageid) return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $pageid of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1728
1729
    global $TOC;
1730
    $oldtoc = $TOC;
1731
    $html   = p_wiki_xhtml($pageid, '', false);
1732
    $TOC    = $oldtoc;
1733
1734
    if($print) echo $html;
1735
    return $html;
1736
}
1737
1738
/**
1739
 * Display the subscribe form
1740
 *
1741
 * @author Adrian Lang <[email protected]>
1742
 */
1743
function tpl_subscribe() {
1744
    global $INFO;
1745
    global $ID;
1746
    global $lang;
1747
    global $conf;
1748
    $stime_days = $conf['subscribe_time'] / 60 / 60 / 24;
1749
1750
    echo p_locale_xhtml('subscr_form');
1751
    echo '<h2>'.$lang['subscr_m_current_header'].'</h2>';
1752
    echo '<div class="level2">';
1753
    if($INFO['subscribed'] === false) {
1754
        echo '<p>'.$lang['subscr_m_not_subscribed'].'</p>';
1755
    } else {
1756
        echo '<ul>';
1757
        foreach($INFO['subscribed'] as $sub) {
1758
            echo '<li><div class="li">';
1759
            if($sub['target'] !== $ID) {
1760
                echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>';
1761
            } else {
1762
                echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>';
1763
            }
1764
            $sstl = sprintf($lang['subscr_style_'.$sub['style']], $stime_days);
1765
            if(!$sstl) $sstl = hsc($sub['style']);
1766
            echo ' ('.$sstl.') ';
1767
1768
            echo '<a href="'.wl(
1769
                $ID,
1770
                array(
1771
                     'do'        => 'subscribe',
1772
                     'sub_target'=> $sub['target'],
1773
                     'sub_style' => $sub['style'],
1774
                     'sub_action'=> 'unsubscribe',
1775
                     'sectok'    => getSecurityToken()
1776
                )
1777
            ).
1778
                '" class="unsubscribe">'.$lang['subscr_m_unsubscribe'].
1779
                '</a></div></li>';
1780
        }
1781
        echo '</ul>';
1782
    }
1783
    echo '</div>';
1784
1785
    // Add new subscription form
1786
    echo '<h2>'.$lang['subscr_m_new_header'].'</h2>';
1787
    echo '<div class="level2">';
1788
    $ns      = getNS($ID).':';
1789
    $targets = array(
1790
        $ID => '<code class="page">'.prettyprint_id($ID).'</code>',
1791
        $ns => '<code class="ns">'.prettyprint_id($ns).'</code>',
1792
    );
1793
    $styles  = array(
1794
        'every'  => $lang['subscr_style_every'],
1795
        'digest' => sprintf($lang['subscr_style_digest'], $stime_days),
1796
        'list'   => sprintf($lang['subscr_style_list'], $stime_days),
1797
    );
1798
1799
    $form = new Doku_Form(array('id' => 'subscribe__form'));
1800
    $form->startFieldset($lang['subscr_m_subscribe']);
1801
    $form->addRadioSet('sub_target', $targets);
1802
    $form->startFieldset($lang['subscr_m_receive']);
1803
    $form->addRadioSet('sub_style', $styles);
1804
    $form->addHidden('sub_action', 'subscribe');
1805
    $form->addHidden('do', 'subscribe');
1806
    $form->addHidden('id', $ID);
1807
    $form->endFieldset();
1808
    $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
1809
    html_form('SUBSCRIBE', $form);
1810
    echo '</div>';
1811
}
1812
1813
/**
1814
 * Tries to send already created content right to the browser
1815
 *
1816
 * Wraps around ob_flush() and flush()
1817
 *
1818
 * @author Andreas Gohr <[email protected]>
1819
 */
1820
function tpl_flush() {
1821
    ob_flush();
1822
    flush();
1823
}
1824
1825
/**
1826
 * Tries to find a ressource file in the given locations.
1827
 *
1828
 * If a given location starts with a colon it is assumed to be a media
1829
 * file, otherwise it is assumed to be relative to the current template
1830
 *
1831
 * @param  string[] $search       locations to look at
1832
 * @param  bool     $abs           if to use absolute URL
1833
 * @param  array   &$imginfo   filled with getimagesize()
1834
 * @return string
1835
 *
1836
 * @author Andreas  Gohr <[email protected]>
1837
 */
1838
function tpl_getMediaFile($search, $abs = false, &$imginfo = null) {
1839
    $img     = '';
1840
    $file    = '';
1841
    $ismedia = false;
1842
    // loop through candidates until a match was found:
1843
    foreach($search as $img) {
1844
        if(substr($img, 0, 1) == ':') {
1845
            $file    = mediaFN($img);
1846
            $ismedia = true;
1847
        } else {
1848
            $file    = tpl_incdir().$img;
1849
            $ismedia = false;
1850
        }
1851
1852
        if(file_exists($file)) break;
1853
    }
1854
1855
    // fetch image data if requested
1856
    if(!is_null($imginfo)) {
1857
        $imginfo = getimagesize($file);
1858
    }
1859
1860
    // build URL
1861
    if($ismedia) {
1862
        $url = ml($img, '', true, '', $abs);
1863
    } else {
1864
        $url = tpl_basedir().$img;
1865
        if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL));
1866
    }
1867
1868
    return $url;
1869
}
1870
1871
/**
1872
 * PHP include a file
1873
 *
1874
 * either from the conf directory if it exists, otherwise use
1875
 * file in the template's root directory.
1876
 *
1877
 * The function honours config cascade settings and looks for the given
1878
 * file next to the ´main´ config files, in the order protected, local,
1879
 * default.
1880
 *
1881
 * Note: no escaping or sanity checking is done here. Never pass user input
1882
 * to this function!
1883
 *
1884
 * @author Anika Henke <[email protected]>
1885
 * @author Andreas Gohr <[email protected]>
1886
 *
1887
 * @param string $file
1888
 */
1889
function tpl_includeFile($file) {
1890
    global $config_cascade;
1891
    foreach(array('protected', 'local', 'default') as $config_group) {
1892
        if(empty($config_cascade['main'][$config_group])) continue;
1893
        foreach($config_cascade['main'][$config_group] as $conf_file) {
1894
            $dir = dirname($conf_file);
1895
            if(file_exists("$dir/$file")) {
1896
                include("$dir/$file");
1897
                return;
1898
            }
1899
        }
1900
    }
1901
1902
    // still here? try the template dir
1903
    $file = tpl_incdir().$file;
1904
    if(file_exists($file)) {
1905
        include($file);
1906
    }
1907
}
1908
1909
/**
1910
 * Returns <link> tag for various icon types (favicon|mobile|generic)
1911
 *
1912
 * @author Anika Henke <[email protected]>
1913
 *
1914
 * @param  array $types - list of icon types to display (favicon|mobile|generic)
1915
 * @return string
1916
 */
1917
function tpl_favicon($types = array('favicon')) {
1918
1919
    $return = '';
1920
1921
    foreach($types as $type) {
1922
        switch($type) {
1923
            case 'favicon':
1924
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
1925
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1926
                break;
1927
            case 'mobile':
1928
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
1929
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1930
                break;
1931
            case 'generic':
1932
                // ideal world solution, which doesn't work in any browser yet
1933
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
1934
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
1935
                break;
1936
        }
1937
    }
1938
1939
    return $return;
1940
}
1941
1942
/**
1943
 * Prints full-screen media manager
1944
 *
1945
 * @author Kate Arzamastseva <[email protected]>
1946
 */
1947
function tpl_media() {
1948
    global $NS, $IMG, $JUMPTO, $REV, $lang, $fullscreen, $INPUT;
1949
    $fullscreen = true;
1950
    require_once DOKU_INC.'lib/exe/mediamanager.php';
1951
1952
    $rev   = '';
1953
    $image = cleanID($INPUT->str('image'));
1954
    if(isset($IMG)) $image = $IMG;
1955
    if(isset($JUMPTO)) $image = $JUMPTO;
1956
    if(isset($REV) && !$JUMPTO) $rev = $REV;
1957
1958
    echo '<div id="mediamanager__page">'.NL;
1959
    echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1960
    html_msgarea();
1961
1962
    echo '<div class="panel namespaces">'.NL;
1963
    echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1964
    echo '<div class="panelHeader">';
1965
    echo $lang['media_namespaces'];
1966
    echo '</div>'.NL;
1967
1968
    echo '<div class="panelContent" id="media__tree">'.NL;
1969
    media_nstree($NS);
1970
    echo '</div>'.NL;
1971
    echo '</div>'.NL;
1972
1973
    echo '<div class="panel filelist">'.NL;
1974
    tpl_mediaFileList();
1975
    echo '</div>'.NL;
1976
1977
    echo '<div class="panel file">'.NL;
1978
    echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1979
    tpl_mediaFileDetails($image, $rev);
1980
    echo '</div>'.NL;
1981
1982
    echo '</div>'.NL;
1983
}
1984
1985
/**
1986
 * Return useful layout classes
1987
 *
1988
 * @author Anika Henke <[email protected]>
1989
 *
1990
 * @return string
1991
 */
1992
function tpl_classes() {
1993
    global $ACT, $conf, $ID, $INFO;
1994
    /** @var Input $INPUT */
1995
    global $INPUT;
1996
1997
    $classes = array(
1998
        'dokuwiki',
1999
        'mode_'.$ACT,
2000
        'tpl_'.$conf['template'],
2001
        $INPUT->server->bool('REMOTE_USER') ? 'loggedIn' : '',
2002
        $INFO['exists'] ? '' : 'notFound',
2003
        ($ID == $conf['start']) ? 'home' : '',
2004
    );
2005
    return join(' ', $classes);
2006
}
2007
2008
/**
2009
 * Create event for tools menues
2010
 *
2011
 * @author Anika Henke <[email protected]>
2012
 * @param string $toolsname name of menu
2013
 * @param array $items
2014
 * @param string $view e.g. 'main', 'detail', ...
2015
 */
2016
function tpl_toolsevent($toolsname, $items, $view = 'main') {
2017
    $data = array(
2018
        'view' => $view,
2019
        'items' => $items
2020
    );
2021
2022
    $hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
2023
    $evt = new Doku_Event($hook, $data);
2024
    if($evt->advise_before()) {
2025
        foreach($evt->data['items'] as $k => $html) echo $html;
2026
    }
2027
    $evt->advise_after();
2028
}
2029
2030
//Setup VIM: ex: et ts=4 :
2031
2032