Failed Conditions
Push — betterJSINFO ( 034db8...b3054f )
by Michael
16:38 queued 03:58
created

inc/template.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

Code
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((time() - $INFO['lastmod']) >= $conf['indexdelay'] && !isHiddenPage($ID) ) {
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
    _tpl_ensureJSINFO();
334
    $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
335
    $head['script'][] = array('type'=> 'text/javascript', '_data'=> $script);
336
337
    // load jquery
338
    $jquery = getCdnUrls();
339
    foreach($jquery as $src) {
340
        $head['script'][] = array(
341
            'type' => 'text/javascript', 'charset' => 'utf-8', '_data' => '', 'src' => $src
342
        );
343
    }
344
345
    // load our javascript dispatcher
346
    $head['script'][] = array(
347
        'type'=> 'text/javascript', 'charset'=> 'utf-8', '_data'=> '',
348
        'src' => DOKU_BASE.'lib/exe/js.php'.'?t='.rawurlencode($conf['template']).'&tseed='.$tseed
349
    );
350
351
    // trigger event here
352
    trigger_event('TPL_METAHEADER_OUTPUT', $head, '_tpl_metaheaders_action', true);
353
    return true;
354
}
355
356
function _tpl_ensureJSINFO() {
357
    global $JSINFO, $ID, $INFO;
358
359
    if (!is_array($JSINFO)) {
360
        $JSINFO = [];
361
    }
362
    //export minimal info to JS, plugins can add more
363
    $JSINFO['id']                    = $ID;
364
    $JSINFO['namespace']             = (string) $INFO['namespace'];
365
    $JSINFO['ACT']                   = act_clean($ACT);
0 ignored issues
show
The variable $ACT 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...
366
    $JSINFO['useHeadingNavigation']  = (int) useHeading('navigation');
367
    $JSINFO['useHeadingContent']     = (int) useHeading('content');
368
}
369
370
/**
371
 * prints the array build by tpl_metaheaders
372
 *
373
 * $data is an array of different header tags. Each tag can have multiple
374
 * instances. Attributes are given as key value pairs. Values will be HTML
375
 * encoded automatically so they should be provided as is in the $data array.
376
 *
377
 * For tags having a body attribute specify the body data in the special
378
 * attribute '_data'. This field will NOT BE ESCAPED automatically.
379
 *
380
 * @author Andreas Gohr <[email protected]>
381
 *
382
 * @param array $data
383
 */
384
function _tpl_metaheaders_action($data) {
385
    foreach($data as $tag => $inst) {
386
        if($tag == 'script') {
387
            echo "<!--[if gte IE 9]><!-->\n"; // no scripts for old IE
388
        }
389
        foreach($inst as $attr) {
390
            if ( empty($attr) ) { continue; }
391
            echo '<', $tag, ' ', buildAttributes($attr);
392
            if(isset($attr['_data']) || $tag == 'script') {
393
                if($tag == 'script' && $attr['_data'])
394
                    $attr['_data'] = "/*<![CDATA[*/".
395
                        $attr['_data'].
396
                        "\n/*!]]>*/";
397
398
                echo '>', $attr['_data'], '</', $tag, '>';
399
            } else {
400
                echo '/>';
401
            }
402
            echo "\n";
403
        }
404
        if($tag == 'script') {
405
            echo "<!--<![endif]-->\n";
406
        }
407
    }
408
}
409
410
/**
411
 * Print a link
412
 *
413
 * Just builds a link.
414
 *
415
 * @author Andreas Gohr <[email protected]>
416
 *
417
 * @param string $url
418
 * @param string $name
419
 * @param string $more
420
 * @param bool $return if true return the link html, otherwise print
421
 * @return bool|string html of the link, or true if printed
422
 */
423
function tpl_link($url, $name, $more = '', $return = false) {
424
    $out = '<a href="'.$url.'" ';
425
    if($more) $out .= ' '.$more;
426
    $out .= ">$name</a>";
427
    if($return) return $out;
428
    print $out;
429
    return true;
430
}
431
432
/**
433
 * Prints a link to a WikiPage
434
 *
435
 * Wrapper around html_wikilink
436
 *
437
 * @author Andreas Gohr <[email protected]>
438
 *
439
 * @param string      $id   page id
440
 * @param string|null $name the name of the link
441
 * @return bool true
442
 */
443
function tpl_pagelink($id, $name = null) {
444
    print '<bdi>'.html_wikilink($id, $name).'</bdi>';
445
    return true;
446
}
447
448
/**
449
 * get the parent page
450
 *
451
 * Tries to find out which page is parent.
452
 * returns false if none is available
453
 *
454
 * @author Andreas Gohr <[email protected]>
455
 *
456
 * @param string $id page id
457
 * @return false|string
458
 */
459
function tpl_getparent($id) {
460
    $parent = getNS($id).':';
461
    resolve_pageid('', $parent, $exists);
462
    if($parent == $id) {
463
        $pos    = strrpos(getNS($id), ':');
464
        $parent = substr($parent, 0, $pos).':';
465
        resolve_pageid('', $parent, $exists);
466
        if($parent == $id) return false;
467
    }
468
    return $parent;
469
}
470
471
/**
472
 * Print one of the buttons
473
 *
474
 * @author Adrian Lang <[email protected]>
475
 * @see    tpl_get_action
476
 *
477
 * @param string $type
478
 * @param bool $return
479
 * @return bool|string html, or false if no data, true if printed
480
 * @deprecated 2017-09-01 see devel:menus
481
 */
482
function tpl_button($type, $return = false) {
483
    dbg_deprecated('see devel:menus');
484
    $data = tpl_get_action($type);
485
    if($data === false) {
486
        return false;
487
    } elseif(!is_array($data)) {
488
        $out = sprintf($data, 'button');
489
    } else {
490
        /**
491
         * @var string $accesskey
492
         * @var string $id
493
         * @var string $method
494
         * @var array  $params
495
         */
496
        extract($data);
497
        if($id === '#dokuwiki__top') {
498
            $out = html_topbtn();
499
        } else {
500
            $out = html_btn($type, $id, $accesskey, $params, $method);
501
        }
502
    }
503
    if($return) return $out;
504
    echo $out;
505
    return true;
506
}
507
508
/**
509
 * Like the action buttons but links
510
 *
511
 * @author Adrian Lang <[email protected]>
512
 * @see    tpl_get_action
513
 *
514
 * @param string $type    action command
515
 * @param string $pre     prefix of link
516
 * @param string $suf     suffix of link
517
 * @param string $inner   innerHML of link
518
 * @param bool   $return  if true it returns html, otherwise prints
519
 * @return bool|string html or false if no data, true if printed
520
 * @deprecated 2017-09-01 see devel:menus
521
 */
