Failed Conditions
Push — master ( 96da53...0afbc1 )
by Andreas
06:02 queued 03:20
created

template.php ➔ tpl_subscribe()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * DokuWiki template functions
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
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);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_get_action() has been deprecated with message: 2017-09-01 see devel:menus

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...
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);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_get_action() has been deprecated with message: 2017-09-01 see devel:menus

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...
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);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_actionlink() has been deprecated with message: 2017-09-01 see devel:menus

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...
642
    } else {
643
        $out .= tpl_button($type, true);
0 ignored issues
show
Deprecated Code introduced by
The function tpl_button() has been deprecated with message: 2017-09-01 see devel:menus

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...
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
709
    echo $searchForm->toHTML('QuickSearch');
710
711
    return true;
712
}
713
714
/**
715
 * Print the breadcrumbs trace
716
 *
717
 * @author Andreas Gohr <[email protected]>
718
 *
719
 * @param string $sep Separator between entries
720
 * @param bool   $return return or print
721
 * @return bool|string
722
 */
723
function tpl_breadcrumbs($sep = null, $return = false) {
724
    global $lang;
725
    global $conf;
726
727
    //check if enabled
728
    if(!$conf['breadcrumbs']) return false;
729
730
    //set default
731
    if(is_null($sep)) $sep = '•';
732
733
    $out='';
734
735
    $crumbs = breadcrumbs(); //setup crumb trace
736
737
    $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
738
739
    //render crumbs, highlight the last one
740
    $out .= '<span class="bchead">'.$lang['breadcrumb'].'</span>';
741
    $last = count($crumbs);
742
    $i    = 0;
743
    foreach($crumbs as $id => $name) {
744
        $i++;
745
        $out .= $crumbs_sep;
746
        if($i == $last) $out .= '<span class="curid">';
747
        $out .= '<bdi>' . tpl_link(wl($id), hsc($name), 'class="breadcrumbs" title="'.$id.'"', true) .  '</bdi>';
748
        if($i == $last) $out .= '</span>';
749
    }
750
    if($return) return $out;
751
    print $out;
752
    return $out ? true : false;
753
}
754
755
/**
756
 * Hierarchical breadcrumbs
757
 *
758
 * This code was suggested as replacement for the usual breadcrumbs.
759
 * It only makes sense with a deep site structure.
760
 *
761
 * @author Andreas Gohr <[email protected]>
762
 * @author Nigel McNie <[email protected]>
763
 * @author Sean Coates <[email protected]>
764
 * @author <[email protected]>
765
 * @todo   May behave strangely in RTL languages
766
 *
767
 * @param string $sep Separator between entries
768
 * @param bool   $return return or print
769
 * @return bool|string
770
 */
771
function tpl_youarehere($sep = null, $return = false) {
772
    global $conf;
773
    global $ID;
774
    global $lang;
775
776
    // check if enabled
777
    if(!$conf['youarehere']) return false;
778
779
    //set default
780
    if(is_null($sep)) $sep = ' » ';
781
782
    $out = '';
783
784
    $parts = explode(':', $ID);
785
    $count = count($parts);
786
787
    $out .= '<span class="bchead">'.$lang['youarehere'].' </span>';
788
789
    // always print the startpage
790
    $out .= '<span class="home">' . tpl_pagelink(':'.$conf['start'], null, true) . '</span>';
791
792
    // print intermediate namespace links
793
    $part = '';
794
    for($i = 0; $i < $count - 1; $i++) {
795
        $part .= $parts[$i].':';
796
        $page = $part;
797
        if($page == $conf['start']) continue; // Skip startpage
798
799
        // output
800
        $out .= $sep . tpl_pagelink($page, null, true);
801
    }
802
803
    // print current page, skipping start page, skipping for namespace index
804
    resolve_pageid('', $page, $exists);
805
    if (isset($page) && $page == $part.$parts[$i]) {
806
        if($return) return $out;
807
        print $out;
808
        return true;
809
    }
810
    $page = $part.$parts[$i];
811
    if($page == $conf['start']) {
812
        if($return) return $out;
813
        print $out;
814
        return true;
815
    }
816
    $out .= $sep;
817
    $out .= tpl_pagelink($page, null, true);
818
    if($return) return $out;
819
    print $out;
820
    return $out ? true : false;
821
}
822
823
/**
824
 * Print info if the user is logged in
825
 * and show full name in that case
826
 *
827
 * Could be enhanced with a profile link in future?
828
 *
829
 * @author Andreas Gohr <[email protected]>
830
 *
831
 * @return bool
832
 */
833
function tpl_userinfo() {
834
    global $lang;
835
    /** @var Input $INPUT */
836
    global $INPUT;
837
838
    if($INPUT->server->str('REMOTE_USER')) {
839
        print $lang['loggedinas'].' '.userlink();
840
        return true;
841
    }
842
    return false;
843
}
844
845
/**
846
 * Print some info about the current page
847
 *
848
 * @author Andreas Gohr <[email protected]>
849
 *
850
 * @param bool $ret return content instead of printing it
851
 * @return bool|string
852
 */
