Failed Conditions
Push — master ( cbaf27...ca549e )
by Andreas
04:42
created

template.php ➔ tpl_pagetitle()   F

Complexity

Conditions 19
Paths 180

Size

Total Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
nc 180
nop 2
dl 0
loc 67
rs 3.85
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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