522
function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = false) {
523
    dbg_deprecated('see devel:menus');
524
    global $lang;
525
    $data = tpl_get_action($type);
526
    if($data === false) {
527
        return false;
528
    } elseif(!is_array($data)) {
529
        $out = sprintf($data, 'link');
530
    } else {
531
        /**
532
         * @var string $accesskey
533
         * @var string $id
534
         * @var string $method
535
         * @var bool   $nofollow
536
         * @var array  $params
537
         * @var string $replacement
538
         */
539
        extract($data);
540
        if(strpos($id, '#') === 0) {
541
            $linktarget = $id;
542
        } else {
543
            $linktarget = wl($id, $params);
544
        }
545
        $caption = $lang['btn_'.$type];
546
        if(strpos($caption, '%s')){
547
            $caption = sprintf($caption, $replacement);
548
        }
549
        $akey    = $addTitle = '';
550
        if($accesskey) {
551
            $akey     = 'accesskey="'.$accesskey.'" ';
552
            $addTitle = ' ['.strtoupper($accesskey).']';
553
        }
554
        $rel = $nofollow ? 'rel="nofollow" ' : '';
555
        $out = tpl_link(
556
            $linktarget, $pre.(($inner) ? $inner : $caption).$suf,
557
            'class="action '.$type.'" '.
558
                $akey.$rel.
559
                'title="'.hsc($caption).$addTitle.'"', true
560
        );
561
    }
562
    if($return) return $out;
563
    echo $out;
564
    return true;
565
}
566
567
/**
568
 * Check the actions and get data for buttons and links
569
 *
570
 * @author Andreas Gohr <[email protected]>
571
 * @author Matthias Grimm <[email protected]>
572
 * @author Adrian Lang <[email protected]>
573
 *
574
 * @param string $type
575
 * @return array|bool|string
576
 * @deprecated 2017-09-01 see devel:menus
577
 */
578
function tpl_get_action($type) {
579
    dbg_deprecated('see devel:menus');
580
    if($type == 'history') $type = 'revisions';
581
    if($type == 'subscription') $type = 'subscribe';
582
    if($type == 'img_backto') $type = 'imgBackto';
583
584
    $class = '\\dokuwiki\\Menu\\Item\\' . ucfirst($type);
585
    if(class_exists($class)) {
586
        try {
587
            /** @var \dokuwiki\Menu\Item\AbstractItem $item */
588
            $item = new $class;
589
            $data = $item->getLegacyData();
590
            $unknown = false;
591
        } catch(\RuntimeException $ignored) {
592
            return false;
593
        }
594
    } else {
595
        global $ID;
596
        $data = array(
597
            'accesskey' => null,
598
            'type' => $type,
599
            'id' => $ID,
600
            'method' => 'get',
601
            'params' => array('do' => $type),
602
            'nofollow' => true,
603
            'replacement' => '',
604
        );
605
        $unknown = true;
606
    }
607
608
    $evt = new Doku_Event('TPL_ACTION_GET', $data);
609
    if($evt->advise_before()) {
610
        //handle unknown types
611
        if($unknown) {
612
            $data = '[unknown %s type]';
613
        }
614
    }
615
    $evt->advise_after();
616
    unset($evt);
617
618
    return $data;
619
}
620
621
/**
622
 * Wrapper around tpl_button() and tpl_actionlink()
623
 *
624
 * @author Anika Henke <[email protected]>
625
 *
626
 * @param string        $type action command
627
 * @param bool          $link link or form button?
628
 * @param string|bool   $wrapper HTML element wrapper
629
 * @param bool          $return return or print
630
 * @param string        $pre prefix for links
631
 * @param string        $suf suffix for links
632
 * @param string        $inner inner HTML for links
633
 * @return bool|string
634
 * @deprecated 2017-09-01 see devel:menus
635
 */
