Failed Conditions
Push — stable ( 017e16...b83837 )
by
unknown
07:54 queued 02:55
created

inc/template.php (1 issue)

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

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
1649
    $form->startFieldset($lang['subscr_m_subscribe']);
1650
    $form->addRadioSet('sub_target', $targets);
1651
    $form->startFieldset($lang['subscr_m_receive']);
1652
    $form->addRadioSet('sub_style', $styles);
1653
    $form->addHidden('sub_action', 'subscribe');
1654
    $form->addHidden('do', 'subscribe');
1655
    $form->addHidden('id', $ID);
1656
    $form->endFieldset();
1657
    $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
1658
    html_form('SUBSCRIBE', $form);
1659
    echo '</div>';
1660
}
1661
1662
/**
1663
 * Tries to send already created content right to the browser
1664
 *
1665
 * Wraps around ob_flush() and flush()
1666
 *
1667
 * @author Andreas Gohr <[email protected]>
1668
 */
1669
function tpl_flush() {
1670
    if( ob_get_level() > 0 ) ob_flush();
1671
    flush();
1672
}
1673
1674
/**
1675
 * Tries to find a ressource file in the given locations.
1676
 *
1677
 * If a given location starts with a colon it is assumed to be a media
1678
 * file, otherwise it is assumed to be relative to the current template
1679
 *
1680
 * @param  string[] $search       locations to look at
1681
 * @param  bool     $abs          if to use absolute URL
1682
 * @param  array    &$imginfo     filled with getimagesize()
1683
 * @param  bool     $fallback     use fallback image if target isn't found or return 'false' if potential
1684
 *                                false result is required
1685
 * @return string
1686
 *
1687
 * @author Andreas  Gohr <[email protected]>
1688
 */
1689
function tpl_getMediaFile($search, $abs = false, &$imginfo = null, $fallback = true) {
1690
    $img     = '';
1691
    $file    = '';
1692
    $ismedia = false;
1693
    // loop through candidates until a match was found:
1694
    foreach($search as $img) {
1695
        if(substr($img, 0, 1) == ':') {
1696
            $file    = mediaFN($img);
1697
            $ismedia = true;
1698
        } else {
1699
            $file    = tpl_incdir().$img;
1700
            $ismedia = false;
1701
        }
1702
1703
        if(file_exists($file)) break;
1704
    }
1705
1706
    // manage non existing target
1707
    if (!file_exists($file)) {
1708
        // give result for fallback image
1709
        if ($fallback === true) {
1710
            $file = DOKU_INC . 'lib/images/blank.gif';
1711
            // stop process if false result is required (if $fallback is false)
1712
        } else {
1713
            return false;
1714
        }
1715
    }
1716
1717
    // fetch image data if requested
1718
    if(!is_null($imginfo)) {
1719
        $imginfo = getimagesize($file);
1720
    }
1721
1722
    // build URL
1723
    if($ismedia) {
1724
        $url = ml($img, '', true, '', $abs);
1725
    } else {
1726
        $url = tpl_basedir().$img;
1727
        if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL));
1728
    }
1729
1730
    return $url;
1731
}
1732
1733
/**
1734
 * PHP include a file
1735
 *
1736
 * either from the conf directory if it exists, otherwise use
1737
 * file in the template's root directory.
1738
 *
1739
 * The function honours config cascade settings and looks for the given
1740
 * file next to the ´main´ config files, in the order protected, local,
1741
 * default.
1742
 *
1743
 * Note: no escaping or sanity checking is done here. Never pass user input
1744
 * to this function!
1745
 *
1746
 * @author Anika Henke <[email protected]>
1747
 * @author Andreas Gohr <[email protected]>
1748
 *
1749
 * @param string $file
1750
 */
1751
function tpl_includeFile($file) {
1752
    global $config_cascade;
1753
    foreach(array('protected', 'local', 'default') as $config_group) {
1754
        if(empty($config_cascade['main'][$config_group])) continue;
1755
        foreach($config_cascade['main'][$config_group] as $conf_file) {
1756
            $dir = dirname($conf_file);
1757
            if(file_exists("$dir/$file")) {
1758
                include("$dir/$file");
1759
                return;
1760
            }
1761
        }
1762
    }
1763
1764
    // still here? try the template dir
1765
    $file = tpl_incdir().$file;
1766
    if(file_exists($file)) {
1767
        include($file);
1768
    }
1769
}
1770
1771
/**
1772
 * Returns <link> tag for various icon types (favicon|mobile|generic)
1773
 *
1774
 * @author Anika Henke <[email protected]>
1775
 *
1776
 * @param  array $types - list of icon types to display (favicon|mobile|generic)
1777
 * @return string
1778
 */
