Completed
Push — master ( bf6f54...20dc95 )
by Andreas
03:16
created

template.php ➔ tpl_content_core()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 0
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
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
    $router = \dokuwiki\ActionRouter::getInstance();
97
    try {
98
        $router->getAction()->tplContent();
99
    } catch(\dokuwiki\Action\Exception\FatalException $e) {
100
        // there was no content for the action
101
        msg(hsc($e->getMessage()), -1);
102
        return false;
103
    }
104
    return true;
105
}
106
107
/**
108
 * Places the TOC where the function is called
109
 *
110
 * If you use this you most probably want to call tpl_content with
111
 * a false argument
112
 *
113
 * @author Andreas Gohr <[email protected]>
114
 *
115
 * @param bool $return Should the TOC be returned instead to be printed?
116
 * @return string
117
 */
118
function tpl_toc($return = false) {
119
    global $TOC;
120
    global $ACT;
121
    global $ID;
122
    global $REV;
123
    global $INFO;
124
    global $conf;
125
    global $INPUT;
126
    $toc = array();
127
128
    if(is_array($TOC)) {
129
        // if a TOC was prepared in global scope, always use it
130
        $toc = $TOC;
131
    } elseif(($ACT == 'show' || substr($ACT, 0, 6) == 'export') && !$REV && $INFO['exists']) {
132
        // get TOC from metadata, render if neccessary
133
        $meta = p_get_metadata($ID, '', METADATA_RENDER_USING_CACHE);
134
        if(isset($meta['internal']['toc'])) {
135
            $tocok = $meta['internal']['toc'];
136
        } else {
137
            $tocok = true;
138
        }
139
        $toc = isset($meta['description']['tableofcontents']) ? $meta['description']['tableofcontents'] : null;
140
        if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']) {
141
            $toc = array();
142
        }
143
    } elseif($ACT == 'admin') {
144
        // try to load admin plugin TOC
145
        /** @var $plugin DokuWiki_Admin_Plugin */
146
        if ($plugin = plugin_getRequestAdminPlugin()) {
147
            $toc = $plugin->getTOC();
148
            $TOC = $toc; // avoid later rebuild
149
        }
150
    }
151
152
    trigger_event('TPL_TOC_RENDER', $toc, null, false);
153
    $html = html_TOC($toc);
154
    if($return) return $html;
155
    echo $html;
156
    return '';
157
}
158
159
/**
160
 * Handle the admin page contents
161
 *
162
 * @author Andreas Gohr <[email protected]>
163
 *
164
 * @return bool
165
 */
166
function tpl_admin() {
167
    global $INFO;
168
    global $TOC;
169
    global $INPUT;
170
171
    $plugin = null;
172
    $class  = $INPUT->str('page');
173
    if(!empty($class)) {
174
        $pluginlist = plugin_list('admin');
175
176
        if(in_array($class, $pluginlist)) {
177
            // attempt to load the plugin
178
            /** @var $plugin DokuWiki_Admin_Plugin */
179
            $plugin = plugin_load('admin', $class);
180
        }
181
    }
182
183
    if($plugin !== null) {
184
        if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet
185
        if($INFO['prependTOC']) tpl_toc();
186
        $plugin->html();
187
    } else {
188
        $admin = new dokuwiki\Ui\Admin();
189
        $admin->show();
190
    }
191
    return true;
192
}
193
194
/**
195
 * Print the correct HTML meta headers
196
 *
197
 * This has to go into the head section of your template.
198
 *
199
 * @author Andreas Gohr <[email protected]>
200
 *
201
 * @triggers TPL_METAHEADER_OUTPUT
202
 * @param  bool $alt Should feeds and alternative format links be added?
203
 * @return bool
204
 */
205
function tpl_metaheaders($alt = true) {
206
    global $ID;
207
    global $REV;
208
    global $INFO;
209
    global $JSINFO;
210
    global $ACT;
211
    global $QUERY;
212
    global $lang;
213
    global $conf;
214
    global $updateVersion;
215
    /** @var Input $INPUT */
216
    global $INPUT;
217
218
    // prepare the head array
219
    $head = array();
220
221
    // prepare seed for js and css
222
    $tseed   = $updateVersion;
223
    $depends = getConfigFiles('main');
224
    $depends[] = DOKU_CONF."tpl/".$conf['template']."/style.ini";
225
    foreach($depends as $f) $tseed .= @filemtime($f);
226
    $tseed   = md5($tseed);
227
228
    // the usual stuff
229
    $head['meta'][] = array('name'=> 'generator', 'content'=> 'DokuWiki');
230
    if(actionOK('search')) {
231
        $head['link'][] = array(
232
            'rel' => 'search', 'type'=> 'application/opensearchdescription+xml',
233
            'href'=> DOKU_BASE.'lib/exe/opensearch.php', 'title'=> $conf['title']
234
        );
235
    }
236
237
    $head['link'][] = array('rel'=> 'start', 'href'=> DOKU_BASE);
238
    if(actionOK('index')) {
239
        $head['link'][] = array(
240
            'rel'  => 'contents', 'href'=> wl($ID, 'do=index', false, '&'),
241
            'title'=> $lang['btn_index']
242
        );
243
    }
244
245
    if($alt) {
246
        if(actionOK('rss')) {
247
            $head['link'][] = array(
248
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
249
                'title'=> $lang['btn_recent'], 'href'=> DOKU_BASE.'feed.php'
250
            );
251
            $head['link'][] = array(
252
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
253
                'title'=> $lang['currentns'],
254
                'href' => DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']
255
            );
256
        }
257
        if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']) {
258
            $head['link'][] = array(
259
                'rel'  => 'edit',
260
                'title'=> $lang['btn_edit'],
261
                'href' => wl($ID, 'do=edit', false, '&')
262
            );
263
        }
264
265
        if(actionOK('rss') && $ACT == 'search') {
266
            $head['link'][] = array(
267
                'rel'  => 'alternate', 'type'=> 'application/rss+xml',
268
                'title'=> $lang['searchresult'],
269
                'href' => DOKU_BASE.'feed.php?mode=search&q='.$QUERY
270
            );
271
        }
272
273
        if(actionOK('export_xhtml')) {
274
            $head['link'][] = array(
275
                'rel' => 'alternate', 'type'=> 'text/html', 'title'=> $lang['plainhtml'],
276
                'href'=> exportlink($ID, 'xhtml', '', false, '&')
277
            );
278
        }
279
280
        if(actionOK('export_raw')) {
281
            $head['link'][] = array(
282
                'rel' => 'alternate', 'type'=> 'text/plain', 'title'=> $lang['wikimarkup'],
283
                'href'=> exportlink($ID, 'raw', '', false, '&')
284
            );
285
        }
286
    }
287
288
    // setup robot tags apropriate for different modes
289
    if(($ACT == 'show' || $ACT == 'export_xhtml') && !$REV) {
290
        if($INFO['exists']) {
291
            //delay indexing:
292
            if(!isHiddenPage($ID) &&  (time() - $INFO['lastmod']) >= $conf['indexdelay']) {
293
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
294
            } else {
295
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
296
            }
297
            $canonicalUrl = wl($ID, '', true, '&');
298
            if ($ID == $conf['start']) {
299
                $canonicalUrl = DOKU_URL;
300
            }
301
            $head['link'][] = array('rel'=> 'canonical', 'href'=> $canonicalUrl);
302
        } else {
303
            $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,follow');
304
        }
305
    } elseif(defined('DOKU_MEDIADETAIL')) {
306
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
307
    } else {
308
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
309
    }
310
311
    // set metadata
312
    if($ACT == 'show' || $ACT == 'export_xhtml') {
313
        // keywords (explicit or implicit)
314
        if(!empty($INFO['meta']['subject'])) {
315
            $head['meta'][] = array('name'=> 'keywords', 'content'=> join(',', $INFO['meta']['subject']));
316
        } else {
317
            $head['meta'][] = array('name'=> 'keywords', 'content'=> str_replace(':', ',', $ID));
318
        }
319
    }