636
function tpl_action($type, $link = false, $wrapper = false, $return = false, $pre = '', $suf = '', $inner = '') {
637
    dbg_deprecated('see devel:menus');
638
    $out = '';
639
    if($link) {
640
        $out .= tpl_actionlink($type, $pre, $suf, $inner, true);
641
    } else {
642
        $out .= tpl_button($type, true);
643
    }
644
    if($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
645
646
    if($return) return $out;
647
    print $out;
648
    return $out ? true : false;
649
}
650
651
/**
652
 * Print the search form
653
 *
654
 * If the first parameter is given a div with the ID 'qsearch_out' will
655
 * be added which instructs the ajax pagequicksearch to kick in and place
656
 * its output into this div. The second parameter controls the propritary
657
 * attribute autocomplete. If set to false this attribute will be set with an
658
 * value of "off" to instruct the browser to disable it's own built in
659
 * autocompletion feature (MSIE and Firefox)
660
 *
661
 * @author Andreas Gohr <[email protected]>
662
 *
663
 * @param bool $ajax
664
 * @param bool $autocomplete
665
 * @return bool
666
 */
667
function tpl_searchform($ajax = true, $autocomplete = true) {
668
    global $lang;
669
    global $ACT;
670
    global $QUERY;
671
672
    // don't print the search form if search action has been disabled
673
    if(!actionOK('search')) return false;
674
675
    print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get" role="search"><div class="no">';
676
    print '<input type="hidden" name="do" value="search" />';
677
    print '<input type="text" ';
678
    if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" ';
679
    print 'placeholder="'.$lang['btn_search'].'" ';
680
    if(!$autocomplete) print 'autocomplete="off" ';
681
    print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
682
    print '<button type="submit" title="'.$lang['btn_search'].'">'.$lang['btn_search'].'</button>';
683
    if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
684
    print '</div></form>';
685
    return true;
686
}
687
688
/**
689
 * Print the breadcrumbs trace
690
 *
691
 * @author Andreas Gohr <[email protected]>
692
 *
693
 * @param string $sep Separator between entries
694
 * @return bool
695
 */
696
function tpl_breadcrumbs($sep = '•') {
697
    global $lang;
698
    global $conf;
699
700
    //check if enabled
701
    if(!$conf['breadcrumbs']) return false;
702
703
    $crumbs = breadcrumbs(); //setup crumb trace
704
705
    $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
706
707
    //render crumbs, highlight the last one
708
    print '<span class="bchead">'.$lang['breadcrumb'].'</span>';
709
    $last = count($crumbs);
710
    $i    = 0;
711
    foreach($crumbs as $id => $name) {
712
        $i++;
713
        echo $crumbs_sep;
714
        if($i == $last) print '<span class="curid">';
715
        print '<bdi>';
716
        tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"');
717
        print '</bdi>';
718
        if($i == $last) print '</span>';
719
    }
720
    return true;
721
}
722
723
/**
724
 * Hierarchical breadcrumbs
725
 *
726
 * This code was suggested as replacement for the usual breadcrumbs.
727
 * It only makes sense with a deep site structure.
728
 *
729
 * @author Andreas Gohr <[email protected]>
730
 * @author Nigel McNie <[email protected]>
731
 * @author Sean Coates <[email protected]>
732
 * @author <[email protected]>
733
 * @todo   May behave strangely in RTL languages
734
 *
735
 * @param string $sep Separator between entries
736
 * @return bool
737
 */
738
function tpl_youarehere($sep = ' » ') {
739
    global $conf;
740
    global $ID;
741
    global $lang;
742
743
    // check if enabled
744
    if(!$conf['youarehere']) return false;
745
746
    $parts = explode(':', $ID);
747
    $count = count($parts);
748
749
    echo '<span class="bchead">'.$lang['youarehere'].' </span>';
750
751
    // always print the startpage
752
    echo '<span class="home">';
753
    tpl_pagelink(':'.$conf['start']);
754
    echo '</span>';
755
756
    // print intermediate namespace links
757
    $part = '';
758
    for($i = 0; $i < $count - 1; $i++) {
759
        $part .= $parts[$i].':';
760
        $page = $part;
761
        if($page == $conf['start']) continue; // Skip startpage
762
763
        // output
764
        echo $sep;
765
        tpl_pagelink($page);
766
    }
767
768
    // print current page, skipping start page, skipping for namespace index
769
    resolve_pageid('', $page, $exists);
770
    if(isset($page) && $page == $part.$parts[$i]) return true;
771
    $page = $part.$parts[$i];
772
    if($page == $conf['start']) return true;
773
    echo $sep;
774
    tpl_pagelink($page);
775
    return true;
776
}
777
778
/**
779
 * Print info if the user is logged in
780
 * and show full name in that case
781
 *
782
 * Could be enhanced with a profile link in future?
783
 *
784
 * @author Andreas Gohr <[email protected]>
785
 *
786
 * @return bool
787
 */
788
function tpl_userinfo() {
789
    global $lang;
790
    /** @var Input $INPUT */
791
    global $INPUT;
792
793
    if($INPUT->server->str('REMOTE_USER')) {
794
        print $lang['loggedinas'].' '.userlink();
795
        return true;
796
    }
797
    return false;
798
}
799
800
/**
801
 * Print some info about the current page
802
 *
803
 * @author Andreas Gohr <[email protected]>
804
 *
805
 * @param bool $ret return content instead of printing it
806
 * @return bool|string
807
 */
808
function tpl_pageinfo($ret = false) {
809
    global $conf;
810
    global $lang;
811
    global $INFO;
812
    global $ID;
813
814
    // return if we are not allowed to view the page
815
    if(!auth_quickaclcheck($ID)) {
816
        return false;
817
    }
818
819
    // prepare date and path
820
    $fn = $INFO['filepath'];
821
    if(!$conf['fullpath']) {
822
        if($INFO['rev']) {
823
            $fn = str_replace($conf['olddir'].'/', '', $fn);
824
        } else {
825
            $fn = str_replace($conf['datadir'].'/', '', $fn);
826
        }
827
    }
828
    $fn   = utf8_decodeFN($fn);
829
    $date = dformat($INFO['lastmod']);
830
831
    // print it
832
    if($INFO['exists']) {
833
        $out = '';
834
        $out .= '<bdi>'.$fn.'</bdi>';
835
        $out .= ' · ';
836
        $out .= $lang['lastmod'];
837
        $out .= ' ';
838
        $out .= $date;
839
        if($INFO['editor']) {
840
            $out .= ' '.$lang['by'].' ';
841
            $out .= '<bdi>'.editorinfo($INFO['editor']).'</bdi>';
842
        } else {
843
            $out .= ' ('.$lang['external_edit'].')';
844
        }
845
        if($INFO['locked']) {
846
            $out .= ' · ';
847
            $out .= $lang['lockedby'];
848
            $out .= ' ';
849
            $out .= '<bdi>'.editorinfo($INFO['locked']).'</bdi>';
850
        }
851
        if($ret) {
852
            return $out;
853
        } else {
854
            echo $out;
855
            return true;
856
        }
857
    }
858
    return false;
859
}
860
861
/**
862
 * Prints or returns the name of the given page (current one if none given).
863
 *
864
 * If useheading is enabled this will use the first headline else
865
 * the given ID is used.
866
 *
867
 * @author Andreas Gohr <[email protected]>
868
 *
869
 * @param string $id page id
870
 * @param bool   $ret return content instead of printing
871
 * @return bool|string
872
 */
873
function tpl_pagetitle($id = null, $ret = false) {
874
    global $ACT, $INPUT, $conf, $lang;
875
876
    if(is_null($id)) {
877
        global $ID;
878
        $id = $ID;
879
    }
880
881
    $name = $id;
882
    if(useHeading('navigation')) {
883
        $first_heading = p_get_first_heading($id);
884
        if($first_heading) $name = $first_heading;
885
    }
886
887
    // default page title is the page name, modify with the current action
888
    switch ($ACT) {
889
        // admin functions
890
        case 'admin' :
891
            $page_title = $lang['btn_admin'];
892
            // try to get the plugin name
893
            /** @var $plugin DokuWiki_Admin_Plugin */
894
            if ($plugin = plugin_getRequestAdminPlugin()){
895
                $plugin_title = $plugin->getMenuText($conf['lang']);
896
                $page_title = $plugin_title ? $plugin_title : $plugin->getPluginName();
897
            }
898
            break;
899
900
        // user functions
901
        case 'login' :
902
        case 'profile' :
903
        case 'register' :
904
        case 'resendpwd' :
905
            $page_title = $lang['btn_'.$ACT];
906
            break;
907
908
         // wiki functions
909
        case 'search' :
910
        case 'index' :
911
            $page_title = $lang['btn_'.$ACT];
912
            break;
913
914
        // page functions
915
        case 'edit' :
916
            $page_title = "✎ ".$name;
917
            break;
918
919
        case 'revisions' :
920
            $page_title = $name . ' - ' . $lang['btn_revs'];
921
            break;
922
923
        case 'backlink' :
924
        case 'recent' :
925
        case 'subscribe' :
926
            $page_title = $name . ' - ' . $lang['btn_'.$ACT];
927
            break;
928
929
        default : // SHOW and anything else not included
930
            $page_title = $name;
931
    }
932
933
    if($ret) {
934
        return hsc($page_title);
935
    } else {
936
        print hsc($page_title);
937
        return true;
938
    }
939
}
940
941
/**
942
 * Returns the requested EXIF/IPTC tag from the current image
943
 *
944
 * If $tags is an array all given tags are tried until a
945
 * value is found. If no value is found $alt is returned.
946
 *
947
 * Which texts are known is defined in the functions _exifTagNames
948
 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
949
 * to the names of the latter one)
950
 *
951
 * Only allowed in: detail.php
952
 *
953
 * @author Andreas Gohr <[email protected]>
954
 *
955
 * @param array|string $tags tag or array of tags to try
956
 * @param string       $alt  alternative output if no data was found
957
 * @param null|string  $src  the image src, uses global $SRC if not given
958
 * @return string
959
 */
960
function tpl_img_getTag($tags, $alt = '', $src = null) {
961
    // Init Exif Reader
962
    global $SRC;
963
964
    if(is_null($src)) $src = $SRC;
965
966
    static $meta = null;
967
    if(is_null($meta)) $meta = new JpegMeta($src);
968
    if($meta === false) return $alt;
969
    $info = cleanText($meta->getField($tags));
970
    if($info == false) return $alt;
971
    return $info;
972
}
973
974
/**
975
 * Returns a description list of the metatags of the current image
976
 *
977
 * @return string html of description list
978
 */
979
function tpl_img_meta() {
980
    global $lang;
981
982
    $tags = tpl_get_img_meta();
983
984
    echo '<dl>';
985
    foreach($tags as $tag) {
986
        $label = $lang[$tag['langkey']];
987
        if(!$label) $label = $tag['langkey'] . ':';
988
989
        echo '<dt>'.$label.'</dt><dd>';
990
        if ($tag['type'] == 'date') {
991
            echo dformat($tag['value']);
992
        } else {
993
            echo hsc($tag['value']);
994
        }
995
        echo '</dd>';
996
    }
997
    echo '</dl>';
998
}
999
1000
/**
1001
 * Returns metadata as configured in mediameta config file, ready for creating html
1002
 *
1003
 * @return array with arrays containing the entries:
1004
 *   - string langkey  key to lookup in the $lang var, if not found printed as is
1005
 *   - string type     type of value
1006
 *   - string value    tag value (unescaped)
1007
 */
1008
function tpl_get_img_meta() {
1009
1010
    $config_files = getConfigFiles('mediameta');
1011
    foreach ($config_files as $config_file) {
1012
        if(file_exists($config_file)) {
1013
            include($config_file);
1014
        }
1015
    }
1016
    /** @var array $fields the included array with metadata */
1017
1018
    $tags = array();
1019
    foreach($fields as $tag){
1020
        $t = array();
1021
        if (!empty($tag[0])) {
1022
            $t = array($tag[0]);
1023
        }
1024
        if(is_array($tag[3])) {
1025
            $t = array_merge($t,$tag[3]);
1026
        }
1027
        $value = tpl_img_getTag($t);
1028
        if ($value) {
1029
            $tags[] = array('langkey' => $tag[1], 'type' => $tag[2], 'value' => $value);
1030
        }
1031
    }
1032
    return $tags;
1033
}
1034
1035
/**
1036
 * Prints the image with a link to the full sized version
1037
 *
1038
 * Only allowed in: detail.php
1039
 *
1040
 * @triggers TPL_IMG_DISPLAY
1041
 * @param $maxwidth  int - maximal width of the image
1042
 * @param $maxheight int - maximal height of the image
1043
 * @param $link bool     - link to the orginal size?
1044
 * @param $params array  - additional image attributes
1045
 * @return bool Result of TPL_IMG_DISPLAY
1046
 */
1047
function tpl_img($maxwidth = 0, $maxheight = 0, $link = true, $params = null) {
1048
    global $IMG;
1049
    /** @var Input $INPUT */
1050
    global $INPUT;
1051
    global $REV;
1052
    $w = (int) tpl_img_getTag('File.Width');
1053
    $h = (int) tpl_img_getTag('File.Height');
1054
1055
    //resize to given max values
1056
    $ratio = 1;
1057
    if($w >= $h) {
1058
        if($maxwidth && $w >= $maxwidth) {
1059
            $ratio = $maxwidth / $w;
1060
        } elseif($maxheight && $h > $maxheight) {
1061
            $ratio = $maxheight / $h;
1062
        }
1063
    } else {
1064
        if($maxheight && $h >= $maxheight) {
1065
            $ratio = $maxheight / $h;
1066
        } elseif($maxwidth && $w > $maxwidth) {
1067
            $ratio = $maxwidth / $w;
1068
        }
1069
    }
1070
    if($ratio) {
1071
        $w = floor($ratio * $w);
1072
        $h = floor($ratio * $h);
1073
    }
1074
1075
    //prepare URLs
1076
    $url = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV), true, '&');