853
function tpl_pageinfo($ret = false) {
854
    global $conf;
855
    global $lang;
856
    global $INFO;
857
    global $ID;
858
859
    // return if we are not allowed to view the page
860
    if(!auth_quickaclcheck($ID)) {
861
        return false;
862
    }
863
864
    // prepare date and path
865
    $fn = $INFO['filepath'];
866
    if(!$conf['fullpath']) {
867
        if($INFO['rev']) {
868
            $fn = str_replace($conf['olddir'].'/', '', $fn);
869
        } else {
870
            $fn = str_replace($conf['datadir'].'/', '', $fn);
871
        }
872
    }
873
    $fn   = utf8_decodeFN($fn);
874
    $date = dformat($INFO['lastmod']);
875
876
    // print it
877
    if($INFO['exists']) {
878
        $out = '';
879
        $out .= '<bdi>'.$fn.'</bdi>';
880
        $out .= ' · ';
881
        $out .= $lang['lastmod'];
882
        $out .= ' ';
883
        $out .= $date;
884
        if($INFO['editor']) {
885
            $out .= ' '.$lang['by'].' ';
886
            $out .= '<bdi>'.editorinfo($INFO['editor']).'</bdi>';
887
        } else {
888
            $out .= ' ('.$lang['external_edit'].')';
889
        }
890
        if($INFO['locked']) {
891
            $out .= ' · ';
892
            $out .= $lang['lockedby'];
893
            $out .= ' ';
894
            $out .= '<bdi>'.editorinfo($INFO['locked']).'</bdi>';
895
        }
896
        if($ret) {
897
            return $out;
898
        } else {
899
            echo $out;
900
            return true;
901
        }
902
    }
903
    return false;
904
}
905
906
/**
907
 * Prints or returns the name of the given page (current one if none given).
908
 *
909
 * If useheading is enabled this will use the first headline else
910
 * the given ID is used.
911
 *
912
 * @author Andreas Gohr <[email protected]>
913
 *
914
 * @param string $id page id
915
 * @param bool   $ret return content instead of printing
916
 * @return bool|string
917
 */
918
function tpl_pagetitle($id = null, $ret = false) {
919
    global $ACT, $INPUT, $conf, $lang;
920
921
    if(is_null($id)) {
922
        global $ID;
923
        $id = $ID;
924
    }
925
926
    $name = $id;
927
    if(useHeading('navigation')) {
928
        $first_heading = p_get_first_heading($id);
929
        if($first_heading) $name = $first_heading;
0 ignored issues
show
Bug Best Practice introduced by
The expression $first_heading of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
930
    }
931
932
    // default page title is the page name, modify with the current action
933
    switch ($ACT) {
934
        // admin functions
935
        case 'admin' :
936
            $page_title = $lang['btn_admin'];
937
            // try to get the plugin name
938
            /** @var $plugin AdminPlugin */
939
            if ($plugin = plugin_getRequestAdminPlugin()){
940
                $plugin_title = $plugin->getMenuText($conf['lang']);
941
                $page_title = $plugin_title ? $plugin_title : $plugin->getPluginName();
942
            }
943
            break;
944
945
        // user functions
946
        case 'login' :
947
        case 'profile' :
948
        case 'register' :
949
        case 'resendpwd' :
950
            $page_title = $lang['btn_'.$ACT];
951
            break;
952
953
         // wiki functions
954
        case 'search' :
955
        case 'index' :
956
            $page_title = $lang['btn_'.$ACT];
957
            break;
958
959
        // page functions
960
        case 'edit' :
961
        case 'preview' :
962
            $page_title = "✎ ".$name;
963
            break;
964
965
        case 'revisions' :
966
            $page_title = $name . ' - ' . $lang['btn_revs'];
967
            break;
968
969
        case 'backlink' :
970
        case 'recent' :
971
        case 'subscribe' :
972
            $page_title = $name . ' - ' . $lang['btn_'.$ACT];
973
            break;
974
975
        default : // SHOW and anything else not included
976
            $page_title = $name;
977
    }
978
979
    if($ret) {
980
        return hsc($page_title);
981
    } else {
982
        print hsc($page_title);
983
        return true;
984
    }
985
}
986
987
/**
988
 * Returns the requested EXIF/IPTC tag from the current image
989
 *
990
 * If $tags is an array all given tags are tried until a
991
 * value is found. If no value is found $alt is returned.
992
 *
993
 * Which texts are known is defined in the functions _exifTagNames
994
 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
995
 * to the names of the latter one)
996
 *
997
 * Only allowed in: detail.php
998
 *
999
 * @author Andreas Gohr <[email protected]>
1000
 *
1001
 * @param array|string $tags tag or array of tags to try
1002
 * @param string       $alt  alternative output if no data was found
1003
 * @param null|string  $src  the image src, uses global $SRC if not given
1004
 * @return string
1005
 */