320
321
    // load stylesheets
322
    $head['link'][] = array(
323
        'rel' => 'stylesheet', 'type'=> 'text/css',
324
        'href'=> DOKU_BASE.'lib/exe/css.php?t='.rawurlencode($conf['template']).'&tseed='.$tseed
325
    );
326
327
    // make $INFO and other vars available to JavaScripts
328
    $json   = new JSON();
329
    $script = "var NS='".$INFO['namespace']."';";
330
    if($conf['useacl'] && $INPUT->server->str('REMOTE_USER')) {
331
        $script .= "var SIG='".toolbar_signature()."';";
332
    }
333
    $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
334
    $head['script'][] = array('type'=> 'text/javascript', '_data'=> $script);
335
336
    // load jquery
337
    $jquery = getCdnUrls();
338
    foreach($jquery as $src) {
339
        $head['script'][] = array(
340
            'type' => 'text/javascript', 'charset' => 'utf-8', '_data' => '', 'src' => $src
341
        );
342
    }
343
344
    // load our javascript dispatcher
345
    $head['script'][] = array(
346
        'type'=> 'text/javascript', 'charset'=> 'utf-8', '_data'=> '',
347
        'src' => DOKU_BASE.'lib/exe/js.php'.'?t='.rawurlencode($conf['template']).'&tseed='.$tseed
348
    );
349
350
    // trigger event here
351
    trigger_event('TPL_METAHEADER_OUTPUT', $head, '_tpl_metaheaders_action', true);
352
    return true;
353
}
354
355
/**
356
 * prints the array build by tpl_metaheaders
357
 *
358
 * $data is an array of different header tags. Each tag can have multiple
359
 * instances. Attributes are given as key value pairs. Values will be HTML
360
 * encoded automatically so they should be provided as is in the $data array.
361
 *
362
 * For tags having a body attribute specify the body data in the special
363
 * attribute '_data'. This field will NOT BE ESCAPED automatically.
364
 *
365
 * @author Andreas Gohr <[email protected]>
366
 *
367
 * @param array $data
368
 */
369
function _tpl_metaheaders_action($data) {
370
    foreach($data as $tag => $inst) {
371
        if($tag == 'script') {
372
            echo "<!--[if gte IE 9]><!-->\n"; // no scripts for old IE
373
        }
374
        foreach($inst as $attr) {
375
            if ( empty($attr) ) { continue; }
376
            echo '<', $tag, ' ', buildAttributes($attr);
377
            if(isset($attr['_data']) || $tag == 'script') {
378
                if($tag == 'script' && $attr['_data'])
379
                    $attr['_data'] = "/*<![CDATA[*/".
380
                        $attr['_data'].
381
                        "\n/*!]]>*/";
382
383
                echo '>', $attr['_data'], '</', $tag, '>';
384
            } else {
385
                echo '/>';
386
            }
387
            echo "\n";
388
        }
389
        if($tag == 'script') {
390
            echo "<!--<![endif]-->\n";
391
        }
392
    }
393
}
394
395
/**
396
 * Print a link
397
 *
398
 * Just builds a link.
399
 *
400
 * @author Andreas Gohr <[email protected]>
401
 *
402
 * @param string $url
403
 * @param string $name
404
 * @param string $more
405
 * @param bool $return if true return the link html, otherwise print
406
 * @return bool|string html of the link, or true if printed
407
 */
408
function tpl_link($url, $name, $more = '', $return = false) {
409
    $out = '<a href="'.$url.'" ';
410
    if($more) $out .= ' '.$more;
411
    $out .= ">$name</a>";
412
    if($return) return $out;
413
    print $out;
414
    return true;
415
}
416
417
/**
418
 * Prints a link to a WikiPage
419
 *
420
 * Wrapper around html_wikilink
421
 *
422
 * @author Andreas Gohr <[email protected]>
423
 *
424
 * @param string      $id   page id
425
 * @param string|null $name the name of the link
426
 * @return bool true
427
 */
428
function tpl_pagelink($id, $name = null) {
429
    print '<bdi>'.html_wikilink($id, $name).'</bdi>';
430
    return true;
431
}
432
433
/**
434
 * get the parent page
435
 *
436
 * Tries to find out which page is parent.
437
 * returns false if none is available
438
 *
439
 * @author Andreas Gohr <[email protected]>
440
 *
441
 * @param string $id page id
442
 * @return false|string
443
 */
444
function tpl_getparent($id) {
445
    $parent = getNS($id).':';
446
    resolve_pageid('', $parent, $exists);
447
    if($parent == $id) {
448
        $pos    = strrpos(getNS($id), ':');
449
        $parent = substr($parent, 0, $pos).':';
450
        resolve_pageid('', $parent, $exists);
451
        if($parent == $id) return false;
452
    }
453
    return $parent;
454
}
455
456
/**
457
 * Print one of the buttons
458
 *
459
 * @author Adrian Lang <[email protected]>
460
 * @see    tpl_get_action
461
 *
462
 * @param string $type
463
 * @param bool $return
464
 * @return bool|string html, or false if no data, true if printed
465
 */
466
function tpl_button($type, $return = false) {
467
    $data = tpl_get_action($type);
468
    if($data === false) {
469
        return false;
470
    } elseif(!is_array($data)) {
471
        $out = sprintf($data, 'button');
472
    } else {
473
        /**
474
         * @var string $accesskey
475
         * @var string $id
476
         * @var string $method
477
         * @var array  $params
478
         */
479
        extract($data);
480
        if($id === '#dokuwiki__top') {
481
            $out = html_topbtn();
482
        } else {
483
            $out = html_btn($type, $id, $accesskey, $params, $method);
484
        }
485
    }
486
    if($return) return $out;
487
    echo $out;
488
    return true;
489
}
490
491
/**
492
 * Like the action buttons but links
493
 *
494
 * @author Adrian Lang <[email protected]>
495
 * @see    tpl_get_action
496
 *
497
 * @param string $type    action command
498
 * @param string $pre     prefix of link
499
 * @param string $suf     suffix of link
500
 * @param string $inner   innerHML of link
501
 * @param bool   $return  if true it returns html, otherwise prints
502
 * @return bool|string html or false if no data, true if printed
503
 */
504
function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = false) {
505
    global $lang;
506
    $data = tpl_get_action($type);
507
    if($data === false) {
508
        return false;
509
    } elseif(!is_array($data)) {
510
        $out = sprintf($data, 'link');
511
    } else {
512
        /**
513
         * @var string $accesskey
514
         * @var string $id
515
         * @var string $method
516
         * @var bool   $nofollow
517
         * @var array  $params
518
         * @var string $replacement
519
         */
520
        extract($data);
521
        if(strpos($id, '#') === 0) {
522
            $linktarget = $id;
523
        } else {
524
            $linktarget = wl($id, $params);
525
        }
526
        $caption = $lang['btn_'.$type];
527
        if(strpos($caption, '%s')){
528
            $caption = sprintf($caption, $replacement);
529
        }
530
        $akey    = $addTitle = '';
531
        if($accesskey) {
532
            $akey     = 'accesskey="'.$accesskey.'" ';
533
            $addTitle = ' ['.strtoupper($accesskey).']';
534
        }
535
        $rel = $nofollow ? 'rel="nofollow" ' : '';
536
        $out = tpl_link(
537
            $linktarget, $pre.(($inner) ? $inner : $caption).$suf,
538
            'class="action '.$type.'" '.
539
                $akey.$rel.
540
                'title="'.hsc($caption).$addTitle.'"', true
541
        );
542
    }
543
    if($return) return $out;
544
    echo $out;
545
    return true;
546
}
547
548
/**
549
 * Check the actions and get data for buttons and links
550
 *
551
 * Available actions are
552
 *
553
 *  edit        - edit/create/show/draft
554
 *  history     - old revisions
555
 *  recent      - recent changes
556
 *  login       - login/logout - if ACL enabled
557
 *  profile     - user profile (if logged in)
558
 *  index       - The index
559
 *  admin       - admin page - if enough rights
560
 *  top         - back to top
561
 *  back        - back to parent - if available
562
 *  backlink    - links to the list of backlinks
563
 *  subscribe/subscription- subscribe/unsubscribe
564
 *
565
 * @author Andreas Gohr <[email protected]>
566
 * @author Matthias Grimm <[email protected]>
567
 * @author Adrian Lang <[email protected]>
568
 *
569
 * @param string $type
570
 * @return array|bool|string
571
 */