1077
    $src = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV, 'w'=> $w, 'h'=> $h), true, '&');
1078
1079
    //prepare attributes
1080
    $alt = tpl_img_getTag('Simple.Title');
1081
    if(is_null($params)) {
1082
        $p = array();
1083
    } else {
1084
        $p = $params;
1085
    }
1086
    if($w) $p['width'] = $w;
1087
    if($h) $p['height'] = $h;
1088
    $p['class'] = 'img_detail';
1089
    if($alt) {
1090
        $p['alt']   = $alt;
1091
        $p['title'] = $alt;
1092
    } else {
1093
        $p['alt'] = '';
1094
    }
1095
    $p['src'] = $src;
1096
1097
    $data = array('url'=> ($link ? $url : null), 'params'=> $p);
1098
    return trigger_event('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
1099
}
1100
1101
/**
1102
 * Default action for TPL_IMG_DISPLAY
1103
 *
1104
 * @param array $data
1105
 * @return bool
1106
 */
1107
function _tpl_img_action($data) {
1108
    global $lang;
1109
    $p = buildAttributes($data['params']);
1110
1111
    if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">';
1112
    print '<img '.$p.'/>';
1113
    if($data['url']) print '</a>';
1114
    return true;
1115
}
1116
1117
/**
1118
 * This function inserts a small gif which in reality is the indexer function.
1119
 *
1120
 * Should be called somewhere at the very end of the main.php
1121
 * template
1122
 *
1123
 * @return bool
1124
 */