1006
function tpl_img_getTag($tags, $alt = '', $src = null) {
1007
    // Init Exif Reader
1008
    global $SRC;
1009
1010
    if(is_null($src)) $src = $SRC;
1011
1012
    static $meta = null;
1013
    if(is_null($meta)) $meta = new JpegMeta($src);
1014
    if($meta === false) return $alt;
1015
    $info = cleanText($meta->getField($tags));
1016
    if($info == false) return $alt;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $info of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
1017
    return $info;
1018
}
1019
1020
/**
1021
 * Returns a description list of the metatags of the current image
1022
 *
1023
 * @return string html of description list
1024
 */
1025
function tpl_img_meta() {
1026
    global $lang;
1027
1028
    $tags = tpl_get_img_meta();
1029
1030
    echo '<dl>';
1031
    foreach($tags as $tag) {
1032
        $label = $lang[$tag['langkey']];
1033
        if(!$label) $label = $tag['langkey'] . ':';
1034
1035
        echo '<dt>'.$label.'</dt><dd>';
1036
        if ($tag['type'] == 'date') {
1037
            echo dformat($tag['value']);
1038
        } else {
1039
            echo hsc($tag['value']);
1040
        }
1041
        echo '</dd>';
1042
    }
1043
    echo '</dl>';
1044
}
1045
1046
/**
1047
 * Returns metadata as configured in mediameta config file, ready for creating html
1048
 *
1049
 * @return array with arrays containing the entries:
1050
 *   - string langkey  key to lookup in the $lang var, if not found printed as is
1051
 *   - string type     type of value
1052
 *   - string value    tag value (unescaped)
1053
 */
1054
function tpl_get_img_meta() {
1055
1056
    $config_files = getConfigFiles('mediameta');
1057
    foreach ($config_files as $config_file) {
1058
        if(file_exists($config_file)) {
1059
            include($config_file);
1060
        }
1061
    }
1062
    /** @var array $fields the included array with metadata */
1063
1064
    $tags = array();
1065
    foreach($fields as $tag){
0 ignored issues
show
Bug introduced by
The variable $fields does not exist. Did you forget to declare it?

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

Loading history...
1066
        $t = array();
1067
        if (!empty($tag[0])) {
1068
            $t = array($tag[0]);
1069
        }
1070
        if(is_array($tag[3])) {
1071
            $t = array_merge($t,$tag[3]);
1072
        }
1073
        $value = tpl_img_getTag($t);
1074
        if ($value) {
1075
            $tags[] = array('langkey' => $tag[1], 'type' => $tag[2], 'value' => $value);
1076
        }
1077
    }
1078
    return $tags;
1079
}
1080
1081
/**
1082
 * Prints the image with a link to the full sized version
1083
 *
1084
 * Only allowed in: detail.php
1085
 *
1086
 * @triggers TPL_IMG_DISPLAY
1087
 * @param $maxwidth  int - maximal width of the image
1088
 * @param $maxheight int - maximal height of the image
1089
 * @param $link bool     - link to the orginal size?
1090
 * @param $params array  - additional image attributes
1091
 * @return bool Result of TPL_IMG_DISPLAY
1092
 */
1093
function tpl_img($maxwidth = 0, $maxheight = 0, $link = true, $params = null) {
1094
    global $IMG;
1095
    /** @var Input $INPUT */
1096
    global $INPUT;
1097
    global $REV;
1098
    $w = (int) tpl_img_getTag('File.Width');
1099
    $h = (int) tpl_img_getTag('File.Height');
1100
1101
    //resize to given max values
1102
    $ratio = 1;
1103
    if($w >= $h) {
1104
        if($maxwidth && $w >= $maxwidth) {
1105
            $ratio = $maxwidth / $w;
1106
        } elseif($maxheight && $h > $maxheight) {
1107
            $ratio = $maxheight / $h;
1108
        }
1109
    } else {
1110
        if($maxheight && $h >= $maxheight) {
1111
            $ratio = $maxheight / $h;
1112
        } elseif($maxwidth && $w > $maxwidth) {
1113
            $ratio = $maxwidth / $w;
1114
        }
1115
    }
1116
    if($ratio) {
1117
        $w = floor($ratio * $w);
1118
        $h = floor($ratio * $h);
1119
    }
1120
1121
    //prepare URLs
1122
    $url = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV), true, '&');
1123
    $src = ml($IMG, array('cache'=> $INPUT->str('cache'),'rev'=>$REV, 'w'=> $w, 'h'=> $h), true, '&');
1124
1125
    //prepare attributes
1126
    $alt = tpl_img_getTag('Simple.Title');
1127
    if(is_null($params)) {
1128
        $p = array();
1129
    } else {
1130
        $p = $params;
1131
    }
1132
    if($w) $p['width'] = $w;
1133
    if($h) $p['height'] = $h;
1134
    $p['class'] = 'img_detail';
1135
    if($alt) {
1136
        $p['alt']   = $alt;
1137
        $p['title'] = $alt;
1138
    } else {
1139
        $p['alt'] = '';
1140
    }
