Failed Conditions
Pull Request — psr2 (#2426)
by Andreas
09:22 queued 06:07
created

inc/template.php (2 issues)

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');
0 ignored issues
show
Deprecated Code introduced by
The function plugin_list() has been deprecated with message: 2018-07-20

This function 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 function will be removed from the class and what other function to use instead.

Loading history...
176
177
        if(in_array($class, $pluginlist)) {
178
            // attempt to load the plugin
179
            /** @var $plugin AdminPlugin */
180
            $plugin = plugin_load('admin', $class);
0 ignored issues
show
Deprecated Code introduced by
The function plugin_load() has been deprecated with message: 2018-07-20 we will probably keep this around for a long time though

This function 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 function will be removed from the class and what other function to use instead.

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