572
function tpl_get_action($type) {
573
    global $ID;
574
    global $INFO;
575
    global $REV;
576
    global $ACT;
577
    global $conf;
578
    /** @var Input $INPUT */
579
    global $INPUT;
580
581
    // check disabled actions and fix the badly named ones
582
    if($type == 'history') $type = 'revisions';
583
    if ($type == 'subscription') $type = 'subscribe';
584
    if(!actionOK($type)) return false;
585
586
    $accesskey   = null;
587
    $id          = $ID;
588
    $method      = 'get';
589
    $params      = array('do' => $type);
590
    $nofollow    = true;
591
    $replacement = '';
592
593
    $unknown = false;
594
    switch($type) {
595
        case 'edit':
596
            // most complicated type - we need to decide on current action
597
            if($ACT == 'show' || $ACT == 'search') {
598
                $method = 'post';
599
                if($INFO['writable']) {
600
                    $accesskey = 'e';
601
                    if(!empty($INFO['draft'])) {
602
                        $type         = 'draft';
603
                        $params['do'] = 'draft';
604
                    } else {
605
                        $params['rev'] = $REV;
606
                        if(!$INFO['exists']) {
607
                            $type = 'create';
608
                        }
609
                    }
610
                } else {
611
                    if(!actionOK('source')) return false; //pseudo action
612
                    $params['rev'] = $REV;
613
                    $type          = 'source';
614
                    $accesskey     = 'v';
615
                }
616
            } else {
617
                $params    = array('do' => '');
618
                $type      = 'show';
619
                $accesskey = 'v';
620
            }
621
            break;
622
        case 'revisions':
623
            $type      = 'revs';
624
            $accesskey = 'o';
625
            break;
626
        case 'recent':
627
            $accesskey = 'r';
628
            break;
629
        case 'index':
630
            $accesskey = 'x';
631
            // allow searchbots to get to the sitemap from the homepage (when dokuwiki isn't providing a sitemap.xml)
632
            if ($conf['start'] == $ID && !$conf['sitemap']) {
633
                $nofollow = false;
634
            }
635
            break;
636
        case 'top':
637
            $accesskey = 't';
638
            $params    = array('do' => '');
639
            $id        = '#dokuwiki__top';
640
            break;
641
        case 'back':
642
            $parent = tpl_getparent($ID);
643
            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...
644
                return false;
645
            }
646
            $id        = $parent;
647
            $params    = array('do' => '');
648
            $accesskey = 'b';
649
            break;
650
        case 'img_backto':
651
            $params = array();
652
            $accesskey = 'b';
653
            $replacement = $ID;
654
            break;
655
        case 'login':
656
            $params['sectok'] = getSecurityToken();
657
            if($INPUT->server->has('REMOTE_USER')) {
658
                if(!actionOK('logout')) {
659
                    return false;
660
                }
661
                $params['do'] = 'logout';
662
                $type         = 'logout';
663
            }
664
            break;
665
        case 'register':
666
            if($INPUT->server->str('REMOTE_USER')) {
667
                return false;
668
            }
669
            break;
670
        case 'resendpwd':
671
            if($INPUT->server->str('REMOTE_USER')) {
672
                return false;
673
            }
674
            break;
675
        case 'admin':
676
            if(!$INFO['ismanager']) {
677
                return false;
678
            }
679
            break;
680
        case 'revert':
681
            if(!$INFO['ismanager'] || !$REV || !$INFO['writable']) {
682
                return false;
683
            }
684
            $params['rev']    = $REV;
685
            $params['sectok'] = getSecurityToken();
686
            break;
687
        case 'subscribe':
688
            if(!$INPUT->server->str('REMOTE_USER')) {
689
                return false;
690
            }
691
            break;
692
        case 'backlink':
693
            break;
694
        case 'profile':
695
            if(!$INPUT->server->has('REMOTE_USER')) {
696
                return false;
697
            }
698
            break;
699
        case 'media':
700
            $params['ns'] = getNS($ID);
701
            break;
702
        case 'mediaManager':
703
            // View image in media manager
704
            global $IMG;
705
            $imgNS = getNS($IMG);
706
            $authNS = auth_quickaclcheck("$imgNS:*");
707
            if ($authNS < AUTH_UPLOAD) {
708
                return false;
709
            }
710
            $params = array(
711
                'ns' => $imgNS,
712
                'image' => $IMG,
713
                'do' => 'media'
714
            );
715
            //$type = 'media';
716
            break;
717
        default:
718
            //unknown type
719
            $unknown = true;
720
    }
721
722
    $data = compact('accesskey', 'type', 'id', 'method', 'params', 'nofollow', 'replacement');
723
724
    $evt = new Doku_Event('TPL_ACTION_GET', $data);
725
    if($evt->advise_before()) {
726
        //handle unknown types
727
        if($unknown) {
728
            $data = '[unknown %s type]';
729
        }
730
    }
731
    $evt->advise_after();
732
    unset($evt);
733
734
    return $data;
735
}
736
737
/**
738
 * Wrapper around tpl_button() and tpl_actionlink()
739
 *
740
 * @author Anika Henke <[email protected]>
741
 *
742
 * @param string        $type action command
743
 * @param bool          $link link or form button?
744
 * @param string|bool   $wrapper HTML element wrapper
745
 * @param bool          $return return or print
746
 * @param string        $pre prefix for links
747
 * @param string        $suf suffix for links
748
 * @param string        $inner inner HTML for links
749
 * @return bool|string
750
 */