1141
    $p['src'] = $src;
1142
1143
    $data = array('url'=> ($link ? $url : null), 'params'=> $p);
1144
    return Event::createAndTrigger('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
1145
}
1146
1147
/**
1148
 * Default action for TPL_IMG_DISPLAY
1149
 *
1150
 * @param array $data
1151
 * @return bool
1152
 */
1153
function _tpl_img_action($data) {
1154
    global $lang;
1155
    $p = buildAttributes($data['params']);
1156
1157
    if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">';
1158
    print '<img '.$p.'/>';
1159
    if($data['url']) print '</a>';
1160
    return true;
1161
}
1162
1163
/**
1164
 * This function inserts a small gif which in reality is the indexer function.
1165
 *
1166
 * Should be called somewhere at the very end of the main.php
1167
 * template
1168
 *
1169
 * @return bool
1170
 */
1171
function tpl_indexerWebBug() {
1172
    global $ID;
1173
1174
    $p           = array();
1175
    $p['src']    = DOKU_BASE.'lib/exe/taskrunner.php?id='.rawurlencode($ID).
1176
        '&'.time();
1177
    $p['width']  = 2; //no more 1x1 px image because we live in times of ad blockers...
1178
    $p['height'] = 1;
1179
    $p['alt']    = '';
1180
    $att         = buildAttributes($p);
1181
    print "<img $att />";
1182
    return true;
1183
}
1184
1185
/**
1186
 * tpl_getConf($id)
1187
 *
1188
 * use this function to access template configuration variables
1189
 *
1190
 * @param string $id      name of the value to access
1191
 * @param mixed  $notset  what to return if the setting is not available
1192
 * @return mixed
1193
 */
1194
function tpl_getConf($id, $notset=false) {
1195
    global $conf;
1196
    static $tpl_configloaded = false;
1197
1198
    $tpl = $conf['template'];
1199
1200
    if(!$tpl_configloaded) {
1201
        $tconf = tpl_loadConfig();
1202
        if($tconf !== false) {
1203
            foreach($tconf as $key => $value) {
1204
                if(isset($conf['tpl'][$tpl][$key])) continue;
1205
                $conf['tpl'][$tpl][$key] = $value;
1206
            }
1207
            $tpl_configloaded = true;
1208
        }
1209
    }
1210
1211
    if(isset($conf['tpl'][$tpl][$id])){
1212
        return $conf['tpl'][$tpl][$id];
1213
    }
1214
1215
    return $notset;
1216
}
1217
1218
/**
1219
 * tpl_loadConfig()
1220
 *
1221
 * reads all template configuration variables
1222
 * this function is automatically called by tpl_getConf()
1223
 *
1224
 * @return array
1225
 */
1226
function tpl_loadConfig() {
1227
1228
    $file = tpl_incdir().'/conf/default.php';
1229
    $conf = array();
1230
1231
    if(!file_exists($file)) return false;
1232
1233
    // load default config file
1234
    include($file);
1235
1236
    return $conf;
1237
}
1238
1239
// language methods
1240
/**
1241
 * tpl_getLang($id)
1242
 *
1243
 * use this function to access template language variables
1244
 *
1245
 * @param string $id key of language string
1246
 * @return string
1247
 */
1248
function tpl_getLang($id) {
1249
    static $lang = array();
1250
1251
    if(count($lang) === 0) {
1252
        global $conf, $config_cascade; // definitely don't invoke "global $lang"
1253
1254
        $path = tpl_incdir() . 'lang/';
1255
1256
        $lang = array();
1257
1258
        // don't include once
1259
        @include($path . 'en/lang.php');
1260
        foreach($config_cascade['lang']['template'] as $config_file) {
1261
            if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
1262
                include($config_file . $conf['template'] . '/en/lang.php');
1263
            }
1264
        }
1265
1266
        if($conf['lang'] != 'en') {
1267
            @include($path . $conf['lang'] . '/lang.php');
1268
            foreach($config_cascade['lang']['template'] as $config_file) {
1269
                if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
1270
                    include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
1271
                }
1272
            }
1273
        }
1274
    }
1275
    return $lang[$id];
1276
}
1277
1278
/**
1279
 * Retrieve a language dependent file and pass to xhtml renderer for display
1280
 * template equivalent of p_locale_xhtml()
1281
 *
1282
 * @param   string $id id of language dependent wiki page
1283
 * @return  string     parsed contents of the wiki page in xhtml format
1284
 */
1285
function tpl_locale_xhtml($id) {
1286
    return p_cached_output(tpl_localeFN($id));
1287
}
1288
1289
/**
1290
 * Prepends appropriate path for a language dependent filename
1291
 *
1292
 * @param string $id id of localized text
1293
 * @return string wiki text
1294
 */