1779
function tpl_favicon($types = array('favicon')) {
1780
1781
    $return = '';
1782
1783
    foreach($types as $type) {
1784
        switch($type) {
1785
            case 'favicon':
1786
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
1787
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1788
                break;
1789
            case 'mobile':
1790
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
1791
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1792
                break;
1793
            case 'generic':
1794
                // ideal world solution, which doesn't work in any browser yet
1795
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
1796
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
1797
                break;
1798
        }
1799
    }
1800
1801
    return $return;
1802
}
1803
1804
/**
1805
 * Prints full-screen media manager
1806
 *
1807
 * @author Kate Arzamastseva <[email protected]>
1808
 */
1809
function tpl_media() {
1810
    global $NS, $IMG, $JUMPTO, $REV, $lang, $fullscreen, $INPUT;
1811
    $fullscreen = true;
1812
    require_once DOKU_INC.'lib/exe/mediamanager.php';
1813
1814
    $rev   = '';
1815
    $image = cleanID($INPUT->str('image'));
1816
    if(isset($IMG)) $image = $IMG;
1817
    if(isset($JUMPTO)) $image = $JUMPTO;
1818
    if(isset($REV) && !$JUMPTO) $rev = $REV;
1819
1820
    echo '<div id="mediamanager__page">'.NL;
1821
    echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1822
    html_msgarea();
1823
1824
    echo '<div class="panel namespaces">'.NL;
1825
    echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1826
    echo '<div class="panelHeader">';
1827
    echo $lang['media_namespaces'];
1828
    echo '</div>'.NL;
1829
1830
    echo '<div class="panelContent" id="media__tree">'.NL;
1831
    media_nstree($NS);
1832
    echo '</div>'.NL;
1833
    echo '</div>'.NL;
1834
1835
    echo '<div class="panel filelist">'.NL;
1836
    tpl_mediaFileList();
1837
    echo '</div>'.NL;
1838
1839
    echo '<div class="panel file">'.NL;
1840
    echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1841
    tpl_mediaFileDetails($image, $rev);
1842
    echo '</div>'.NL;
1843
1844
    echo '</div>'.NL;
1845
}
1846
1847
/**
1848
 * Return useful layout classes
1849
 *
1850
 * @author Anika Henke <[email protected]>
1851
 *
1852
 * @return string
1853
 */
1854
function tpl_classes() {
1855
    global $ACT, $conf, $ID, $INFO;
1856
    /** @var Input $INPUT */
1857
    global $INPUT;
1858
1859
    $classes = array(
1860
        'dokuwiki',
1861
        'mode_'.$ACT,
1862
        'tpl_'.$conf['template'],
1863
        $INPUT->server->bool('REMOTE_USER') ? 'loggedIn' : '',
1864
        (isset($INFO) && $INFO['exists']) ? '' : 'notFound',
1865
        ($ID == $conf['start']) ? 'home' : '',
1866
    );
1867
    return join(' ', $classes);
1868
}
1869
1870
/**
1871
 * Create event for tools menues
1872
 *
1873
 * @author Anika Henke <[email protected]>
1874
 * @param string $toolsname name of menu
1875
 * @param array $items
1876
 * @param string $view e.g. 'main', 'detail', ...
1877
 * @deprecated 2017-09-01 see devel:menus
1878
 */
1879
function tpl_toolsevent($toolsname, $items, $view = 'main') {
1880
    dbg_deprecated('see devel:menus');
1881
    $data = array(
1882
        'view' => $view,
1883
        'items' => $items
1884
    );
1885
1886
    $hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
1887
    $evt = new Event($hook, $data);
1888
    if($evt->advise_before()) {
1889
        foreach($evt->data['items'] as $k => $html) echo $html;
1890
    }
1891
    $evt->advise_after();
1892
}
1893
1894
//Setup VIM: ex: et ts=4 :
1895
1896