751
function tpl_action($type, $link = false, $wrapper = false, $return = false, $pre = '', $suf = '', $inner = '') {
752
    $out = '';
753
    if($link) {
754
        $out .= tpl_actionlink($type, $pre, $suf, $inner, true);
755
    } else {
756
        $out .= tpl_button($type, true);
757
    }
758
    if($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
759
760
    if($return) return $out;
761
    print $out;
762
    return $out ? true : false;
763
}
764
765
/**
766
 * Print the search form
767
 *
768
 * If the first parameter is given a div with the ID 'qsearch_out' will
769
 * be added which instructs the ajax pagequicksearch to kick in and place
770
 * its output into this div. The second parameter controls the propritary
771
 * attribute autocomplete. If set to false this attribute will be set with an
772
 * value of "off" to instruct the browser to disable it's own built in
773
 * autocompletion feature (MSIE and Firefox)
774
 *
775
 * @author Andreas Gohr <[email protected]>
776
 *
777
 * @param bool $ajax
778
 * @param bool $autocomplete
779
 * @return bool
780
 */
781
function tpl_searchform($ajax = true, $autocomplete = true) {
782
    global $lang;
783
    global $ACT;
784
    global $QUERY;
785
786
    // don't print the search form if search action has been disabled
787
    if(!actionOK('search')) return false;
788
789
    print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get" role="search"><div class="no">';
790
    print '<input type="hidden" name="do" value="search" />';
791
    print '<input type="text" ';
792
    if($ACT == 'search') print 'value="'.hsc($QUERY).'" ';
793
    print 'placeholder="'.$lang['btn_search'].'" ';
794
    if(!$autocomplete) print 'autocomplete="off" ';
795
    print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
796
    print '<button type="submit" title="'.$lang['btn_search'].'">'.$lang['btn_search'].'</button>';
797
    if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
798
    print '</div></form>';
799
    return true;
800
}
801
802
/**
803
 * Print the breadcrumbs trace
804
 *
805
 * @author Andreas Gohr <[email protected]>
806
 *
807
 * @param string $sep Separator between entries
808
 * @return bool
809
 */
810
function tpl_breadcrumbs($sep = '•') {
811
    global $lang;
812
    global $conf;
813
814
    //check if enabled
815
    if(!$conf['breadcrumbs']) return false;
816
817
    $crumbs = breadcrumbs(); //setup crumb trace
818
819
    $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
820
821
    //render crumbs, highlight the last one
822
    print '<span class="bchead">'.$lang['breadcrumb'].'</span>';
823
    $last = count($crumbs);
824
    $i    = 0;
825
    foreach($crumbs as $id => $name) {
826
        $i++;
827
        echo $crumbs_sep;
828
        if($i == $last) print '<span class="curid">';
829
        print '<bdi>';
830
        tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"');
831
        print '</bdi>';
832
        if($i == $last) print '</span>';
833
    }
834
    return true;
835
}
836
837
/**
838
 * Hierarchical breadcrumbs
839
 *
840
 * This code was suggested as replacement for the usual breadcrumbs.
841
 * It only makes sense with a deep site structure.
842
 *
843
 * @author Andreas Gohr <[email protected]>
844
 * @author Nigel McNie <[email protected]>
845
 * @author Sean Coates <[email protected]>
846
 * @author <[email protected]>
847
 * @todo   May behave strangely in RTL languages
848
 *
849
 * @param string $sep Separator between entries
850
 * @return bool
851
 */
852
function tpl_youarehere($sep = ' » ') {
853
    global $conf;
854
    global $ID;
855
    global $lang;
856
857
    // check if enabled
858
    if(!$conf['youarehere']) return false;
859
860
    $parts = explode(':', $ID);
861
    $count = count($parts);
862
863
    echo '<span class="bchead">'.$lang['youarehere'].' </span>';
864
865
    // always print the startpage
866
    echo '<span class="home">';
867
    tpl_pagelink(':'.$conf['start']);
868
    echo '</span>';
869
870
    // print intermediate namespace links
871
    $part = '';
872
    for($i = 0; $i < $count - 1; $i++) {
873
        $part .= $parts[$i].':';
874
        $page = $part;
875
        if($page == $conf['start']) continue; // Skip startpage
876
877
        // output
878
        echo $sep;
879
        tpl_pagelink($page);
880
    }
881
882
    // print current page, skipping start page, skipping for namespace index
883
    resolve_pageid('', $page, $exists);
884
    if(isset($page) && $page == $part.$parts[$i]) return true;
885
    $page = $part.$parts[$i];
886
    if($page == $conf['start']) return true;
887
    echo $sep;
888
    tpl_pagelink($page);
889
    return true;
890
}
891
892
/**
893
 * Print info if the user is logged in
894
 * and show full name in that case
895
 *
896
 * Could be enhanced with a profile link in future?
897
 *
898
 * @author Andreas Gohr <[email protected]>
899
 *
900
 * @return bool
901
 */
902
function tpl_userinfo() {
903
    global $lang;
904
    /** @var Input $INPUT */
905
    global $INPUT;
906
907
    if($INPUT->server->str('REMOTE_USER')) {
908
        print $lang['loggedinas'].' '.userlink();
909
        return true;
910
    }
911
    return false;
912
}
913
914
/**
915
 * Print some info about the current page
916
 *
917
 * @author Andreas Gohr <[email protected]>
918
 *
919
 * @param bool $ret return content instead of printing it
920
 * @return bool|string
921
 */
922
function tpl_pageinfo($ret = false) {
923
    global $conf;
924
    global $lang;
925
    global $INFO;
926
    global $ID;
927
928
    // return if we are not allowed to view the page
929
    if(!auth_quickaclcheck($ID)) {
930
        return false;
931
    }
932
933
    // prepare date and path
934
    $fn = $INFO['filepath'];
935
    if(!$conf['fullpath']) {
936
        if($INFO['rev']) {
937
            $fn = str_replace($conf['olddir'].'/', '', $fn);
938
        } else {
939
            $fn = str_replace($conf['datadir'].'/', '', $fn);
940
        }
941
    }
942
    $fn   = utf8_decodeFN($fn);
943
    $date = dformat($INFO['lastmod']);
944
945
    // print it
946
    if($INFO['exists']) {
947
        $out = '';
948
        $out .= '<bdi>'.$fn.'</bdi>';
949
        $out .= ' · ';
950
        $out .= $lang['lastmod'];
951
        $out .= ' ';
952
        $out .= $date;
953
        if($INFO['editor']) {
954
            $out .= ' '.$lang['by'].' ';
955
            $out .= '<bdi>'.editorinfo($INFO['editor']).'</bdi>';
956
        } else {
957
            $out .= ' ('.$lang['external_edit'].')';
958
        }
959
        if($INFO['locked']) {
960
            $out .= ' · ';
961
            $out .= $lang['lockedby'];
962
            $out .= ' ';
963
            $out .= '<bdi>'.editorinfo($INFO['locked']).'</bdi>';
964
        }
965
        if($ret) {
966
            return $out;
967
        } else {
968
            echo $out;
969
            return true;
970
        }
971
    }
972
    return false;
973
}
974
975
/**
976
 * Prints or returns the name of the given page (current one if none given).
977
 *
978
 * If useheading is enabled this will use the first headline else
979
 * the given ID is used.
980
 *
981
 * @author Andreas Gohr <[email protected]>
982
 *
983
 * @param string $id page id
984
 * @param bool   $ret return content instead of printing
985
 * @return bool|string
986
 */
987
function tpl_pagetitle($id = null, $ret = false) {
988
    global $ACT, $INPUT, $conf, $lang;
989
990
    if(is_null($id)) {
991
        global $ID;
992
        $id = $ID;
993
    }
994
995
    $name = $id;
996
    if(useHeading('navigation')) {
997
        $first_heading = p_get_first_heading($id);
998
        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...
999
    }
1000
1001
    // default page title is the page name, modify with the current action
1002
    switch ($ACT) {
1003
        // admin functions
1004
        case 'admin' :
1005
            $page_title = $lang['btn_admin'];
1006
            // try to get the plugin name
1007
            /** @var $plugin DokuWiki_Admin_Plugin */
1008
            if ($plugin = plugin_getRequestAdminPlugin()){
1009
                $plugin_title = $plugin->getMenuText($conf['lang']);
1010
                $page_title = $plugin_title ? $plugin_title : $plugin->getPluginName();
1011
            }
1012
            break;
1013
1014
        // user functions
1015
        case 'login' :
1016
        case 'profile' :
1017
        case 'register' :
1018
        case 'resendpwd' :
1019
            $page_title = $lang['btn_'.$ACT];
1020
            break;
1021
1022
         // wiki functions
1023
        case 'search' :
1024
        case 'index' :
1025
            $page_title = $lang['btn_'.$ACT];
1026
            break;
1027
1028
        // page functions
1029
        case 'edit' :
1030
            $page_title = "✎ ".$name;
1031
            break;
1032
1033
        case 'revisions' :
1034
            $page_title = $name . ' - ' . $lang['btn_revs'];
1035
            break;
1036
1037
        case 'backlink' :
1038
        case 'recent' :
1039
        case 'subscribe' :
1040
            $page_title = $name . ' - ' . $lang['btn_'.$ACT];
1041
            break;
1042
1043
        default : // SHOW and anything else not included
1044
            $page_title = $name;
1045
    }
1046
1047
    if($ret) {
1048
        return hsc($page_title);
1049
    } else {
1050
        print hsc($page_title);
1051
        return true;
1052
    }
1053
}
1054
1055
/**
1056
 * Returns the requested EXIF/IPTC tag from the current image
1057
 *
1058
 * If $tags is an array all given tags are tried until a
1059
 * value is found. If no value is found $alt is returned.
1060
 *
1061
 * Which texts are known is defined in the functions _exifTagNames
1062
 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
1063
 * to the names of the latter one)
1064
 *
1065
 * Only allowed in: detail.php
1066
 *
1067
 * @author Andreas Gohr <[email protected]>
1068
 *
1069
 * @param array|string $tags tag or array of tags to try
1070
 * @param string       $alt  alternative output if no data was found
1071
 * @param null|string  $src  the image src, uses global $SRC if not given
1072
 * @return string
1073
 */
1074
function tpl_img_getTag($tags, $alt = '', $src = null) {
1075
    // Init Exif Reader
1076
    global $SRC;
1077
1078
    if(is_null($src)) $src = $SRC;
1079
1080
    static $meta = null;
1081
    if(is_null($meta)) $meta = new JpegMeta($src);
1082
    if($meta === false) return $alt;
1083
    $info = cleanText($meta->getField($tags));
1084
    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...
1085
    return $info;
1086
}
1087
1088
/**
1089
 * Returns a description list of the metatags of the current image
1090
 *
1091
 * @return string html of description list
1092
 */
1093
function tpl_img_meta() {
1094
    global $lang;
1095
1096
    $tags = tpl_get_img_meta();
1097
1098
    echo '<dl>';
1099
    foreach($tags as $tag) {
1100
        $label = $lang[$tag['langkey']];
1101
        if(!$label) $label = $tag['langkey'] . ':';
1102
1103
        echo '<dt>'.$label.'</dt><dd>';
1104
        if ($tag['type'] == 'date') {
1105
            echo dformat($tag['value']);
1106
        } else {
1107
            echo hsc($tag['value']);
1108
        }
1109
        echo '</dd>';
1110
    }
1111
    echo '</dl>';
1112
}
1113
1114
/**
1115
 * Returns metadata as configured in mediameta config file, ready for creating html
1116
 *
1117
 * @return array with arrays containing the entries:
1118
 *   - string langkey  key to lookup in the $lang var, if not found printed as is
1119
 *   - string type     type of value
1120
 *   - string value    tag value (unescaped)
1121
 */
1122
function tpl_get_img_meta() {
1123
1124
    $config_files = getConfigFiles('mediameta');
1125
    foreach ($config_files as $config_file) {
1126
        if(file_exists($config_file)) {
1127
            include($config_file);
1128
        }
1129
    }
1130
    /** @var array $fields the included array with metadata */
1131
1132
    $tags = array();
1133
    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...
1134
        $t = array();
1135
        if (!empty($tag[0])) {
1136
            $t = array($tag[0]);
1137
        }
1138
        if(is_array($tag[3])) {
1139
            $t = array_merge($t,$tag[3]);
1140
        }
1141
        $value = tpl_img_getTag($t);
1142
        if ($value) {
1143
            $tags[] = array('langkey' => $tag[1], 'type' => $tag[2], 'value' => $value);
1144
        }
1145
    }
1146
    return $tags;
1147
}
1148
1149
/**
1150
 * Prints the image with a link to the full sized version
1151
 *
1152
 * Only allowed in: detail.php
1153
 *
1154
 * @triggers TPL_IMG_DISPLAY
1155
 * @param $maxwidth  int - maximal width of the image
1156
 * @param $maxheight int - maximal height of the image
1157
 * @param $link bool     - link to the orginal size?
1158
 * @param $params array  - additional image attributes
1159
 * @return bool Result of TPL_IMG_DISPLAY
1160
 */