1295
function tpl_localeFN($id) {
1296
    $path = tpl_incdir().'lang/';
1297
    global $conf;
1298
    $file = DOKU_CONF.'template_lang/'.$conf['template'].'/'.$conf['lang'].'/'.$id.'.txt';
1299
    if (!file_exists($file)){
1300
        $file = $path.$conf['lang'].'/'.$id.'.txt';
1301
        if(!file_exists($file)){
1302
            //fall back to english
1303
            $file = $path.'en/'.$id.'.txt';
1304
        }
1305
    }
1306
    return $file;
1307
}
1308
1309
/**
1310
 * prints the "main content" in the mediamanager popup
1311
 *
1312
 * Depending on the user's actions this may be a list of
1313
 * files in a namespace, the meta editing dialog or
1314
 * a message of referencing pages
1315
 *
1316
 * Only allowed in mediamanager.php
1317
 *
1318
 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1319
 * @param bool $fromajax - set true when calling this function via ajax
1320
 * @param string $sort
1321
 *
1322
 * @author Andreas Gohr <[email protected]>
1323
 */
1324
function tpl_mediaContent($fromajax = false, $sort='natural') {
1325
    global $IMG;
1326
    global $AUTH;
1327
    global $INUSE;
1328
    global $NS;
1329
    global $JUMPTO;
1330
    /** @var Input $INPUT */
1331
    global $INPUT;
1332
1333
    $do = $INPUT->extract('do')->str('do');
1334
    if(in_array($do, array('save', 'cancel'))) $do = '';
1335
1336
    if(!$do) {
1337
        if($INPUT->bool('edit')) {
1338
            $do = 'metaform';
1339
        } elseif(is_array($INUSE)) {
1340
            $do = 'filesinuse';
1341
        } else {
1342
            $do = 'filelist';
1343
        }
1344
    }
1345
1346
    // output the content pane, wrapped in an event.
1347
    if(!$fromajax) ptln('<div id="media__content">');
1348
    $data = array('do' => $do);
1349
    $evt  = new Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1350
    if($evt->advise_before()) {
1351
        $do = $data['do'];
1352
        if($do == 'filesinuse') {
1353
            media_filesinuse($INUSE, $IMG);
1354
        } elseif($do == 'filelist') {
1355
            media_filelist($NS, $AUTH, $JUMPTO,false,$sort);
1356
        } elseif($do == 'searchlist') {
1357
            media_searchlist($INPUT->str('q'), $NS, $AUTH);
1358
        } else {
1359
            msg('Unknown action '.hsc($do), -1);
1360
        }
1361
    }
1362
    $evt->advise_after();
1363
    unset($evt);
1364
    if(!$fromajax) ptln('</div>');
1365
1366
}
1367
1368
/**
1369
 * Prints the central column in full-screen media manager
1370
 * Depending on the opened tab this may be a list of
1371
 * files in a namespace, upload form or search form
1372
 *
1373
 * @author Kate Arzamastseva <[email protected]>
1374
 */