1125
function tpl_indexerWebBug() {
1126
    global $ID;
1127
1128
    $p           = array();
1129
    $p['src']    = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID).
1130
        '&'.time();
1131
    $p['width']  = 2; //no more 1x1 px image because we live in times of ad blockers...
1132
    $p['height'] = 1;
1133
    $p['alt']    = '';
1134
    $att         = buildAttributes($p);
1135
    print "<img $att />";
1136
    return true;
1137
}
1138
1139
/**
1140
 * tpl_getConf($id)
1141
 *
1142
 * use this function to access template configuration variables
1143
 *
1144
 * @param string $id      name of the value to access
1145
 * @param mixed  $notset  what to return if the setting is not available
1146
 * @return mixed
1147
 */
1148
function tpl_getConf($id, $notset=false) {
1149
    global $conf;
1150
    static $tpl_configloaded = false;
1151
1152
    $tpl = $conf['template'];
1153
1154
    if(!$tpl_configloaded) {
1155
        $tconf = tpl_loadConfig();
1156
        if($tconf !== false) {
1157
            foreach($tconf as $key => $value) {
1158
                if(isset($conf['tpl'][$tpl][$key])) continue;
1159
                $conf['tpl'][$tpl][$key] = $value;
1160
            }
1161
            $tpl_configloaded = true;
1162
        }
1163
    }
1164
1165
    if(isset($conf['tpl'][$tpl][$id])){
1166
        return $conf['tpl'][$tpl][$id];
1167
    }
1168
1169
    return $notset;
1170
}
1171
1172
/**
1173
 * tpl_loadConfig()
1174
 *
1175
 * reads all template configuration variables
1176
 * this function is automatically called by tpl_getConf()
1177
 *
1178
 * @return array
1179
 */
1180
function tpl_loadConfig() {
1181
1182
    $file = tpl_incdir().'/conf/default.php';
1183
    $conf = array();
1184
1185
    if(!file_exists($file)) return false;
1186
1187
    // load default config file
1188
    include($file);
1189
1190
    return $conf;
1191
}
1192
1193
// language methods
1194
/**
1195
 * tpl_getLang($id)
1196
 *
1197
 * use this function to access template language variables
1198
 *
1199
 * @param string $id key of language string
1200
 * @return string
1201
 */
1202
function tpl_getLang($id) {
1203
    static $lang = array();
1204
1205
    if(count($lang) === 0) {
1206
        global $conf, $config_cascade; // definitely don't invoke "global $lang"
1207
1208
        $path = tpl_incdir() . 'lang/';
1209
1210
        $lang = array();
1211
1212
        // don't include once
1213
        @include($path . 'en/lang.php');
1214
        foreach($config_cascade['lang']['template'] as $config_file) {
1215
            if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
1216
                include($config_file . $conf['template'] . '/en/lang.php');
1217
            }
1218
        }
1219
1220
        if($conf['lang'] != 'en') {
1221
            @include($path . $conf['lang'] . '/lang.php');
1222
            foreach($config_cascade['lang']['template'] as $config_file) {
1223
                if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
1224
                    include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
1225
                }
1226
            }
1227
        }
1228
    }
1229
    return $lang[$id];
1230
}
1231
1232
/**
1233
 * Retrieve a language dependent file and pass to xhtml renderer for display
1234
 * template equivalent of p_locale_xhtml()
1235
 *
1236
 * @param   string $id id of language dependent wiki page
1237
 * @return  string     parsed contents of the wiki page in xhtml format
1238
 */
1239
function tpl_locale_xhtml($id) {
1240
    return p_cached_output(tpl_localeFN($id));
1241
}
1242
1243
/**
1244
 * Prepends appropriate path for a language dependent filename
1245
 *
1246
 * @param string $id id of localized text
1247
 * @return string wiki text
1248
 */
1249
function tpl_localeFN($id) {
1250
    $path = tpl_incdir().'lang/';
1251
    global $conf;
1252
    $file = DOKU_CONF.'template_lang/'.$conf['template'].'/'.$conf['lang'].'/'.$id.'.txt';
1253
    if (!file_exists($file)){
1254
        $file = $path.$conf['lang'].'/'.$id.'.txt';
1255
        if(!file_exists($file)){
1256
            //fall back to english
1257
            $file = $path.'en/'.$id.'.txt';
1258
        }
1259
    }
1260
    return $file;
1261
}
1262
1263
/**
1264
 * prints the "main content" in the mediamanager popup
1265
 *
1266
 * Depending on the user's actions this may be a list of
1267
 * files in a namespace, the meta editing dialog or
1268
 * a message of referencing pages
1269
 *
1270
 * Only allowed in mediamanager.php
1271
 *
1272
 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1273
 * @param bool $fromajax - set true when calling this function via ajax
1274
 * @param string $sort
1275
 *
1276
 * @author Andreas Gohr <[email protected]>
1277
 */
1278
function tpl_mediaContent($fromajax = false, $sort='natural') {
1279
    global $IMG;
1280
    global $AUTH;
1281
    global $INUSE;
1282
    global $NS;
1283
    global $JUMPTO;
1284
    /** @var Input $INPUT */
1285
    global $INPUT;
1286
1287
    $do = $INPUT->extract('do')->str('do');
1288
    if(in_array($do, array('save', 'cancel'))) $do = '';
1289
1290
    if(!$do) {
1291
        if($INPUT->bool('edit')) {
1292
            $do = 'metaform';
1293
        } elseif(is_array($INUSE)) {
1294
            $do = 'filesinuse';
1295
        } else {
1296
            $do = 'filelist';
1297
        }
1298
    }
1299
1300
    // output the content pane, wrapped in an event.
1301
    if(!$fromajax) ptln('<div id="media__content">');
1302
    $data = array('do' => $do);
1303
    $evt  = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1304
    if($evt->advise_before()) {
1305
        $do = $data['do'];
1306
        if($do == 'filesinuse') {
1307
            media_filesinuse($INUSE, $IMG);
1308
        } elseif($do == 'filelist') {
1309
            media_filelist($NS, $AUTH, $JUMPTO,false,$sort);
1310
        } elseif($do == 'searchlist') {
1311
            media_searchlist($INPUT->str('q'), $NS, $AUTH);
1312
        } else {
1313
            msg('Unknown action '.hsc($do), -1);
1314
        }
1315
    }
1316
    $evt->advise_after();
1317
    unset($evt);
1318
    if(!$fromajax) ptln('</div>');
1319
1320
}
1321
1322
/**
1323
 * Prints the central column in full-screen media manager
1324
 * Depending on the opened tab this may be a list of
1325
 * files in a namespace, upload form or search form
1326
 *
1327
 * @author Kate Arzamastseva <[email protected]>
1328
 */