1161
function tpl_img($maxwidth = 0, $maxheight = 0, $link = true, $params = null) {
1162
    global $IMG;
1163
    /** @var Input $INPUT */
1164
    global $INPUT;
1165
    global $REV;
1166
    $w = (int) tpl_img_getTag('File.Width');
1167
    $h = (int) tpl_img_getTag('File.Height');
1168
1169
    //resize to given max values
1170
    $ratio = 1;
1171
    if($w >= $h) {
1172
        if($maxwidth && $w >= $maxwidth) {
1173
            $ratio = $maxwidth / $w;
1174
        } elseif($maxheight && $h > $maxheight) {
1175
            $ratio = $maxheight / $h;
1176
        }
1177
    } else {
1178
        if($maxheight && $h >= $maxheight) {
1179
            $ratio = $maxheight / $h;
1180
        } elseif($maxwidth && $w > $maxwidth) {
1181
            $ratio = $maxwidth / $w;
1182
        }
1183
    }
1184
    if($ratio) {
1185
        $w = floor($ratio * $w);
1186
        $h = floor($ratio * $h);
1187
    }
1188
1189
    //prepare URLs
1190
    $url = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV), true, '&');
1191
    $src = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV, 'w'=> $w, 'h'=> $h), true, '&');
1192
1193
    //prepare attributes
1194
    $alt = tpl_img_getTag('Simple.Title');
1195
    if(is_null($params)) {
1196
        $p = array();
1197
    } else {
1198
        $p = $params;
1199
    }
1200
    if($w) $p['width'] = $w;
1201
    if($h) $p['height'] = $h;
1202
    $p['class'] = 'img_detail';
1203
    if($alt) {
1204
        $p['alt']   = $alt;
1205
        $p['title'] = $alt;
1206
    } else {
1207
        $p['alt'] = '';
1208
    }
1209
    $p['src'] = $src;
1210
1211
    $data = array('url'=> ($link ? $url : null), 'params'=> $p);
1212
    return trigger_event('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
1213
}
1214
1215
/**
1216
 * Default action for TPL_IMG_DISPLAY
1217
 *
1218
 * @param array $data
1219
 * @return bool
1220
 */
1221
function _tpl_img_action($data) {
1222
    global $lang;
1223
    $p = buildAttributes($data['params']);
1224
1225
    if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">';
1226
    print '<img '.$p.'/>';
1227
    if($data['url']) print '</a>';
1228
    return true;
1229
}
1230
1231
/**
1232
 * This function inserts a small gif which in reality is the indexer function.
1233
 *
1234
 * Should be called somewhere at the very end of the main.php
1235
 * template
1236
 *
1237
 * @return bool
1238
 */
1239
function tpl_indexerWebBug() {
1240
    global $ID;
1241
1242
    $p           = array();
1243
    $p['src']    = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID).
1244
        '&'.time();
1245
    $p['width']  = 2; //no more 1x1 px image because we live in times of ad blockers...
1246
    $p['height'] = 1;
1247
    $p['alt']    = '';
1248
    $att         = buildAttributes($p);
1249
    print "<img $att />";
1250
    return true;
1251
}
1252
1253
/**
1254
 * tpl_getConf($id)
1255
 *
1256
 * use this function to access template configuration variables
1257
 *
1258
 * @param string $id      name of the value to access
1259
 * @param mixed  $notset  what to return if the setting is not available
1260
 * @return mixed
1261
 */
1262
function tpl_getConf($id, $notset=false) {
1263
    global $conf;
1264
    static $tpl_configloaded = false;
1265
1266
    $tpl = $conf['template'];
1267
1268
    if(!$tpl_configloaded) {
1269
        $tconf = tpl_loadConfig();
1270
        if($tconf !== false) {
1271
            foreach($tconf as $key => $value) {
1272
                if(isset($conf['tpl'][$tpl][$key])) continue;
1273
                $conf['tpl'][$tpl][$key] = $value;
1274
            }
1275
            $tpl_configloaded = true;
1276
        }
1277
    }
1278
1279
    if(isset($conf['tpl'][$tpl][$id])){
1280
        return $conf['tpl'][$tpl][$id];
1281
    }
1282
1283
    return $notset;
1284
}
1285
1286
/**
1287
 * tpl_loadConfig()
1288
 *
1289
 * reads all template configuration variables
1290
 * this function is automatically called by tpl_getConf()
1291
 *
1292
 * @return array
1293
 */
1294
function tpl_loadConfig() {
1295
1296
    $file = tpl_incdir().'/conf/default.php';
1297
    $conf = array();
1298
1299
    if(!file_exists($file)) return false;
1300
1301
    // load default config file
1302
    include($file);
1303
1304
    return $conf;
1305
}
1306
1307
// language methods
1308
/**
1309
 * tpl_getLang($id)
1310
 *
1311
 * use this function to access template language variables
1312
 *
1313
 * @param string $id key of language string
1314
 * @return string
1315
 */