1375
function tpl_mediaFileList() {
1376
    global $AUTH;
1377
    global $NS;
1378
    global $JUMPTO;
1379
    global $lang;
1380
    /** @var Input $INPUT */
1381
    global $INPUT;
1382
1383
    $opened_tab = $INPUT->str('tab_files');
1384
    if(!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files';
1385
    if($INPUT->str('mediado') == 'update') $opened_tab = 'upload';
1386
1387
    echo '<h2 class="a11y">'.$lang['mediaselect'].'</h2>'.NL;
1388
1389
    media_tabs_files($opened_tab);
1390
1391
    echo '<div class="panelHeader">'.NL;
1392
    echo '<h3>';
1393
    $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']';
1394
    printf($lang['media_'.$opened_tab], '<strong>'.hsc($tabTitle).'</strong>');
1395
    echo '</h3>'.NL;
1396
    if($opened_tab === 'search' || $opened_tab === 'files') {
1397
        media_tab_files_options();
1398
    }
1399
    echo '</div>'.NL;
1400
1401
    echo '<div class="panelContent">'.NL;
1402
    if($opened_tab == 'files') {
1403
        media_tab_files($NS, $AUTH, $JUMPTO);
1404
    } elseif($opened_tab == 'upload') {
1405
        media_tab_upload($NS, $AUTH, $JUMPTO);
1406
    } elseif($opened_tab == 'search') {
1407
        media_tab_search($NS, $AUTH);
1408
    }
1409
    echo '</div>'.NL;
1410
}
1411
1412
/**
1413
 * Prints the third column in full-screen media manager
1414
 * Depending on the opened tab this may be details of the
1415
 * selected file, the meta editing dialog or
1416
 * list of file revisions
1417
 *
1418
 * @author Kate Arzamastseva <[email protected]>
1419
 *
1420
 * @param string $image
1421
 * @param boolean $rev
1422
 */
1423
function tpl_mediaFileDetails($image, $rev) {
1424
    global $conf, $DEL, $lang;
1425
    /** @var Input $INPUT */
1426
    global $INPUT;
1427
1428
    $removed = (
1429
        !file_exists(mediaFN($image)) &&
1430
        file_exists(mediaMetaFN($image, '.changes')) &&
1431
        $conf['mediarevisions']
1432
    );
1433
    if(!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return;
1434
    if($rev && !file_exists(mediaFN($image, $rev))) $rev = false;
0 ignored issues
show
Documentation introduced by
$rev is of type boolean, but the function expects a string|integer.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1435
    $ns = getNS($image);
1436
    $do = $INPUT->str('mediado');
1437
1438
    $opened_tab = $INPUT->str('tab_details');
1439
1440
    $tab_array = array('view');
1441
    list(, $mime) = mimetype($image);
1442
    if($mime == 'image/jpeg') {
1443
        $tab_array[] = 'edit';
1444
    }
1445
    if($conf['mediarevisions']) {
1446
        $tab_array[] = 'history';
1447
    }
1448
1449
    if(!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view';
1450
    if($INPUT->bool('edit')) $opened_tab = 'edit';
1451
    if($do == 'restore') $opened_tab = 'view';
1452
1453
    media_tabs_details($image, $opened_tab);
1454
1455
    echo '<div class="panelHeader"><h3>';
1456
    list($ext) = mimetype($image, false);
1457
    $class    = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
1458
    $class    = 'select mediafile mf_'.$class;
1459
    $attributes = $rev ? ['rev' => $rev] : [];
1460
    $tabTitle = '<strong><a href="'.ml($image, $attributes).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.
1461
        $image.'</a>'.'</strong>';
1462
    if($opened_tab === 'view' && $rev) {
1463
        printf($lang['media_viewold'], $tabTitle, dformat($rev));
0 ignored issues
show
Documentation introduced by
$rev is of type boolean, but the function expects a integer|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1464
    } else {
1465
        printf($lang['media_'.$opened_tab], $tabTitle);
1466
    }
1467
1468
    echo '</h3></div>'.NL;
1469
1470
    echo '<div class="panelContent">'.NL;
1471
1472
    if($opened_tab == 'view') {
1473
        media_tab_view($image, $ns, null, $rev);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1435 can also be of type false; however, media_tab_view() does only seem to accept string, did you maybe forget to handle an error condition?

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

Consider the follow example

<?php

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

    return false;
}

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

Loading history...
Documentation introduced by
$rev is of type boolean, but the function expects a string|integer.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1474
1475
    } elseif($opened_tab == 'edit' && !$removed) {
1476
        media_tab_edit($image, $ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns defined by getNS($image) on line 1435 can also be of type false; however, media_tab_edit() does only seem to accept string, did you maybe forget to handle an error condition?

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

Consider the follow example

<?php

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

    return false;
}

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

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

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

Consider the follow example

<?php

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

    return false;
}

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

Loading history...
1480
    }
1481
1482
    echo '</div>'.NL;
1483
}
1484
1485
/**
1486
 * prints the namespace tree in the mediamanager popup
1487
 *
1488
 * Only allowed in mediamanager.php
1489
 *
1490
 * @author Andreas Gohr <[email protected]>
1491
 */
1492
function tpl_mediaTree() {
1493
    global $NS;
1494
    ptln('<div id="media__tree">');
1495
    media_nstree($NS);
1496
    ptln('</div>');
1497
}
1498
1499
/**
1500
 * Print a dropdown menu with all DokuWiki actions
1501
 *
1502
 * Note: this will not use any pretty URLs
1503
 *
1504
 * @author Andreas Gohr <[email protected]>
1505
 *
1506
 * @param string $empty empty option label
1507
 * @param string $button submit button label
1508
 * @deprecated 2017-09-01 see devel:menus
1509
 */
1510
function tpl_actiondropdown($empty = '', $button = '&gt;') {
1511
    dbg_deprecated('see devel:menus');
1512
    $menu = new \dokuwiki\Menu\MobileMenu();
1513
    echo $menu->getDropdown($empty, $button);
1514
}
1515
1516
/**
1517
 * Print a informational line about the used license
1518
 *
1519
 * @author Andreas Gohr <[email protected]>
1520
 * @param  string $img     print image? (|button|badge)
1521
 * @param  bool   $imgonly skip the textual description?
1522
 * @param  bool   $return  when true don't print, but return HTML
1523
 * @param  bool   $wrap    wrap in div with class="license"?
1524
 * @return string
1525
 */
1526
function tpl_license($img = 'badge', $imgonly = false, $return = false, $wrap = true) {
1527
    global $license;
1528
    global $conf;
1529
    global $lang;
1530
    if(!$conf['license']) return '';
1531
    if(!is_array($license[$conf['license']])) return '';
1532
    $lic    = $license[$conf['license']];
1533
    $target = ($conf['target']['extern']) ? ' target="'.$conf['target']['extern'].'"' : '';
1534
1535
    $out = '';
1536
    if($wrap) $out .= '<div class="license">';
1537
    if($img) {
1538
        $src = license_img($img);
1539
        if($src) {
1540
            $out .= '<a href="'.$lic['url'].'" rel="license"'.$target;
1541
            $out .= '><img src="'.DOKU_BASE.$src.'" alt="'.$lic['name'].'" /></a>';
1542
            if(!$imgonly) $out .= ' ';
1543
        }
1544
    }
1545
    if(!$imgonly) {
1546
        $out .= $lang['license'].' ';
1547
        $out .= '<bdi><a href="'.$lic['url'].'" rel="license" class="urlextern"'.$target;
1548
        $out .= '>'.$lic['name'].'</a></bdi>';
1549
    }
1550
    if($wrap) $out .= '</div>';
1551
1552
    if($return) return $out;
1553
    echo $out;
1554
    return '';
1555
}
1556
1557
/**
1558
 * Includes the rendered HTML of a given page
1559
 *
1560
 * This function is useful to populate sidebars or similar features in a
1561
 * template
1562
 *
1563
 * @param string $pageid The page name you want to include
1564
 * @param bool $print Should the content be printed or returned only
1565
 * @param bool $propagate Search higher namespaces, too?
1566
 * @param bool $useacl Include the page only if the ACLs check out?
1567
 * @return bool|null|string
1568
 */
1569
function tpl_include_page($pageid, $print = true, $propagate = false, $useacl = true) {
1570
    if($propagate) {
1571
        $pageid = page_findnearest($pageid, $useacl);
1572
    } elseif($useacl && auth_quickaclcheck($pageid) == AUTH_NONE) {
1573
        return false;
1574
    }
1575
    if(!$pageid) return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $pageid of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1576
1577
    global $TOC;
1578
    $oldtoc = $TOC;
1579
    $html   = p_wiki_xhtml($pageid, '', false);
1580
    $TOC    = $oldtoc;
1581
1582
    if($print) echo $html;
1583
    return $html;
1584
}
1585
1586
/**
1587
 * Display the subscribe form
1588
 *
1589
 * @author Adrian Lang <[email protected]>
1590
 * @deprecated 2020-07-23
1591
 */
1592
function tpl_subscribe() {
1593
    dbg_deprecated(\dokuwiki\Ui\Subscribe::class .'::show()');
1594
    (new \dokuwiki\Ui\Subscribe)->show();
1595
}
1596
1597
/**
1598
 * Tries to send already created content right to the browser
1599
 *
1600
 * Wraps around ob_flush() and flush()
1601
 *
1602
 * @author Andreas Gohr <[email protected]>
1603
 */
1604
function tpl_flush() {
1605
    if( ob_get_level() > 0 ) ob_flush();
1606
    flush();
1607
}
1608
1609
/**
1610
 * Tries to find a ressource file in the given locations.
1611
 *
1612
 * If a given location starts with a colon it is assumed to be a media
1613
 * file, otherwise it is assumed to be relative to the current template
1614
 *
1615
 * @param  string[] $search       locations to look at
1616
 * @param  bool     $abs          if to use absolute URL
1617
 * @param  array    &$imginfo     filled with getimagesize()
1618
 * @param  bool     $fallback     use fallback image if target isn't found or return 'false' if potential
1619
 *                                false result is required
1620
 * @return string
1621
 *
1622
 * @author Andreas  Gohr <[email protected]>
1623
 */
1624
function tpl_getMediaFile($search, $abs = false, &$imginfo = null, $fallback = true) {
1625
    $img     = '';
1626
    $file    = '';
1627
    $ismedia = false;
1628
    // loop through candidates until a match was found:
1629
    foreach($search as $img) {
1630
        if(substr($img, 0, 1) == ':') {
1631
            $file    = mediaFN($img);
1632
            $ismedia = true;
1633
        } else {
1634
            $file    = tpl_incdir().$img;
1635
            $ismedia = false;
1636
        }
1637
1638
        if(file_exists($file)) break;
1639
    }
1640
1641
    // manage non existing target
1642
    if (!file_exists($file)) {
1643
        // give result for fallback image
1644
        if ($fallback === true) {
1645
            $file = DOKU_INC . 'lib/images/blank.gif';
1646
            // stop process if false result is required (if $fallback is false)
1647
        } else {
1648
            return false;
1649
        }
1650
    }
1651
1652
    // fetch image data if requested
1653
    if(!is_null($imginfo)) {
1654
        $imginfo = getimagesize($file);
1655
    }
1656
1657
    // build URL
1658
    if($ismedia) {
1659
        $url = ml($img, '', true, '', $abs);
1660
    } else {
1661
        $url = tpl_basedir().$img;
1662
        if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL));
1663
    }