1329
function tpl_mediaFileList() {
1330
    global $AUTH;
1331
    global $NS;
1332
    global $JUMPTO;
1333
    global $lang;
1334
    /** @var Input $INPUT */
1335
    global $INPUT;
1336
1337
    $opened_tab = $INPUT->str('tab_files');
1338
    if(!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files';
1339
    if($INPUT->str('mediado') == 'update') $opened_tab = 'upload';
1340
1341
    echo '<h2 class="a11y">'.$lang['mediaselect'].'</h2>'.NL;
1342
1343
    media_tabs_files($opened_tab);
1344
1345
    echo '<div class="panelHeader">'.NL;
1346
    echo '<h3>';
1347
    $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']';
1348
    printf($lang['media_'.$opened_tab], '<strong>'.hsc($tabTitle).'</strong>');
1349
    echo '</h3>'.NL;
1350
    if($opened_tab === 'search' || $opened_tab === 'files') {
1351
        media_tab_files_options();
1352
    }
1353
    echo '</div>'.NL;
1354
1355
    echo '<div class="panelContent">'.NL;
1356
    if($opened_tab == 'files') {
1357
        media_tab_files($NS, $AUTH, $JUMPTO);
1358
    } elseif($opened_tab == 'upload') {
1359
        media_tab_upload($NS, $AUTH, $JUMPTO);
1360
    } elseif($opened_tab == 'search') {
1361
        media_tab_search($NS, $AUTH);
1362
    }
1363
    echo '</div>'.NL;
1364
}
1365
1366
/**
1367
 * Prints the third column in full-screen media manager
1368
 * Depending on the opened tab this may be details of the
1369
 * selected file, the meta editing dialog or
1370
 * list of file revisions
1371
 *
1372
 * @author Kate Arzamastseva <[email protected]>
1373
 *
1374
 * @param string $image
1375
 * @param boolean $rev
1376
 */
1377
function tpl_mediaFileDetails($image, $rev) {
1378
    global $conf, $DEL, $lang;
1379
    /** @var Input $INPUT */
1380
    global $INPUT;
1381
1382
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')) && $conf['mediarevisions']);
1383
    if(!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return;
1384
    if($rev && !file_exists(mediaFN($image, $rev))) $rev = false;
1385
    $ns = getNS($image);
1386
    $do = $INPUT->str('mediado');
1387
1388
    $opened_tab = $INPUT->str('tab_details');
1389
1390
    $tab_array = array('view');
1391
    list(, $mime) = mimetype($image);
1392
    if($mime == 'image/jpeg') {
1393
        $tab_array[] = 'edit';
1394
    }
1395
    if($conf['mediarevisions']) {
1396
        $tab_array[] = 'history';
1397
    }
1398
1399
    if(!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view';
1400
    if($INPUT->bool('edit')) $opened_tab = 'edit';
1401
    if($do == 'restore') $opened_tab = 'view';
1402
1403
    media_tabs_details($image, $opened_tab);
1404
1405
    echo '<div class="panelHeader"><h3>';
1406
    list($ext) = mimetype($image, false);
1407
    $class    = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1408
    $class    = 'select mediafile mf_'.$class;
1409
    $attributes = $rev ? ['rev' => $rev] : [];
1410
    $tabTitle = '<strong><a href="'.ml($image, $attributes).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>';
1411
    if($opened_tab === 'view' && $rev) {
1412
        printf($lang['media_viewold'], $tabTitle, dformat($rev));
1413
    } else {
1414
        printf($lang['media_'.$opened_tab], $tabTitle);
1415
    }
1416
1417
    echo '</h3></div>'.NL;
1418
1419
    echo '<div class="panelContent">'.NL;
1420
1421
    if($opened_tab == 'view') {
1422
        media_tab_view($image, $ns, null, $rev);
1423
1424
    } elseif($opened_tab == 'edit' && !$removed) {
1425
        media_tab_edit($image, $ns);
1426
1427
    } elseif($opened_tab == 'history' && $conf['mediarevisions']) {
1428
        media_tab_history($image, $ns);
1429
    }
1430
1431
    echo '</div>'.NL;
1432
}
1433
1434
/**
1435
 * prints the namespace tree in the mediamanager popup
1436
 *
1437
 * Only allowed in mediamanager.php
1438
 *
1439
 * @author Andreas Gohr <[email protected]>
1440
 */
1441
function tpl_mediaTree() {
1442
    global $NS;
1443
    ptln('<div id="media__tree">');
1444
    media_nstree($NS);
1445
    ptln('</div>');
1446
}
1447
1448
/**
1449
 * Print a dropdown menu with all DokuWiki actions
1450
 *
1451
 * Note: this will not use any pretty URLs
1452
 *
1453
 * @author Andreas Gohr <[email protected]>
1454
 *
1455
 * @param string $empty empty option label
1456
 * @param string $button submit button label
1457
 * @deprecated 2017-09-01 see devel:menus
1458
 */
1459
function tpl_actiondropdown($empty = '', $button = '&gt;') {
1460
    dbg_deprecated('see devel:menus');
1461
    $menu = new \dokuwiki\Menu\MobileMenu();
1462
    echo $menu->getDropdown($empty, $button);
1463
}
1464
1465
/**
1466
 * Print a informational line about the used license
1467
 *
1468
 * @author Andreas Gohr <[email protected]>
1469
 * @param  string $img     print image? (|button|badge)
1470
 * @param  bool   $imgonly skip the textual description?
1471
 * @param  bool   $return  when true don't print, but return HTML
1472
 * @param  bool   $wrap    wrap in div with class="license"?
1473
 * @return string
1474
 */
1475
function tpl_license($img = 'badge', $imgonly = false, $return = false, $wrap = true) {
1476
    global $license;
1477
    global $conf;
1478
    global $lang;
1479
    if(!$conf['license']) return '';
1480
    if(!is_array($license[$conf['license']])) return '';
1481
    $lic    = $license[$conf['license']];
1482
    $target = ($conf['target']['extern']) ? ' target="'.$conf['target']['extern'].'"' : '';
1483
1484
    $out = '';
1485
    if($wrap) $out .= '<div class="license">';
1486
    if($img) {
1487
        $src = license_img($img);
1488
        if($src) {
1489
            $out .= '<a href="'.$lic['url'].'" rel="license"'.$target;
1490
            $out .= '><img src="'.DOKU_BASE.$src.'" alt="'.$lic['name'].'" /></a>';
1491
            if(!$imgonly) $out .= ' ';
1492
        }
1493
    }
1494
    if(!$imgonly) {
1495
        $out .= $lang['license'].' ';
1496
        $out .= '<bdi><a href="'.$lic['url'].'" rel="license" class="urlextern"'.$target;
1497
        $out .= '>'.$lic['name'].'</a></bdi>';
1498
    }
1499
    if($wrap) $out .= '</div>';
1500
1501
    if($return) return $out;
1502
    echo $out;
1503
    return '';
1504
}
1505
1506
/**
1507
 * Includes the rendered HTML of a given page
1508
 *
1509
 * This function is useful to populate sidebars or similar features in a
1510
 * template
1511
 *
1512
 * @param string $pageid The page name you want to include
1513
 * @param bool $print Should the content be printed or returned only
1514
 * @param bool $propagate Search higher namespaces, too?
1515
 * @param bool $useacl Include the page only if the ACLs check out?
1516
 * @return bool|null|string
1517
 */
1518
function tpl_include_page($pageid, $print = true, $propagate = false, $useacl = true) {
1519
    if($propagate) {
1520
        $pageid = page_findnearest($pageid, $useacl);
1521
    } elseif($useacl && auth_quickaclcheck($pageid) == AUTH_NONE) {
1522
        return false;
1523
    }
1524
    if(!$pageid) return false;
1525
1526
    global $TOC;
1527
    $oldtoc = $TOC;
1528
    $html   = p_wiki_xhtml($pageid, '', false);
1529
    $TOC    = $oldtoc;
1530
1531
    if($print) echo $html;
1532
    return $html;
1533
}
1534
1535
/**
1536
 * Display the subscribe form
1537
 *
1538
 * @author Adrian Lang <[email protected]>
1539
 */
1540
function tpl_subscribe() {
1541
    global $INFO;
1542
    global $ID;
1543
    global $lang;
1544
    global $conf;
1545
    $stime_days = $conf['subscribe_time'] / 60 / 60 / 24;
1546
1547
    echo p_locale_xhtml('subscr_form');
1548
    echo '<h2>'.$lang['subscr_m_current_header'].'</h2>';
1549
    echo '<div class="level2">';
1550
    if($INFO['subscribed'] === false) {
1551
        echo '<p>'.$lang['subscr_m_not_subscribed'].'</p>';
1552
    } else {
1553
        echo '<ul>';
1554
        foreach($INFO['subscribed'] as $sub) {
1555
            echo '<li><div class="li">';
1556
            if($sub['target'] !== $ID) {
1557
                echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>';
1558
            } else {
1559
                echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>';
1560
            }
1561
            $sstl = sprintf($lang['subscr_style_'.$sub['style']], $stime_days);
1562
            if(!$sstl) $sstl = hsc($sub['style']);
1563
            echo ' ('.$sstl.') ';
1564
1565
            echo '<a href="'.wl(
1566
                $ID,
1567
                array(
1568
                     'do'        => 'subscribe',
1569
                     'sub_target'=> $sub['target'],
1570
                     'sub_style' => $sub['style'],
1571
                     'sub_action'=> 'unsubscribe',
1572
                     'sectok'    => getSecurityToken()
1573
                )
1574
            ).
1575
                '" class="unsubscribe">'.$lang['subscr_m_unsubscribe'].
1576
                '</a></div></li>';
1577
        }
1578
        echo '</ul>';
1579
    }
1580
    echo '</div>';
1581
1582
    // Add new subscription form
1583
    echo '<h2>'.$lang['subscr_m_new_header'].'</h2>';
1584
    echo '<div class="level2">';
1585
    $ns      = getNS($ID).':';
1586
    $targets = array(
1587
        $ID => '<code class="page">'.prettyprint_id($ID).'</code>',
1588
        $ns => '<code class="ns">'.prettyprint_id($ns).'</code>',
1589
    );
1590
    $styles  = array(
1591
        'every'  => $lang['subscr_style_every'],
1592
        'digest' => sprintf($lang['subscr_style_digest'], $stime_days),
1593
        'list'   => sprintf($lang['subscr_style_list'], $stime_days),
1594
    );
1595
1596
    $form = new Doku_Form(array('id' => 'subscribe__form'));
1597
    $form->startFieldset($lang['subscr_m_subscribe']);
1598
    $form->addRadioSet('sub_target', $targets);
1599
    $form->startFieldset($lang['subscr_m_receive']);
1600
    $form->addRadioSet('sub_style', $styles);
1601
    $form->addHidden('sub_action', 'subscribe');
1602
    $form->addHidden('do', 'subscribe');
1603
    $form->addHidden('id', $ID);
1604
    $form->endFieldset();
1605
    $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
1606
    html_form('SUBSCRIBE', $form);
1607
    echo '</div>';
1608
}
1609
1610
/**
1611
 * Tries to send already created content right to the browser
1612
 *
1613
 * Wraps around ob_flush() and flush()
1614
 *
1615
 * @author Andreas Gohr <[email protected]>
1616
 */
1617
function tpl_flush() {
1618
    ob_flush();
1619
    flush();
1620
}
1621
1622
/**
1623
 * Tries to find a ressource file in the given locations.
1624
 *
1625
 * If a given location starts with a colon it is assumed to be a media
1626
 * file, otherwise it is assumed to be relative to the current template
1627
 *
1628
 * @param  string[] $search       locations to look at
1629
 * @param  bool     $abs           if to use absolute URL
1630
 * @param  array   &$imginfo   filled with getimagesize()
1631
 * @return string
1632
 *
1633
 * @author Andreas  Gohr <[email protected]>
1634
 */
1635
function tpl_getMediaFile($search, $abs = false, &$imginfo = null) {
1636
    $img     = '';
1637
    $file    = '';
1638
    $ismedia = false;
1639
    // loop through candidates until a match was found:
1640
    foreach($search as $img) {
1641
        if(substr($img, 0, 1) == ':') {
1642
            $file    = mediaFN($img);
1643
            $ismedia = true;
1644
        } else {
1645
            $file    = tpl_incdir().$img;
1646
            $ismedia = false;
1647
        }
1648
1649
        if(file_exists($file)) break;
1650
    }
1651
1652
    // fetch image data if requested
1653
    if(!is_null($imginfo)) {
1654
        $imginfo = getimagesize($file);
1655
    }
1656
1657
    // build URL
1658
    if($ismedia) {
1659
        $url = ml($img, '', true, '', $abs);
1660
    } else {
1661
        $url = tpl_basedir().$img;
1662
        if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL));
1663
    }
1664
1665
    return $url;
1666
}
1667
1668
/**
1669
 * PHP include a file
1670
 *
1671
 * either from the conf directory if it exists, otherwise use
1672
 * file in the template's root directory.
1673
 *
1674
 * The function honours config cascade settings and looks for the given
1675
 * file next to the ´main´ config files, in the order protected, local,
1676
 * default.
1677
 *
1678
 * Note: no escaping or sanity checking is done here. Never pass user input
1679
 * to this function!
1680
 *
1681
 * @author Anika Henke <[email protected]>
1682
 * @author Andreas Gohr <[email protected]>
1683
 *
1684
 * @param string $file
1685
 */
1686
function tpl_includeFile($file) {
1687
    global $config_cascade;
1688
    foreach(array('protected', 'local', 'default') as $config_group) {
1689
        if(empty($config_cascade['main'][$config_group])) continue;
1690
        foreach($config_cascade['main'][$config_group] as $conf_file) {
1691
            $dir = dirname($conf_file);
1692
            if(file_exists("$dir/$file")) {
1693
                include("$dir/$file");
1694
                return;
1695
            }
1696
        }
1697
    }
1698
1699
    // still here? try the template dir
1700
    $file = tpl_incdir().$file;
1701
    if(file_exists($file)) {
1702
        include($file);
1703
    }
1704
}
1705
1706
/**
1707
 * Returns <link> tag for various icon types (favicon|mobile|generic)
1708
 *
1709
 * @author Anika Henke <[email protected]>
1710
 *
1711
 * @param  array $types - list of icon types to display (favicon|mobile|generic)
1712
 * @return string
1713
 */
1714
function tpl_favicon($types = array('favicon')) {
1715
1716
    $return = '';
1717
1718
    foreach($types as $type) {
1719
        switch($type) {
1720
            case 'favicon':
1721
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
1722
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1723
                break;
1724
            case 'mobile':
1725
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
1726
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1727
                break;
1728
            case 'generic':
1729
                // ideal world solution, which doesn't work in any browser yet
1730
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
1731
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
1732
                break;
1733
        }
1734
    }
1735
1736
    return $return;
1737
}
1738
1739
/**
1740
 * Prints full-screen media manager
1741
 *
1742
 * @author Kate Arzamastseva <[email protected]>
1743
 */
1744
function tpl_media() {
1745
    global $NS, $IMG, $JUMPTO, $REV, $lang, $fullscreen, $INPUT;
1746
    $fullscreen = true;
1747
    require_once DOKU_INC.'lib/exe/mediamanager.php';
1748
1749
    $rev   = '';
1750
    $image = cleanID($INPUT->str('image'));
1751
    if(isset($IMG)) $image = $IMG;
1752
    if(isset($JUMPTO)) $image = $JUMPTO;
1753
    if(isset($REV) && !$JUMPTO) $rev = $REV;
1754
1755
    echo '<div id="mediamanager__page">'.NL;
1756
    echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1757
    html_msgarea();
1758
1759
    echo '<div class="panel namespaces">'.NL;
1760
    echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1761
    echo '<div class="panelHeader">';
1762
    echo $lang['media_namespaces'];
1763
    echo '</div>'.NL;
1764
1765
    echo '<div class="panelContent" id="media__tree">'.NL;
1766
    media_nstree($NS);
1767
    echo '</div>'.NL;
1768
    echo '</div>'.NL;
1769
1770
    echo '<div class="panel filelist">'.NL;
1771
    tpl_mediaFileList();
1772
    echo '</div>'.NL;
1773
1774
    echo '<div class="panel file">'.NL;
1775
    echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1776
    tpl_mediaFileDetails($image, $rev);
1777
    echo '</div>'.NL;
1778
1779
    echo '</div>'.NL;
1780
}
1781
1782
/**
1783
 * Return useful layout classes
1784
 *
1785
 * @author Anika Henke <[email protected]>
1786
 *
1787
 * @return string
1788
 */
1789
function tpl_classes() {
1790
    global $ACT, $conf, $ID, $INFO;
1791
    /** @var Input $INPUT */
1792
    global $INPUT;
1793
1794
    $classes = array(
1795
        'dokuwiki',
1796
        'mode_'.$ACT,
1797
        'tpl_'.$conf['template'],
1798
        $INPUT->server->bool('REMOTE_USER') ? 'loggedIn' : '',
1799
        $INFO['exists'] ? '' : 'notFound',
1800
        ($ID == $conf['start']) ? 'home' : '',
1801
    );
1802
    return join(' ', $classes);
1803
}
1804
1805
/**
1806
 * Create event for tools menues
1807
 *
1808
 * @author Anika Henke <[email protected]>
1809
 * @param string $toolsname name of menu
1810
 * @param array $items
1811
 * @param string $view e.g. 'main', 'detail', ...
1812
 * @deprecated 2017-09-01 see devel:menus
1813
 */
1814
function tpl_toolsevent($toolsname, $items, $view = 'main') {
1815
    dbg_deprecated('see devel:menus');
1816
    $data = array(
1817
        'view' => $view,
1818
        'items' => $items
1819
    );
1820
1821
    $hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
1822
    $evt = new Doku_Event($hook, $data);
1823
    if($evt->advise_before()) {
1824
        foreach($evt->data['items'] as $k => $html) echo $html;
1825
    }
1826
    $evt->advise_after();
1827
}
1828
1829
//Setup VIM: ex: et ts=4 :
1830
1831