1316
function tpl_getLang($id) {
1317
    static $lang = array();
1318
1319
    if(count($lang) === 0) {
1320
        global $conf, $config_cascade; // definitely don't invoke "global $lang"
1321
1322
        $path = tpl_incdir() . 'lang/';
1323
1324
        $lang = array();
1325
1326
        // don't include once
1327
        @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...
1328
        foreach($config_cascade['lang']['template'] as $config_file) {
1329
            if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
1330
                include($config_file . $conf['template'] . '/en/lang.php');
1331
            }
1332
        }
1333
1334
        if($conf['lang'] != 'en') {
1335
            @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...
1336
            foreach($config_cascade['lang']['template'] as $config_file) {
1337
                if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
1338
                    include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
1339
                }
1340
            }
1341
        }
1342
    }
1343
    return $lang[$id];
1344
}
1345
1346
/**
1347
 * Retrieve a language dependent file and pass to xhtml renderer for display
1348
 * template equivalent of p_locale_xhtml()
1349
 *
1350
 * @param   string $id id of language dependent wiki page
1351
 * @return  string     parsed contents of the wiki page in xhtml format
1352
 */
1353
function tpl_locale_xhtml($id) {
1354
    return p_cached_output(tpl_localeFN($id));
1355
}
1356
1357
/**
1358
 * Prepends appropriate path for a language dependent filename
1359
 *
1360
 * @param string $id id of localized text
1361
 * @return string wiki text
1362
 */
1363
function tpl_localeFN($id) {
1364
    $path = tpl_incdir().'lang/';
1365
    global $conf;
1366
    $file = DOKU_CONF.'template_lang/'.$conf['template'].'/'.$conf['lang'].'/'.$id.'.txt';
1367
    if (!file_exists($file)){
1368
        $file = $path.$conf['lang'].'/'.$id.'.txt';
1369
        if(!file_exists($file)){
1370
            //fall back to english
1371
            $file = $path.'en/'.$id.'.txt';
1372
        }
1373
    }
1374
    return $file;
1375
}
1376
1377
/**
1378
 * prints the "main content" in the mediamanager popup
1379
 *
1380
 * Depending on the user's actions this may be a list of
1381
 * files in a namespace, the meta editing dialog or
1382
 * a message of referencing pages
1383
 *
1384
 * Only allowed in mediamanager.php
1385
 *
1386
 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1387
 * @param bool $fromajax - set true when calling this function via ajax
1388
 * @param string $sort
1389
 *
1390
 * @author Andreas Gohr <[email protected]>
1391
 */
1392
function tpl_mediaContent($fromajax = false, $sort='natural') {
1393
    global $IMG;
1394
    global $AUTH;
1395
    global $INUSE;
1396
    global $NS;
1397
    global $JUMPTO;
1398
    /** @var Input $INPUT */
1399
    global $INPUT;
1400
1401
    $do = $INPUT->extract('do')->str('do');
1402
    if(in_array($do, array('save', 'cancel'))) $do = '';
1403
1404
    if(!$do) {
1405
        if($INPUT->bool('edit')) {
1406
            $do = 'metaform';
1407
        } elseif(is_array($INUSE)) {
1408
            $do = 'filesinuse';
1409
        } else {
1410
            $do = 'filelist';
1411
        }
1412
    }
1413
1414
    // output the content pane, wrapped in an event.
1415
    if(!$fromajax) ptln('<div id="media__content">');
1416
    $data = array('do' => $do);
1417
    $evt  = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1418
    if($evt->advise_before()) {
1419
        $do = $data['do'];
1420
        if($do == 'filesinuse') {
1421
            media_filesinuse($INUSE, $IMG);
1422
        } elseif($do == 'filelist') {
1423
            media_filelist($NS, $AUTH, $JUMPTO,false,$sort);
1424
        } elseif($do == 'searchlist') {
1425
            media_searchlist($INPUT->str('q'), $NS, $AUTH);
1426
        } else {
1427
            msg('Unknown action '.hsc($do), -1);
1428
        }
1429
    }
1430
    $evt->advise_after();
1431
    unset($evt);
1432
    if(!$fromajax) ptln('</div>');
1433
1434
}
1435
1436
/**
1437
 * Prints the central column in full-screen media manager
1438
 * Depending on the opened tab this may be a list of
1439
 * files in a namespace, upload form or search form
1440
 *
1441
 * @author Kate Arzamastseva <[email protected]>
1442
 */