1664
1665
    return $url;
1666
}
1667
1668
/**
1669
 * PHP include a file
1670
 *
1671
 * either from the conf directory if it exists, otherwise use
1672
 * file in the template's root directory.
1673
 *
1674
 * The function honours config cascade settings and looks for the given
1675
 * file next to the ´main´ config files, in the order protected, local,
1676
 * default.
1677
 *
1678
 * Note: no escaping or sanity checking is done here. Never pass user input
1679
 * to this function!
1680
 *
1681
 * @author Anika Henke <[email protected]>
1682
 * @author Andreas Gohr <[email protected]>
1683
 *
1684
 * @param string $file
1685
 */
1686
function tpl_includeFile($file) {
1687
    global $config_cascade;
1688
    foreach(array('protected', 'local', 'default') as $config_group) {
1689
        if(empty($config_cascade['main'][$config_group])) continue;
1690
        foreach($config_cascade['main'][$config_group] as $conf_file) {
1691
            $dir = dirname($conf_file);
1692
            if(file_exists("$dir/$file")) {
1693
                include("$dir/$file");
1694
                return;
1695
            }
1696
        }
1697
    }
1698
1699
    // still here? try the template dir
1700
    $file = tpl_incdir().$file;
1701
    if(file_exists($file)) {
1702
        include($file);
1703
    }
1704
}
1705
1706
/**
1707
 * Returns <link> tag for various icon types (favicon|mobile|generic)
1708
 *
1709
 * @author Anika Henke <[email protected]>
1710
 *
1711
 * @param  array $types - list of icon types to display (favicon|mobile|generic)
1712
 * @return string
1713
 */
1714
function tpl_favicon($types = array('favicon')) {
1715
1716
    $return = '';
1717
1718
    foreach($types as $type) {
1719
        switch($type) {
1720
            case 'favicon':
1721
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
1722
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1723
                break;
1724
            case 'mobile':
1725
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
1726
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
1727
                break;
1728
            case 'generic':
1729
                // ideal world solution, which doesn't work in any browser yet
1730
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
1731
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
1732
                break;
1733
        }
1734
    }
1735
1736
    return $return;
1737
}
1738
1739
/**
1740
 * Prints full-screen media manager
1741
 *
1742
 * @author Kate Arzamastseva <[email protected]>
1743
 */
1744
function tpl_media() {
1745
    global $NS, $IMG, $JUMPTO, $REV, $lang, $fullscreen, $INPUT;
1746
    $fullscreen = true;
1747
    require_once DOKU_INC.'lib/exe/mediamanager.php';
1748
1749
    $rev   = '';
1750
    $image = cleanID($INPUT->str('image'));
1751
    if(isset($IMG)) $image = $IMG;
1752
    if(isset($JUMPTO)) $image = $JUMPTO;
1753
    if(isset($REV) && !$JUMPTO) $rev = $REV;
1754
1755
    echo '<div id="mediamanager__page">'.NL;
1756
    echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1757
    html_msgarea();
1758
1759
    echo '<div class="panel namespaces">'.NL;
1760
    echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1761
    echo '<div class="panelHeader">';
1762
    echo $lang['media_namespaces'];
1763
    echo '</div>'.NL;
1764
1765
    echo '<div class="panelContent" id="media__tree">'.NL;
1766
    media_nstree($NS);
1767
    echo '</div>'.NL;
1768
    echo '</div>'.NL;
1769
1770
    echo '<div class="panel filelist">'.NL;
1771
    tpl_mediaFileList();
1772
    echo '</div>'.NL;
1773
1774
    echo '<div class="panel file">'.NL;
1775
    echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1776
    tpl_mediaFileDetails($image, $rev);
1777
    echo '</div>'.NL;
1778
1779
    echo '</div>'.NL;
1780
}
1781
1782
/**
1783
 * Return useful layout classes
1784
 *
1785
 * @author Anika Henke <[email protected]>
1786
 *
1787
 * @return string
1788
 */
1789
function tpl_classes() {
1790
    global $ACT, $conf, $ID, $INFO;
1791
    /** @var Input $INPUT */
1792
    global $INPUT;
1793
1794
    $classes = array(
1795
        'dokuwiki',
1796
        'mode_'.$ACT,
1797
        'tpl_'.$conf['template'],
1798
        $INPUT->server->bool('REMOTE_USER') ? 'loggedIn' : '',
1799
        (isset($INFO) && $INFO['exists']) ? '' : 'notFound',
1800
        ($ID == $conf['start']) ? 'home' : '',
1801
    );
1802
    return join(' ', $classes);
1803
}
1804
1805
/**
1806
 * Create event for tools menues
1807
 *
1808
 * @author Anika Henke <[email protected]>
1809
 * @param string $toolsname name of menu
1810
 * @param array $items
1811
 * @param string $view e.g. 'main', 'detail', ...
1812
 * @deprecated 2017-09-01 see devel:menus
1813
 */
1814
function tpl_toolsevent($toolsname, $items, $view = 'main') {
1815
    dbg_deprecated('see devel:menus');
1816
    $data = array(
1817
        'view' => $view,
1818
        'items' => $items
1819
    );
1820
1821
    $hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
1822
    $evt = new Event($hook, $data);
1823
    if($evt->advise_before()) {
1824
        foreach($evt->data['items'] as $k => $html) echo $html;
1825
    }
1826
    $evt->advise_after();
1827
}
1828
1829
//Setup VIM: ex: et ts=4 :
1830
1831