1443
function tpl_mediaFileList() {
1444
    global $AUTH;
1445
    global $NS;
1446
    global $JUMPTO;
1447
    global $lang;
1448
    /** @var Input $INPUT */
1449
    global $INPUT;
1450
1451
    $opened_tab = $INPUT->str('tab_files');
1452
    if(!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files';
1453
    if($INPUT->str('mediado') == 'update') $opened_tab = 'upload';
1454
1455
    echo '<h2 class="a11y">'.$lang['mediaselect'].'</h2>'.NL;
1456
1457
    media_tabs_files($opened_tab);
1458
1459
    echo '<div class="panelHeader">'.NL;
1460
    echo '<h3>';
1461
    $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']';
1462
    printf($lang['media_'.$opened_tab], '<strong>'.hsc($tabTitle).'</strong>');
1463
    echo '</h3>'.NL;
1464
    if($opened_tab === 'search' || $opened_tab === 'files') {
1465
        media_tab_files_options();
1466
    }
1467
    echo '</div>'.NL;
1468
1469
    echo '<div class="panelContent">'.NL;
1470
    if($opened_tab == 'files') {
1471
        media_tab_files($NS, $AUTH, $JUMPTO);
1472
    } elseif($opened_tab == 'upload') {
1473
        media_tab_upload($NS, $AUTH, $JUMPTO);
1474
    } elseif($opened_tab == 'search') {
1475
        media_tab_search($NS, $AUTH);
1476
    }
1477
    echo '</div>'.NL;
1478
}
1479
1480
/**
1481
 * Prints the third column in full-screen media manager
1482
 * Depending on the opened tab this may be details of the
1483
 * selected file, the meta editing dialog or
1484
 * list of file revisions
1485
 *
1486
 * @author Kate Arzamastseva <[email protected]>
1487
 *
1488
 * @param string $image
1489
 * @param boolean $rev
1490
 */
1491
function tpl_mediaFileDetails($image, $rev) {
1492
    global $conf, $DEL, $lang;
1493
    /** @var Input $INPUT */
1494
    global $INPUT;
1495
1496
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')) && $conf['mediarevisions']);
1497
    if(!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return;
1498
    if($rev && !file_exists(mediaFN($image, $rev))) $rev = false;
0 ignored issues
show
Documentation introduced by
$rev is of type boolean, but the function expects a string|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1499
    $ns = getNS($image);
1500
    $do = $INPUT->str('mediado');
1501
1502
    $opened_tab = $INPUT->str('tab_details');
1503
1504
    $tab_array = array('view');
1505
    list(, $mime) = mimetype($image);
1506
    if($mime == 'image/jpeg') {
1507
        $tab_array[] = 'edit';
1508
    }
1509
    if($conf['mediarevisions']) {
1510
        $tab_array[] = 'history';
1511
    }
1512
1513
    if(!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view';
1514
    if($INPUT->bool('edit')) $opened_tab = 'edit';
1515
    if($do == 'restore') $opened_tab = 'view';
1516
1517
    media_tabs_details($image, $opened_tab);
1518
1519
    echo '<div class="panelHeader"><h3>';
1520
    list($ext) = mimetype($image, false);
1521
    $class    = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1522
    $class    = 'select mediafile mf_'.$class;
1523
    $tabTitle = '<strong><a href="'.ml($image).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>';
1524
    if($opened_tab === 'view' && $rev) {
1525
        printf($lang['media_viewold'], $tabTitle, dformat($rev));
0 ignored issues
show
Documentation introduced by
$rev is of type boolean, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1526
    } else {
1527
        printf($lang['media_'.$opened_tab], $tabTitle);
1528
    }
1529
1530
    echo '</h3></div>'.NL;
1531
1532
    echo '<div class="panelContent">'.NL;
1533
1534
    if($opened_tab == 'view') {
1535
        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 1499 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...
Documentation introduced by
$rev is of type boolean, but the function expects a string|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1536
1537
    } elseif($opened_tab == 'edit' && !$removed) {
1538
        media_tab_edit($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1499 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...
1539
1540
    } elseif($opened_tab == 'history' && $conf['mediarevisions']) {
1541
        media_tab_history($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1499 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...
1542
    }
1543
1544
    echo '</div>'.NL;
1545
}
1546
1547
/**
1548
 * prints the namespace tree in the mediamanager popup
1549
 *
1550
 * Only allowed in mediamanager.php
1551
 *
1552
 * @author Andreas Gohr <[email protected]>
1553
 */
1554
function tpl_mediaTree() {
1555
    global $NS;
1556
    ptln('<div id="media__tree">');
1557
    media_nstree($NS);
1558
    ptln('</div>');
1559
}
1560
1561
/**
1562
 * Print a dropdown menu with all DokuWiki actions
1563
 *
1564
 * Note: this will not use any pretty URLs
1565
 *
1566
 * @author Andreas Gohr <[email protected]>
1567
 *
1568
 * @param string $empty empty option label
1569
 * @param string $button submit button label
1570
 */
1571
function tpl_actiondropdown($empty = '&nbsp;', $button = '&gt;') {
1572
    global $ID;
1573
    global $REV;
1574
    global $lang;
1575
    /** @var Input $INPUT */
1576
    global $INPUT;
1577
1578
    $action_structure = array(
1579
        'page_tools' => array('edit', 'revert', 'revisions', 'backlink', 'subscribe'),
1580
        'site_tools' => array('recent', 'media', 'index'),
1581
        'user_tools' => array('login', 'register', 'profile', 'admin'),
1582
    );
1583
1584
    echo '<form action="'.script().'" method="get" accept-charset="utf-8">';
1585
    echo '<div class="no">';
1586
    echo '<input type="hidden" name="id" value="'.$ID.'" />';
1587
    if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />';
1588
    if ($INPUT->server->str('REMOTE_USER')) {
1589
        echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
1590
    }
1591
1592
    echo '<select name="do" class="edit quickselect" title="'.$lang['tools'].'">';
1593
    echo '<option value="">'.$empty.'</option>';
1594
1595
    foreach($action_structure as $tools => $actions) {
1596
        echo '<optgroup label="'.$lang[$tools].'">';
1597
        foreach($actions as $action) {
1598
            $act = tpl_get_action($action);
1599
            if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1600
        }
1601
        echo '</optgroup>';
1602
    }
1603
1604
    echo '</select>';
1605
    echo '<button type="submit">'.$button.'</button>';
1606
    echo '</div>';
1607
    echo '</form>';
1608
}
1609
1610
/**
1611
 * Print a informational line about the used license
1612
 *
1613
 * @author Andreas Gohr <[email protected]>
1614
 * @param  string $img     print image? (|button|badge)
1615
 * @param  bool   $imgonly skip the textual description?
1616
 * @param  bool   $return  when true don't print, but return HTML
1617
 * @param  bool   $wrap    wrap in div with class="license"?
1618
 * @return string
1619
 */
1620
function tpl_license($img = 'badge', $imgonly = false, $return = false, $wrap = true) {
1621
    global $license;
1622
    global $conf;
1623
    global $lang;
1624
    if(!$conf['license']) return '';
1625
    if(!is_array($license[$conf['license']])) return '';
1626
    $lic    = $license[$conf['license']];
1627
    $target = ($conf['target']['extern']) ? ' target="'.$conf['target']['extern'].'"' : '';
1628
1629
    $out = '';
1630
    if($wrap) $out .= '<div class="license">';
1631
    if($img) {
1632
        $src = license_img($img);
1633
        if($src) {
1634
            $out .= '<a href="'.$lic['url'].'" rel="license"'.$target;
1635
            $out .= '><img src="'.DOKU_BASE.$src.'" alt="'.$lic['name'].'" /></a>';
1636
            if(!$imgonly) $out .= ' ';
1637
        }
1638
    }
1639
    if(!$imgonly) {
1640
        $out .= $lang['license'].' ';
1641
        $out .= '<bdi><a href="'.$lic['url'].'" rel="license" class="urlextern"'.$target;
1642
        $out .= '>'.$lic['name'].'</a></bdi>';
1643
    }
1644
    if($wrap) $out .= '</div>';
1645
1646
    if($return) return $out;
1647
    echo $out;
1648
    return '';
1649
}
1650
1651
/**
1652
 * Includes the rendered HTML of a given page
1653
 *
1654
 * This function is useful to populate sidebars or similar features in a
1655
 * template
1656
 *
1657
 * @param string $pageid The page name you want to include
1658
 * @param bool $print Should the content be printed or returned only
1659
 * @param bool $propagate Search higher namespaces, too?
1660
 * @param bool $useacl Include the page only if the ACLs check out?
1661
 * @return bool|null|string
1662
 */
1663
function tpl_include_page($pageid, $print = true, $propagate = false, $useacl = true) {
1664
    if($propagate) {
1665
        $pageid = page_findnearest($pageid, $useacl);
1666
    } elseif($useacl && auth_quickaclcheck($pageid) == AUTH_NONE) {
1667
        return false;
1668
    }
1669
    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...
1670
1671
    global $TOC;
1672
    $oldtoc = $TOC;
1673
    $html   = p_wiki_xhtml($pageid, '', false);
1674
    $TOC    = $oldtoc;
1675
1676
    if($print) echo $html;
1677
    return $html;
1678
}
1679
1680
/**
1681
 * Display the subscribe form
1682
 *
1683
 * @author Adrian Lang <[email protected]>
1684
 */
1685
function tpl_subscribe() {
1686
    global $INFO;
1687
    global $ID;
1688
    global $lang;
1689
    global $conf;
1690
    $stime_days = $conf['subscribe_time'] / 60 / 60 / 24;
1691
1692
    echo p_locale_xhtml('subscr_form');
1693
    echo '<h2>'.$lang['subscr_m_current_header'].'</h2>';
1694
    echo '<div class="level2">';
1695
    if($INFO['subscribed'] === false) {
1696
        echo '<p>'.$lang['subscr_m_not_subscribed'].'</p>';
1697
    } else {
1698
        echo '<ul>';
1699
        foreach($INFO['subscribed'] as $sub) {
1700
            echo '<li><div class="li">';
1701
            if($sub['target'] !== $ID) {
1702
                echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>';
1703
            } else {
1704
                echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>';
1705
            }
1706
            $sstl = sprintf($lang['subscr_style_'.$sub['style']], $stime_days);
1707
            if(!$sstl) $sstl = hsc($sub['style']);
1708
            echo ' ('.$sstl.') ';
1709
1710
            echo '<a href="'.wl(
1711
                $ID,
1712
                array(
1713
                     'do'        => 'subscribe',
1714
                     'sub_target'=> $sub['target'],
1715
                     'sub_style' => $sub['style'],
1716
                     'sub_action'=> 'unsubscribe',
1717
                     'sectok'    => getSecurityToken()
1718
                )
1719
            ).
1720
                '" class="unsubscribe">'.$lang['subscr_m_unsubscribe'].
1721
                '</a></div></li>';
1722
        }
1723
        echo '</ul>';
1724
    }
1725
    echo '</div>';
1726
1727
    // Add new subscription form
1728
    echo '<h2>'.$lang['subscr_m_new_header'].'</h2>';
1729
    echo '<div class="level2">';
1730
    $ns      = getNS($ID).':';
1731
    $targets = array(
1732
        $ID => '<code class="page">'.prettyprint_id($ID).'</code>',
1733
        $ns => '<code class="ns">'.prettyprint_id($ns).'</code>',
1734
    );
1735
    $styles  = array(
1736
        'every'  => $lang['subscr_style_every'],
1737
        'digest' => sprintf($lang['subscr_style_digest'], $stime_days),
1738
        'list'   => sprintf($lang['subscr_style_list'], $stime_days),
1739
    );
1740
1741
    $form = new Doku_Form(array('id' => 'subscribe__form'));
1742
    $form->startFieldset($lang['subscr_m_subscribe']);
1743
    $form->addRadioSet('sub_target', $targets);
1744
    $form->startFieldset($lang['subscr_m_receive']);
1745
    $form->addRadioSet('sub_style', $styles);
1746
    $form->addHidden('sub_action', 'subscribe');
1747
    $form->addHidden('do', 'subscribe');
1748
    $form->addHidden('id', $ID);
1749
    $form->endFieldset();
1750
    $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
1751
    html_form('SUBSCRIBE', $form);
1752
    echo '</div>';
1753
}
1754
1755
/**
1756
 * Tries to send already created content right to the browser
1757
 *
1758
 * Wraps around ob_flush() and flush()
1759
 *
1760
 * @author Andreas Gohr <[email protected]>
1761
 */
1762
function tpl_flush() {
1763
    ob_flush();
1764
    flush();
1765
}
1766
1767
/**
1768
 * Tries to find a ressource file in the given locations.
1769
 *
1770
 * If a given location starts with a colon it is assumed to be a media
1771
 * file, otherwise it is assumed to be relative to the current template
1772
 *
1773
 * @param  string[] $search       locations to look at
1774
 * @param  bool     $abs           if to use absolute URL
1775
 * @param  array   &$imginfo   filled with getimagesize()
1776
 * @return string
1777
 *
1778
 * @author Andreas  Gohr <[email protected]>
1779
 */
1780
function tpl_getMediaFile($search, $abs = false, &$imginfo = null) {
1781
    $img     = '';
1782
    $file    = '';
1783
    $ismedia = false;
1784
    // loop through candidates until a match was found:
1785
    foreach($search as $img) {
1786
        if(substr($img, 0, 1) == ':') {
1787
            $file    = mediaFN($img);
1788
            $ismedia = true;
1789
        } else {
1790
            $file    = tpl_incdir().$img;
1791
            $ismedia = false;
1792
        }
1793
1794
        if(file_exists($file)) break;
1795
    }
1796
1797
    // fetch image data if requested
1798
    if(!is_null($imginfo)) {
1799
        $imginfo = getimagesize($file);
1800
    }
1801
1802
    // build URL
1803
    if($ismedia) {
1804
        $url = ml($img, '', true, '', $abs);
1805
    } else {
1806
        $url = tpl_basedir().$img;
1807
        if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL));
1808
    }
1809
1810
    return $url;
1811
}
1812
1813
/**
1814
 * PHP include a file
1815
 *
1816
 * either from the conf directory if it exists, otherwise use
1817
 * file in the template's root directory.
1818
 *
1819
 * The function honours config cascade settings and looks for the given
1820
 * file next to the ´main´ config files, in the order protected, local,
1821
 * default.
1822
 *
1823
 * Note: no escaping or sanity checking is done here. Never pass user input
1824
 * to this function!
1825
 *
1826
 * @author Anika Henke <[email protected]>
1827
 * @author Andreas Gohr <[email protected]>
1828
 *
1829
 * @param string $file
1830
 */
1831
function tpl_includeFile($file) {
1832
    global $config_cascade;
1833
    foreach(array('protected', 'local', 'default') as $config_group) {
1834
        if(empty($config_cascade['main'][$config_group])) continue;
1835
        foreach($config_cascade['main'][$config_group] as $conf_file) {
1836
            $dir = dirname($conf_file);
1837
            if(file_exists("$dir/$file")) {
1838
                include("$dir/$file");
1839
                return;
1840
            }
1841
        }
1842
    }
1843
1844
    // still here? try the template dir
1845
    $file = tpl_incdir().$file;
1846
    if(file_exists($file)) {
1847
        include($file);
1848
    }
1849
}
1850
1851
/**
1852
 * Returns <link> tag for various icon types (favicon|mobile|generic)
1853
 *
1854
 * @author Anika Henke <[email protected]>
1855
 *
1856
 * @param  array $types - list of icon types to display (favicon|mobile|generic)
1857
 * @return string
1858
 */
1859
function tpl_favicon($types = array('favicon')) {
1860
1861
    $return = '';
1862
1863
    foreach($types as $type) {
1864
        switch($type) {
1865
            case 'favicon':
1866
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
1867
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1868
                break;
1869
            case 'mobile':
1870
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
1871
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1872
                break;
1873
            case 'generic':
1874
                // ideal world solution, which doesn't work in any browser yet
1875
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
1876
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
1877
                break;
1878
        }
1879
    }
1880
1881
    return $return;
1882
}
1883
1884
/**
1885
 * Prints full-screen media manager
1886
 *
1887
 * @author Kate Arzamastseva <[email protected]>
1888
 */
1889
function tpl_media() {
1890
    global $NS, $IMG, $JUMPTO, $REV, $lang, $fullscreen, $INPUT;
1891
    $fullscreen = true;
1892
    require_once DOKU_INC.'lib/exe/mediamanager.php';
1893
1894
    $rev   = '';
1895
    $image = cleanID($INPUT->str('image'));
1896
    if(isset($IMG)) $image = $IMG;
1897
    if(isset($JUMPTO)) $image = $JUMPTO;
1898
    if(isset($REV) && !$JUMPTO) $rev = $REV;
1899
1900
    echo '<div id="mediamanager__page">'.NL;
1901
    echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1902
    html_msgarea();
1903
1904
    echo '<div class="panel namespaces">'.NL;
1905
    echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1906
    echo '<div class="panelHeader">';
1907
    echo $lang['media_namespaces'];
1908
    echo '</div>'.NL;
1909
1910
    echo '<div class="panelContent" id="media__tree">'.NL;
1911
    media_nstree($NS);
1912
    echo '</div>'.NL;
1913
    echo '</div>'.NL;
1914
1915
    echo '<div class="panel filelist">'.NL;
1916
    tpl_mediaFileList();
1917
    echo '</div>'.NL;
1918
1919
    echo '<div class="panel file">'.NL;
1920
    echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1921
    tpl_mediaFileDetails($image, $rev);
1922
    echo '</div>'.NL;
1923
1924
    echo '</div>'.NL;
1925
}
1926
1927
/**
1928
 * Return useful layout classes
1929
 *
1930
 * @author Anika Henke <[email protected]>
1931
 *
1932
 * @return string
1933
 */
1934
function tpl_classes() {
1935
    global $ACT, $conf, $ID, $INFO;
1936
    /** @var Input $INPUT */
1937
    global $INPUT;
1938
1939
    $classes = array(
1940
        'dokuwiki',
1941
        'mode_'.$ACT,
1942
        'tpl_'.$conf['template'],
1943
        $INPUT->server->bool('REMOTE_USER') ? 'loggedIn' : '',
1944
        $INFO['exists'] ? '' : 'notFound',
1945
        ($ID == $conf['start']) ? 'home' : '',
1946
    );
1947
    return join(' ', $classes);
1948
}
1949
1950
/**
1951
 * Create event for tools menues
1952
 *
1953
 * @author Anika Henke <[email protected]>
1954
 * @param string $toolsname name of menu
1955
 * @param array $items
1956
 * @param string $view e.g. 'main', 'detail', ...
1957
 */
1958
function tpl_toolsevent($toolsname, $items, $view = 'main') {
1959
    $data = array(
1960
        'view' => $view,
1961
        'items' => $items
1962
    );
1963
1964
    $hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
1965
    $evt = new Doku_Event($hook, $data);
1966
    if($evt->advise_before()) {
1967
        foreach($evt->data['items'] as $k => $html) echo $html;
1968
    }
1969
    $evt->advise_after();
1970
}
1971
1972
//Setup VIM: ex: et ts=4 :
1973
1974