Failed Conditions
Push — oldmediaonrev ( 996e87...cfefec )
by Andreas
06:59 queued 03:56
created

html.php ➔ html_btn()   B

Complexity

Conditions 9
Paths 96

Size

Total Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 96
nop 8
dl 0
loc 54
rs 7.448
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * HTML output 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
if(!defined('NL')) define('NL',"\n");
11
if (!defined('SEC_EDIT_PATTERN')) {
12
    define('SEC_EDIT_PATTERN', '#<!-- EDIT({.*?}) -->#');
13
}
14
15
16
/**
17
 * Convenience function to quickly build a wikilink
18
 *
19
 * @author Andreas Gohr <[email protected]>
20
 * @param string  $id      id of the target page
21
 * @param string  $name    the name of the link, i.e. the text that is displayed
22
 * @param string|array  $search  search string(s) that shall be highlighted in the target page
23
 * @return string the HTML code of the link
24
 */
25
function html_wikilink($id,$name=null,$search=''){
26
    /** @var Doku_Renderer_xhtml $xhtml_renderer */
27
    static $xhtml_renderer = null;
28
    if(is_null($xhtml_renderer)){
29
        $xhtml_renderer = p_get_renderer('xhtml');
30
    }
31
32
    return $xhtml_renderer->internallink($id,$name,$search,true,'navigation');
33
}
34
35
/**
36
 * The loginform
37
 *
38
 * @author   Andreas Gohr <[email protected]>
39
 *
40
 * @param bool $svg Whether to show svg icons in the register and resendpwd links or not
41
 */
42
function html_login($svg = false){
43
    global $lang;
44
    global $conf;
45
    global $ID;
46
    global $INPUT;
47
48
    print p_locale_xhtml('login');
49
    print '<div class="centeralign">'.NL;
50
    $form = new Doku_Form(array('id' => 'dw__login'));
51
    $form->startFieldset($lang['btn_login']);
52
    $form->addHidden('id', $ID);
53
    $form->addHidden('do', 'login');
54
    $form->addElement(form_makeTextField('u', ((!$INPUT->bool('http_credentials')) ? $INPUT->str('u') : ''), $lang['user'], 'focus__this', 'block'));
55
    $form->addElement(form_makePasswordField('p', $lang['pass'], '', 'block'));
56
    if($conf['rememberme']) {
57
        $form->addElement(form_makeCheckboxField('r', '1', $lang['remember'], 'remember__me', 'simple'));
58
    }
59
    $form->addElement(form_makeButton('submit', '', $lang['btn_login']));
60
    $form->endFieldset();
61
62
    if(actionOK('register')){
63
        $registerLink = (new \dokuwiki\Menu\Item\Register())->asHtmlLink('', $svg);
64
        $form->addElement('<p>'.$lang['reghere'].': '. $registerLink .'</p>');
65
    }
66
67
    if (actionOK('resendpwd')) {
68
        $resendPwLink = (new \dokuwiki\Menu\Item\Resendpwd())->asHtmlLink('', $svg);
69
        $form->addElement('<p>'.$lang['pwdforget'].': '. $resendPwLink .'</p>');
70
    }
71
72
    html_form('login', $form);
73
    print '</div>'.NL;
74
}
75
76
77
/**
78
 * Denied page content
79
 *
80
 * @return string html
81
 */
82
function html_denied() {
83
    print p_locale_xhtml('denied');
84
85
    if(empty($_SERVER['REMOTE_USER']) && actionOK('login')){
86
        html_login();
87
    }
88
}
89
90
/**
91
 * inserts section edit buttons if wanted or removes the markers
92
 *
93
 * @author Andreas Gohr <[email protected]>
94
 *
95
 * @param string $text
96
 * @param bool   $show show section edit buttons?
97
 * @return string
98
 */
99
function html_secedit($text,$show=true){
100
    global $INFO;
101
102
    if(!$INFO['writable'] || !$show || $INFO['rev']){
103
        return preg_replace(SEC_EDIT_PATTERN,'',$text);
104
    }
105
106
    return preg_replace_callback(SEC_EDIT_PATTERN,
107
                'html_secedit_button', $text);
108
}
109
110
/**
111
 * prepares section edit button data for event triggering
112
 * used as a callback in html_secedit
113
 *
114
 * @author Andreas Gohr <[email protected]>
115
 *
116
 * @param array $matches matches with regexp
117
 * @return string
118
 * @triggers HTML_SECEDIT_BUTTON
119
 */
120
function html_secedit_button($matches){
121
    $json = htmlspecialchars_decode($matches[1], ENT_QUOTES);
122
    $data = json_decode($json, true);
123
    if ($data == NULL) {
124
        return;
125
    }
126
    $data ['target'] = strtolower($data['target']);
127
    $data ['hid'] = strtolower($data['hid']);
128
129
    return trigger_event('HTML_SECEDIT_BUTTON', $data,
130
                         'html_secedit_get_button');
131
}
132
133
/**
134
 * prints a section editing button
135
 * used as default action form HTML_SECEDIT_BUTTON
136
 *
137
 * @author Adrian Lang <[email protected]>
138
 *
139
 * @param array $data name, section id and target
140
 * @return string html
141
 */
142
function html_secedit_get_button($data) {
143
    global $ID;
144
    global $INFO;
145
146
    if (!isset($data['name']) || $data['name'] === '') return '';
147
148
    $name = $data['name'];
149
    unset($data['name']);
150
151
    $secid = $data['secid'];
152
    unset($data['secid']);
153
154
    return "<div class='secedit editbutton_" . $data['target'] .
155
                       " editbutton_" . $secid . "'>" .
156
           html_btn('secedit', $ID, '',
157
                    array_merge(array('do'  => 'edit',
158
                                      'rev' => $INFO['lastmod'],
159
                                      'summary' => '['.$name.'] '), $data),
160
                    'post', $name) . '</div>';
161
}
162
163
/**
164
 * Just the back to top button (in its own form)
165
 *
166
 * @author Andreas Gohr <[email protected]>
167
 *
168
 * @return string html
169
 */
170
function html_topbtn(){
171
    global $lang;
172
173
    $ret  = '<a class="nolink" href="#dokuwiki__top"><button class="button" onclick="window.scrollTo(0, 0)" title="'.$lang['btn_top'].'">'.$lang['btn_top'].'</button></a>';
174
175
    return $ret;
176
}
177
178
/**
179
 * Displays a button (using its own form)
180
 * If tooltip exists, the access key tooltip is replaced.
181
 *
182
 * @author Andreas Gohr <[email protected]>
183
 *
184
 * @param string         $name
185
 * @param string         $id
186
 * @param string         $akey   access key
187
 * @param string[] $params key-value pairs added as hidden inputs
188
 * @param string         $method
189
 * @param string         $tooltip
190
 * @param bool|string    $label  label text, false: lookup btn_$name in localization
191
 * @param string         $svg (optional) svg code, inserted into the button
192
 * @return string
193
 */
194
function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label=false, $svg=null){
195
    global $conf;
196
    global $lang;
197
198
    if (!$label)
199
        $label = $lang['btn_'.$name];
200
201
    $ret = '';
202
203
    //filter id (without urlencoding)
204
    $id = idfilter($id,false);
205
206
    //make nice URLs even for buttons
207
    if($conf['userewrite'] == 2){
208
        $script = DOKU_BASE.DOKU_SCRIPT.'/'.$id;
209
    }elseif($conf['userewrite']){
210
        $script = DOKU_BASE.$id;
211
    }else{
212
        $script = DOKU_BASE.DOKU_SCRIPT;
213
        $params['id'] = $id;
214
    }
215
216
    $ret .= '<form class="button btn_'.$name.'" method="'.$method.'" action="'.$script.'"><div class="no">';
217
218
    if(is_array($params)){
219
        foreach($params as $key => $val) {
220
            $ret .= '<input type="hidden" name="'.$key.'" ';
221
            $ret .= 'value="'.hsc($val).'" />';
222
        }
223
    }
224
225
    if ($tooltip!='') {
226
        $tip = hsc($tooltip);
227
    }else{
228
        $tip = hsc($label);
229
    }
230
231
    $ret .= '<button type="submit" ';
232
    if($akey){
233
        $tip .= ' ['.strtoupper($akey).']';
234
        $ret .= 'accesskey="'.$akey.'" ';
235
    }
236
    $ret .= 'title="'.$tip.'">';
237
    if ($svg) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $svg 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...
238
        $ret .= '<span>' . hsc($label) . '</span>';
239
        $ret .= inlineSVG($svg);
240
    } else {
241
        $ret .= hsc($label);
242
    }
243
    $ret .= '</button>';
244
    $ret .= '</div></form>';
245
246
    return $ret;
247
}
248
/**
249
 * show a revision warning
250
 *
251
 * @author Szymon Olewniczak <[email protected]>
252
 */
253
function html_showrev() {
254
    print p_locale_xhtml('showrev');
255
}
256
257
/**
258
 * Show a wiki page
259
 *
260
 * @author Andreas Gohr <[email protected]>
261
 *
262
 * @param null|string $txt wiki text or null for showing $ID
263
 */
264
function html_show($txt=null){
265
    global $ID;
266
    global $REV;
267
    global $HIGH;
268
    global $INFO;
269
    global $DATE_AT;
270
    //disable section editing for old revisions or in preview
271
    if($txt || $REV){
0 ignored issues
show
Bug Best Practice introduced by
The expression $txt of type null|string 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...
272
        $secedit = false;
273
    }else{
274
        $secedit = true;
275
    }
276
277
    if (!is_null($txt)){
278
        //PreviewHeader
279
        echo '<br id="scroll__here" />';
280
        echo p_locale_xhtml('preview');
281
        echo '<div class="preview"><div class="pad">';
282
        $html = html_secedit(p_render('xhtml',p_get_instructions($txt),$info),$secedit);
283
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
284
        echo $html;
285
        echo '<div class="clearer"></div>';
286
        echo '</div></div>';
287
288
    }else{
289
        if ($REV||$DATE_AT){
290
            $data = array('rev' => &$REV, 'date_at' => &$DATE_AT);
291
            trigger_event('HTML_SHOWREV_OUTPUT', $data, 'html_showrev');
292
        }
293
        $html = p_wiki_xhtml($ID,$REV,true,$DATE_AT);
294
        $html = html_secedit($html,$secedit);
0 ignored issues
show
Bug introduced by
It seems like $html can also be of type boolean or null; however, html_secedit() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
295
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
296
        $html = html_hilight($html,$HIGH);
297
        echo $html;
298
    }
299
}
300
301
/**
302
 * ask the user about how to handle an exisiting draft
303
 *
304
 * @author Andreas Gohr <[email protected]>
305
 */
306
function html_draft(){
307
    global $INFO;
308
    global $ID;
309
    global $lang;
310
    $draft = new \dokuwiki\Draft($ID, $INFO['client']);
311
    $text  = $draft->getDraftText();
312
313
    print p_locale_xhtml('draft');
314
    html_diff($text, false);
315
    $form = new Doku_Form(array('id' => 'dw__editform'));
316
    $form->addHidden('id', $ID);
317
    $form->addHidden('date', $draft->getDraftDate());
318
    $form->addHidden('wikitext', $text);
319
    $form->addElement(form_makeOpenTag('div', array('id'=>'draft__status')));
320
    $form->addElement($draft->getDraftMessage());
321
    $form->addElement(form_makeCloseTag('div'));
322
    $form->addElement(form_makeButton('submit', 'recover', $lang['btn_recover'], array('tabindex'=>'1')));
323
    $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_draftdel'], array('tabindex'=>'2')));
324
    $form->addElement(form_makeButton('submit', 'show', $lang['btn_cancel'], array('tabindex'=>'3')));
325
    html_form('draft', $form);
326
}
327
328
/**
329
 * Highlights searchqueries in HTML code
330
 *
331
 * @author Andreas Gohr <[email protected]>
332
 * @author Harry Fuecks <[email protected]>
333
 *
334
 * @param string $html
335
 * @param array|string $phrases
336
 * @return string html
337
 */
338
function html_hilight($html,$phrases){
339
    $phrases = (array) $phrases;
340
    $phrases = array_map('preg_quote_cb', $phrases);
341
    $phrases = array_map('ft_snippet_re_preprocess', $phrases);
342
    $phrases = array_filter($phrases);
343
    $regex = join('|',$phrases);
344
345
    if ($regex === '') return $html;
346
    if (!utf8_check($regex)) return $html;
347
    $html = @preg_replace_callback("/((<[^>]*)|$regex)/ui",'html_hilight_callback',$html);
348
    return $html;
349
}
350
351
/**
352
 * Callback used by html_hilight()
353
 *
354
 * @author Harry Fuecks <[email protected]>
355
 *
356
 * @param array $m matches
357
 * @return string html
358
 */
359
function html_hilight_callback($m) {
360
    $hlight = unslash($m[0]);
361
    if ( !isset($m[2])) {
362
        $hlight = '<span class="search_hit">'.$hlight.'</span>';
363
    }
364
    return $hlight;
365
}
366
367
/**
368
 * Display error on locked pages
369
 *
370
 * @author Andreas Gohr <[email protected]>
371
 */
372
function html_locked(){
373
    global $ID;
374
    global $conf;
375
    global $lang;
376
    global $INFO;
377
378
    $locktime = filemtime(wikiLockFN($ID));
379
    $expire = dformat($locktime + $conf['locktime']);
380
    $min    = round(($conf['locktime'] - (time() - $locktime) )/60);
381
382
    print p_locale_xhtml('locked');
383
    print '<ul>';
384
    print '<li><div class="li"><strong>'.$lang['lockedby'].'</strong> '.editorinfo($INFO['locked']).'</div></li>';
385
    print '<li><div class="li"><strong>'.$lang['lockexpire'].'</strong> '.$expire.' ('.$min.' min)</div></li>';
386
    print '</ul>';
387
}
388
389
/**
390
 * Return the link to old page or media revision
391
 *
392
 * @author Szymon Olewniczak <[email protected]>
393
 *
394
 * @param $id
395
 * @param $rev
396
 * @param $separator
397
 * @param $func may be "wl" or "ml"
398
 * @return string
399
 */
400
function html_revision_link($id, $rev, $func='wl', $separator='&amp;') {
401
    global $conf;
402
403
    if ($func !== 'wl' && $func !== 'ml') {
404
        msg('html_revision_link: $func should be "wl" or "ml". falling back to "wl"', -1);
405
        $func = 'wl';
406
    }
407
408
    $rev_var = 'rev';
409
    if ($conf['rev_handle'] != 'normal') {
410
        $rev_var = 'at';
411
    }
412
413
    $urlParameters = "$rev_var=$rev";
414
    if ($func === 'wl') {
415
        //function wl($id = '', $urlParameters = '', $absolute = false, $separator = '&amp;')
416
        return wl($id, $urlParameters, false, $separator);
417
    } elseif ($func == 'ml') {
418
        //functin ml($id = '', $more = '', $direct = true, $sep = '&amp;', $abs = false)
419
        return ml($id, $urlParameters, true, $separator, false);
420
    }
421
}
422
423
/**
424
 * list old revisions
425
 *
426
 * @author Andreas Gohr <[email protected]>
427
 * @author Ben Coburn <[email protected]>
428
 * @author Kate Arzamastseva <[email protected]>
429
 *
430
 * @param int $first skip the first n changelog lines
431
 * @param bool|string $media_id id of media, or false for current page
432
 */
433
function html_revisions($first=0, $media_id = false){
434
    global $ID;
435
    global $INFO;
436
    global $conf;
437
    global $lang;
438
    $id = $ID;
439
    if ($media_id) {
440
        $id = $media_id;
441
        $changelog = new MediaChangeLog($id);
442
    } else {
443
        $changelog = new PageChangeLog($id);
444
    }
445
446
    /* we need to get one additional log entry to be able to
447
     * decide if this is the last page or is there another one.
448
     * see html_recent()
449
     */
450
451
    $revisions = $changelog->getRevisions($first, $conf['recent']+1);
452
453
    if(count($revisions)==0 && $first!=0){
454
        $first=0;
455
        $revisions = $changelog->getRevisions($first, $conf['recent']+1);
456
    }
457
    $hasNext = false;
458
    if (count($revisions)>$conf['recent']) {
459
        $hasNext = true;
460
        array_pop($revisions); // remove extra log entry
461
    }
462
463
    if (!$media_id) print p_locale_xhtml('revisions');
464
465
    $params = array('id' => 'page__revisions', 'class' => 'changes');
466
    if($media_id) {
467
        $params['action'] = media_managerURL(array('image' => $media_id), '&');
468
    }
469
470
    if(!$media_id) {
471
        $exists = $INFO['exists'];
472
        $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
473
        if(!$display_name) {
474
            $display_name = $id;
475
        }
476
    } else {
477
        $exists = file_exists(mediaFN($id));
478
        $display_name = $id;
479
    }
480
481
    $form = new Doku_Form($params);
482
    $form->addElement(form_makeOpenTag('ul'));
483
484
    if($exists && $first == 0) {
485
        $minor = false;
486
        if($media_id) {
487
            $date = dformat(@filemtime(mediaFN($id)));
488
            $href = media_managerURL(array('image' => $id, 'tab_details' => 'view'), '&');
489
490
            $changelog->setChunkSize(1024);
491
            $revinfo = $changelog->getRevisionInfo(@filemtime(fullpath(mediaFN($id))));
492
493
            $summary = $revinfo['sum'];
494
            if($revinfo['user']) {
495
                $editor = $revinfo['user'];
496
            } else {
497
                $editor = $revinfo['ip'];
498
            }
499
            $sizechange = $revinfo['sizechange'];
500
        } else {
501
            $date = dformat($INFO['lastmod']);
502
            if(isset($INFO['meta']) && isset($INFO['meta']['last_change'])) {
503
                if($INFO['meta']['last_change']['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
504
                    $minor = true;
505
                }
506
                if(isset($INFO['meta']['last_change']['sizechange'])) {
507
                    $sizechange = $INFO['meta']['last_change']['sizechange'];
508
                } else {
509
                    $sizechange = null;
510
                }
511
            }
512
            $pagelog = new PageChangeLog($ID);
513
            $latestrev = $pagelog->getRevisions(-1, 1);
514
            $latestrev = array_pop($latestrev);
515
            $href = html_revision_link($id, $latestrev, 'wl', '&');
516
            $summary = $INFO['sum'];
517
            $editor = $INFO['editor'];
518
        }
519
520
        $form->addElement(form_makeOpenTag('li', array('class' => ($minor ? 'minor' : ''))));
521
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
522
        $form->addElement(form_makeTag('input', array(
523
                        'type' => 'checkbox',
524
                        'name' => 'rev2[]',
525
                        'value' => 'current')));
526
527
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
528
        $form->addElement($date);
529
        $form->addElement(form_makeCloseTag('span'));
530
531
        $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
532
533
        $form->addElement(form_makeOpenTag('a', array(
534
                        'class' => 'wikilink1',
535
                        'href'  => $href)));
536
        $form->addElement($display_name);
537
        $form->addElement(form_makeCloseTag('a'));
538
539
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
540
541
        if($summary) {
542
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
543
            if(!$media_id) $form->addElement(' – ');
544
            $form->addElement('<bdi>' . hsc($summary) . '</bdi>');
545
            $form->addElement(form_makeCloseTag('span'));
546
        }
547
548
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
549
        $form->addElement((empty($editor))?('('.$lang['external_edit'].')'):'<bdi>'.editorinfo($editor).'</bdi>');
550
        $form->addElement(form_makeCloseTag('span'));
551
552
        html_sizechange($sizechange, $form);
0 ignored issues
show
Bug introduced by
The variable $sizechange does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
553
554
        $form->addElement('('.$lang['current'].')');
555
556
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
557
558
        $form->addElement(form_makeCloseTag('div'));
559
        $form->addElement(form_makeCloseTag('li'));
560
    }
561
562
    foreach($revisions as $rev) {
563
        $date = dformat($rev);
564
        $info = $changelog->getRevisionInfo($rev);
565
        if($media_id) {
566
            $exists = file_exists(mediaFN($id, $rev));
567
        } else {
568
            $exists = page_exists($id, $rev);
569
        }
570
571
        $class = '';
572
        if($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
573
            $class = 'minor';
574
        }
575
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
576
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
577
        if($exists){
578
            $form->addElement(form_makeTag('input', array(
579
                            'type' => 'checkbox',
580
                            'name' => 'rev2[]',
581
                            'value' => $rev)));
582
        }else{
583
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
584
        }
585
586
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
587
        $form->addElement($date);
588
        $form->addElement(form_makeCloseTag('span'));
589
590
        if($exists){
591
            if (!$media_id) {
592
                $href = wl($id,"rev=$rev,do=diff", false, '&');
593
            } else {
594
                $href = media_managerURL(array('image' => $id, 'rev' => $rev, 'mediado' => 'diff'), '&');
595
            }
596
            $form->addElement(form_makeOpenTag('a', array(
597
                            'class' => 'diff_link',
598
                            'href' => $href)));
599
            $form->addElement(form_makeTag('img', array(
600
                            'src'    => DOKU_BASE.'lib/images/diff.png',
601
                            'width'  => 15,
602
                            'height' => 11,
603
                            'title'  => $lang['diff'],
604
                            'alt'    => $lang['diff'])));
605
            $form->addElement(form_makeCloseTag('a'));
606
607
            if (!$media_id) {
608
                $href = html_revision_link($id, $rev, 'wl','&');
609
            } else {
610
                $href = media_managerURL(array('image' => $id, 'tab_details' => 'view', 'rev' => $rev), '&');
611
            }
612
            $form->addElement(form_makeOpenTag('a', array(
613
                            'class' => 'wikilink1',
614
                            'href' => $href)));
615
            $form->addElement($display_name);
616
            $form->addElement(form_makeCloseTag('a'));
617
        }else{
618
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
619
            $form->addElement($display_name);
620
        }
621
622
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
623
624
        if ($info['sum']) {
625
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
626
            if(!$media_id) $form->addElement(' – ');
627
            $form->addElement('<bdi>'.hsc($info['sum']).'</bdi>');
628
            $form->addElement(form_makeCloseTag('span'));
629
        }
630
631
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
632
        if($info['user']){
633
            $form->addElement('<bdi>'.editorinfo($info['user']).'</bdi>');
634
            if(auth_ismanager()){
635
                $form->addElement(' <bdo dir="ltr">('.$info['ip'].')</bdo>');
636
            }
637
        }else{
638
            $form->addElement('<bdo dir="ltr">'.$info['ip'].'</bdo>');
639
        }
640
        $form->addElement(form_makeCloseTag('span'));
641
642
        html_sizechange($info['sizechange'], $form);
643
644
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
645
646
        $form->addElement(form_makeCloseTag('div'));
647
        $form->addElement(form_makeCloseTag('li'));
648
    }
649
    $form->addElement(form_makeCloseTag('ul'));
650
    if (!$media_id) {
651
        $form->addElement(form_makeButton('submit', 'diff', $lang['diff2']));
652
    } else {
653
        $form->addHidden('mediado', 'diff');
654
        $form->addElement(form_makeButton('submit', '', $lang['diff2']));
655
    }
656
    html_form('revisions', $form);
657
658
    print '<div class="pagenav">';
659
    $last = $first + $conf['recent'];
660
    if ($first > 0) {
661
        $first -= $conf['recent'];
662
        if ($first < 0) $first = 0;
663
        print '<div class="pagenav-prev">';
664
        if ($media_id) {
665
            print html_btn('newer',$media_id,"p",media_managerURL(array('first' => $first), '&amp;', false, true));
666
        } else {
667
            print html_btn('newer',$id,"p",array('do' => 'revisions', 'first' => $first));
668
        }
669
        print '</div>';
670
    }
671
    if ($hasNext) {
672
        print '<div class="pagenav-next">';
673
        if ($media_id) {
674
            print html_btn('older',$media_id,"n",media_managerURL(array('first' => $last), '&amp;', false, true));
675
        } else {
676
            print html_btn('older',$id,"n",array('do' => 'revisions', 'first' => $last));
677
        }
678
        print '</div>';
679
    }
680
    print '</div>';
681
682
}
683
684
/**
685
 * display recent changes
686
 *
687
 * @author Andreas Gohr <[email protected]>
688
 * @author Matthias Grimm <[email protected]>
689
 * @author Ben Coburn <[email protected]>
690
 * @author Kate Arzamastseva <[email protected]>
691
 *
692
 * @param int $first
693
 * @param string $show_changes
694
 */
695
function html_recent($first = 0, $show_changes = 'both') {
696
    global $conf;
697
    global $lang;
698
    global $ID;
699
    /* we need to get one additionally log entry to be able to
700
     * decide if this is the last page or is there another one.
701
     * This is the cheapest solution to get this information.
702
     */
703
    $flags = 0;
704
    if($show_changes == 'mediafiles' && $conf['mediarevisions']) {
705
        $flags = RECENTS_MEDIA_CHANGES;
706
    } elseif($show_changes == 'pages') {
707
        $flags = 0;
708
    } elseif($conf['mediarevisions']) {
709
        $show_changes = 'both';
710
        $flags = RECENTS_MEDIA_PAGES_MIXED;
711
    }
712
713
    $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, getRecents() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
714
    if(count($recents) == 0 && $first != 0) {
715
        $first = 0;
716
        $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, getRecents() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
717
    }
718
    $hasNext = false;
719
    if(count($recents) > $conf['recent']) {
720
        $hasNext = true;
721
        array_pop($recents); // remove extra log entry
722
    }
723
724
    print p_locale_xhtml('recent');
725
726
    if(getNS($ID) != '') {
727
        print '<div class="level1"><p>' . sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent')) . '</p></div>';
728
    }
729
730
    $form = new Doku_Form(array('id' => 'dw__recent', 'method' => 'GET', 'class' => 'changes'));
731
    $form->addHidden('sectok', null);
732
    $form->addHidden('do', 'recent');
733
    $form->addHidden('id', $ID);
734
735
    if($conf['mediarevisions']) {
736
        $form->addElement('<div class="changeType">');
737
        $form->addElement(form_makeListboxField(
738
                    'show_changes',
739
                    array(
740
                        'pages'      => $lang['pages_changes'],
741
                        'mediafiles' => $lang['media_changes'],
742
                        'both'       => $lang['both_changes']
743
                    ),
744
                    $show_changes,
745
                    $lang['changes_type'],
746
                    '', '',
747
                    array('class' => 'quickselect')));
748
749
        $form->addElement(form_makeButton('submit', 'recent', $lang['btn_apply']));
750
        $form->addElement('</div>');
751
    }
752
753
    $form->addElement(form_makeOpenTag('ul'));
754
755
    foreach($recents as $recent) {
756
        $date = dformat($recent['date']);
757
758
        $class = '';
759
        if($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
760
            $class = 'minor';
761
        }
762
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
763
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
764
765
        if(!empty($recent['media'])) {
766
            $form->addElement(media_printicon($recent['id']));
767
        } else {
768
            $icon = DOKU_BASE . 'lib/images/fileicons/file.png';
769
            $form->addElement('<img src="' . $icon . '" alt="' . $recent['id'] . '" class="icon" />');
770
        }
771
772
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
773
        $form->addElement($date);
774
        $form->addElement(form_makeCloseTag('span'));
775
776
        $diff = false;
777
        $href = '';
778
779
        if(!empty($recent['media'])) {
780
            $changelog = new MediaChangeLog($recent['id']);
781
            $revs = $changelog->getRevisions(0, 1);
782
            $diff = (count($revs) && file_exists(mediaFN($recent['id'])));
783
            if($diff) {
784
                $href = media_managerURL(array(
785
                                            'tab_details' => 'history',
786
                                            'mediado' => 'diff',
787
                                            'image' => $recent['id'],
788
                                            'ns' => getNS($recent['id'])
789
                                        ), '&');
790
            }
791
        } else {
792
            $href = wl($recent['id'], "do=diff", false, '&');
793
        }
794
795
        if(!empty($recent['media']) && !$diff) {
796
            $form->addElement('<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />');
797
        } else {
798
            $form->addElement(form_makeOpenTag('a', array('class' => 'diff_link', 'href' => $href)));
799
            $form->addElement(form_makeTag('img', array(
800
                            'src'    => DOKU_BASE . 'lib/images/diff.png',
801
                            'width'  => 15,
802
                            'height' => 11,
803
                            'title'  => $lang['diff'],
804
                            'alt'    => $lang['diff']
805
                        )));
806
            $form->addElement(form_makeCloseTag('a'));
807
        }
808
809
        if(!empty($recent['media'])) {
810
            $href = media_managerURL(array('tab_details' => 'history', 'image' => $recent['id'], 'ns' => getNS($recent['id'])), '&');
811
        } else {
812
            $href = wl($recent['id'], "do=revisions", false, '&');
813
        }
814
        $form->addElement(form_makeOpenTag('a', array(
815
                        'class' => 'revisions_link',
816
                        'href'  => $href)));
817
        $form->addElement(form_makeTag('img', array(
818
                        'src'    => DOKU_BASE . 'lib/images/history.png',
819
                        'width'  => 12,
820
                        'height' => 14,
821
                        'title'  => $lang['btn_revs'],
822
                        'alt'    => $lang['btn_revs']
823
                    )));
824
        $form->addElement(form_makeCloseTag('a'));
825
826
        if(!empty($recent['media'])) {
827
            $href = media_managerURL(array('tab_details' => 'view', 'image' => $recent['id'], 'ns' => getNS($recent['id'])), '&');
828
            $class = file_exists(mediaFN($recent['id'])) ? 'wikilink1' : 'wikilink2';
829
            $form->addElement(form_makeOpenTag('a', array(
830
                        'class' => $class,
831
                        'href'  => $href)));
832
            $form->addElement($recent['id']);
833
            $form->addElement(form_makeCloseTag('a'));
834
        } else {
835
            $form->addElement(html_wikilink(':' . $recent['id'], useHeading('navigation') ? null : $recent['id']));
836
        }
837
        $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
838
        $form->addElement(' – ' . hsc($recent['sum']));
839
        $form->addElement(form_makeCloseTag('span'));
840
841
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
842
        if($recent['user']) {
843
            $form->addElement('<bdi>' . editorinfo($recent['user']) . '</bdi>');
844
            if(auth_ismanager()) {
845
                $form->addElement(' <bdo dir="ltr">(' . $recent['ip'] . ')</bdo>');
846
            }
847
        } else {
848
            $form->addElement('<bdo dir="ltr">' . $recent['ip'] . '</bdo>');
849
        }
850
        $form->addElement(form_makeCloseTag('span'));
851
852
        html_sizechange($recent['sizechange'], $form);
853
854
        $form->addElement(form_makeCloseTag('div'));
855
        $form->addElement(form_makeCloseTag('li'));
856
    }
857
    $form->addElement(form_makeCloseTag('ul'));
858
859
    $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav')));
860
    $last = $first + $conf['recent'];
861
    if($first > 0) {
862
        $first -= $conf['recent'];
863
        if($first < 0) $first = 0;
864
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-prev')));
865
        $form->addElement(form_makeOpenTag('button', array(
866
                        'type'      => 'submit',
867
                        'name'      => 'first[' . $first . ']',
868
                        'accesskey' => 'n',
869
                        'title'     => $lang['btn_newer'] . ' [N]',
870
                        'class'     => 'button show'
871
                    )));
872
        $form->addElement($lang['btn_newer']);
873
        $form->addElement(form_makeCloseTag('button'));
874
        $form->addElement(form_makeCloseTag('div'));
875
    }
876
    if($hasNext) {
877
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-next')));
878
        $form->addElement(form_makeOpenTag('button', array(
879
                        'type'      => 'submit',
880
                        'name'      => 'first[' . $last . ']',
881
                        'accesskey' => 'p',
882
                        'title'     => $lang['btn_older'] . ' [P]',
883
                        'class'     => 'button show'
884
                    )));
885
        $form->addElement($lang['btn_older']);
886
        $form->addElement(form_makeCloseTag('button'));
887
        $form->addElement(form_makeCloseTag('div'));
888
    }
889
    $form->addElement(form_makeCloseTag('div'));
890
    html_form('recent', $form);
891
}
892
893
/**
894
 * Display page index
895
 *
896
 * @author Andreas Gohr <[email protected]>
897
 *
898
 * @param string $ns
899
 */
900
function html_index($ns){
901
    global $conf;
902
    global $ID;
903
    $ns  = cleanID($ns);
904
    if(empty($ns)){
905
        $ns = getNS($ID);
906
        if($ns === false) $ns ='';
907
    }
908
    $ns  = utf8_encodeFN(str_replace(':','/',$ns));
909
910
    echo p_locale_xhtml('index');
911
    echo '<div id="index__tree" class="index__tree">';
912
913
    $data = array();
914
    search($data,$conf['datadir'],'search_index',array('ns' => $ns));
915
    echo html_buildlist($data,'idx','html_list_index','html_li_index');
916
917
    echo '</div>';
918
}
919
920
/**
921
 * Index item formatter
922
 *
923
 * User function for html_buildlist()
924
 *
925
 * @author Andreas Gohr <[email protected]>
926
 *
927
 * @param array $item
928
 * @return string
929
 */
930
function html_list_index($item){
931
    global $ID, $conf;
932
933
    // prevent searchbots needlessly following links
934
    $nofollow = ($ID != $conf['start'] || $conf['sitemap']) ? ' rel="nofollow"' : '';
935
936
    $ret = '';
937
    $base = ':'.$item['id'];
938
    $base = substr($base,strrpos($base,':')+1);
939
    if($item['type']=='d'){
940
        // FS#2766, no need for search bots to follow namespace links in the index
941
        $ret .= '<a href="'.wl($ID,'idx='.rawurlencode($item['id'])).'" title="' . $item['id'] . '" class="idx_dir"' . $nofollow . '><strong>';
942
        $ret .= $base;
943
        $ret .= '</strong></a>';
944
    }else{
945
        // default is noNSorNS($id), but we want noNS($id) when useheading is off FS#2605
946
        $ret .= html_wikilink(':'.$item['id'], useHeading('navigation') ? null : noNS($item['id']));
947
    }
948
    return $ret;
949
}
950
951
/**
952
 * Index List item
953
 *
954
 * This user function is used in html_buildlist to build the
955
 * <li> tags for namespaces when displaying the page index
956
 * it gives different classes to opened or closed "folders"
957
 *
958
 * @author Andreas Gohr <[email protected]>
959
 *
960
 * @param array $item
961
 * @return string html
962
 */
963
function html_li_index($item){
964
    global $INFO;
965
    global $ACT;
966
967
    $class = '';
968
    $id = '';
969
970
    if($item['type'] == "f"){
971
        // scroll to the current item
972
        if($item['id'] == $INFO['id'] && $ACT == 'index') {
973
            $id = ' id="scroll__here"';
974
            $class = ' bounce';
975
        }
976
        return '<li class="level'.$item['level'].$class.'" '.$id.'>';
977
    }elseif($item['open']){
978
        return '<li class="open">';
979
    }else{
980
        return '<li class="closed">';
981
    }
982
}
983
984
/**
985
 * Default List item
986
 *
987
 * @author Andreas Gohr <[email protected]>
988
 *
989
 * @param array $item
990
 * @return string html
991
 */
992
function html_li_default($item){
993
    return '<li class="level'.$item['level'].'">';
994
}
995
996
/**
997
 * Build an unordered list
998
 *
999
 * Build an unordered list from the given $data array
1000
 * Each item in the array has to have a 'level' property
1001
 * the item itself gets printed by the given $func user
1002
 * function. The second and optional function is used to
1003
 * print the <li> tag. Both user function need to accept
1004
 * a single item.
1005
 *
1006
 * Both user functions can be given as array to point to
1007
 * a member of an object.
1008
 *
1009
 * @author Andreas Gohr <[email protected]>
1010
 *
1011
 * @param array    $data  array with item arrays
1012
 * @param string   $class class of ul wrapper
1013
 * @param callable $func  callback to print an list item
1014
 * @param callable $lifunc callback to the opening li tag
1015
 * @param bool     $forcewrapper Trigger building a wrapper ul if the first level is
1016
 *                               0 (we have a root object) or 1 (just the root content)
1017
 * @return string html of an unordered list
1018
 */
1019
function html_buildlist($data,$class,$func,$lifunc='html_li_default',$forcewrapper=false){
1020
    if (count($data) === 0) {
1021
        return '';
1022
    }
1023
1024
    $firstElement = reset($data);
1025
    $start_level = $firstElement['level'];
1026
    $level = $start_level;
1027
    $ret   = '';
1028
    $open  = 0;
1029
1030
    foreach ($data as $item){
1031
1032
        if( $item['level'] > $level ){
1033
            //open new list
1034
            for($i=0; $i<($item['level'] - $level); $i++){
1035
                if ($i) $ret .= "<li class=\"clear\">";
1036
                $ret .= "\n<ul class=\"$class\">\n";
1037
                $open++;
1038
            }
1039
            $level = $item['level'];
1040
1041
        }elseif( $item['level'] < $level ){
1042
            //close last item
1043
            $ret .= "</li>\n";
1044
            while( $level > $item['level'] && $open > 0 ){
1045
                //close higher lists
1046
                $ret .= "</ul>\n</li>\n";
1047
                $level--;
1048
                $open--;
1049
            }
1050
        } elseif ($ret !== '') {
1051
            //close previous item
1052
            $ret .= "</li>\n";
1053
        }
1054
1055
        //print item
1056
        $ret .= call_user_func($lifunc,$item);
1057
        $ret .= '<div class="li">';
1058
1059
        $ret .= call_user_func($func,$item);
1060
        $ret .= '</div>';
1061
    }
1062
1063
    //close remaining items and lists
1064
    $ret .= "</li>\n";
1065
    while($open-- > 0) {
1066
        $ret .= "</ul></li>\n";
1067
    }
1068
1069
    if ($forcewrapper || $start_level < 2) {
1070
        // Trigger building a wrapper ul if the first level is
1071
        // 0 (we have a root object) or 1 (just the root content)
1072
        $ret = "\n<ul class=\"$class\">\n".$ret."</ul>\n";
1073
    }
1074
1075
    return $ret;
1076
}
1077
1078
/**
1079
 * display backlinks
1080
 *
1081
 * @author Andreas Gohr <[email protected]>
1082
 * @author Michael Klier <[email protected]>
1083
 */
1084
function html_backlinks(){
1085
    global $ID;
1086
    global $lang;
1087
1088
    print p_locale_xhtml('backlinks');
1089
1090
    $data = ft_backlinks($ID);
1091
1092
    if(!empty($data)) {
1093
        print '<ul class="idx">';
1094
        foreach($data as $blink){
1095
            print '<li><div class="li">';
1096
            print html_wikilink(':'.$blink,useHeading('navigation')?null:$blink);
1097
            print '</div></li>';
1098
        }
1099
        print '</ul>';
1100
    } else {
1101
        print '<div class="level1"><p>' . $lang['nothingfound'] . '</p></div>';
1102
    }
1103
}
1104
1105
/**
1106
 * Get header of diff HTML
1107
 *
1108
 * @param string $l_rev   Left revisions
1109
 * @param string $r_rev   Right revision
1110
 * @param string $id      Page id, if null $ID is used
1111
 * @param bool   $media   If it is for media files
1112
 * @param bool   $inline  Return the header on a single line
1113
 * @return string[] HTML snippets for diff header
1114
 */
1115
function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) {
1116
    global $lang;
1117
    if ($id === null) {
1118
        global $ID;
1119
        $id = $ID;
1120
    }
1121
    $head_separator = $inline ? ' ' : '<br />';
1122
    $media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN';
1123
    $ml_or_wl = $media ? 'ml' : 'wl';
1124
    $l_minor = $r_minor = '';
1125
1126
    if($media) {
1127
        $changelog = new MediaChangeLog($id);
1128
    } else {
1129
        $changelog = new PageChangeLog($id);
1130
    }
1131
    if(!$l_rev){
1132
        $l_head = '&mdash;';
1133
    }else{
1134
        $l_info   = $changelog->getRevisionInfo($l_rev);
1135
        if($l_info['user']){
1136
            $l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>';
1137
            if(auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>';
1138
        } else {
1139
            $l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>';
1140
        }
1141
        $l_user  = '<span class="user">'.$l_user.'</span>';
1142
        $l_sum   = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : '';
1143
        if ($l_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"';
1144
1145
        $l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']';
1146
        $l_head = '<bdi><a class="wikilink1" href="'.html_revision_link($id, $l_rev, $ml_or_wl).'">'.
1147
        $l_head_title.'</a></bdi>'.
1148
        $head_separator.$l_user.' '.$l_sum;
1149
    }
1150
1151
    if($r_rev){
1152
        $r_info   = $changelog->getRevisionInfo($r_rev);
1153
        if($r_info['user']){
1154
            $r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>';
1155
            if(auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>';
1156
        } else {
1157
            $r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>';
1158
        }
1159
        $r_user = '<span class="user">'.$r_user.'</span>';
1160
        $r_sum  = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : '';
1161
        if ($r_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1162
1163
        $r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']';
1164
        $r_head = '<bdi><a class="wikilink1" href="'.html_revision_link($id, $r_rev, $ml_or_wl).'">'.
1165
        $r_head_title.'</a></bdi>'.
1166
        $head_separator.$r_user.' '.$r_sum;
1167
    }elseif($_rev = @filemtime($media_or_wikiFN($id))){
1168
        $_info   = $changelog->getRevisionInfo($_rev);
1169
        if($_info['user']){
1170
            $_user = '<bdi>'.editorinfo($_info['user']).'</bdi>';
1171
            if(auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>';
1172
        } else {
1173
            $_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>';
1174
        }
1175
        $_user = '<span class="user">'.$_user.'</span>';
1176
        $_sum  = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : '';
1177
        if ($_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1178
1179
        $r_head_title = ($media) ? dformat($_rev) : $id.' ['.dformat($_rev).']';
1180
        $r_head  = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id).'">'.
1181
        $r_head_title.'</a></bdi> '.
1182
        '('.$lang['current'].')'.
1183
        $head_separator.$_user.' '.$_sum;
1184
    }else{
1185
        $r_head = '&mdash; ('.$lang['current'].')';
1186
    }
1187
1188
    return array($l_head, $r_head, $l_minor, $r_minor);
1189
}
1190
1191
/**
1192
 * Show diff
1193
 * between current page version and provided $text
1194
 * or between the revisions provided via GET or POST
1195
 *
1196
 * @author Andreas Gohr <[email protected]>
1197
 * @param  string $text  when non-empty: compare with this text with most current version
1198
 * @param  bool   $intro display the intro text
1199
 * @param  string $type  type of the diff (inline or sidebyside)
1200
 */
1201
function html_diff($text = '', $intro = true, $type = null) {
1202
    global $ID;
1203
    global $REV;
1204
    global $lang;
1205
    global $INPUT;
1206
    global $INFO;
1207
    $pagelog = new PageChangeLog($ID);
1208
1209
    /*
1210
     * Determine diff type
1211
     */
1212
    if(!$type) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to false; 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...
1213
        $type = $INPUT->str('difftype');
1214
        if(empty($type)) {
1215
            $type = get_doku_pref('difftype', $type);
1216
            if(empty($type) && $INFO['ismobile']) {
1217
                $type = 'inline';
1218
            }
1219
        }
1220
    }
1221
    if($type != 'inline') $type = 'sidebyside';
1222
1223
    /*
1224
     * Determine requested revision(s)
1225
     */
1226
    // we're trying to be clever here, revisions to compare can be either
1227
    // given as rev and rev2 parameters, with rev2 being optional. Or in an
1228
    // array in rev2.
1229
    $rev1 = $REV;
1230
1231
    $rev2 = $INPUT->ref('rev2');
1232
    if(is_array($rev2)) {
1233
        $rev1 = (int) $rev2[0];
1234
        $rev2 = (int) $rev2[1];
1235
1236
        if(!$rev1) {
1237
            $rev1 = $rev2;
1238
            unset($rev2);
1239
        }
1240
    } else {
1241
        $rev2 = $INPUT->int('rev2');
1242
    }
1243
1244
    /*
1245
     * Determine left and right revision, its texts and the header
1246
     */
1247
    $r_minor = '';
1248
    $l_minor = '';
1249
1250
    if($text) { // compare text to the most current revision
1251
        $l_rev = '';
1252
        $l_text = rawWiki($ID, '');
1253
        $l_head = '<a class="wikilink1" href="' . wl($ID) . '">' .
1254
            $ID . ' ' . dformat((int) @filemtime(wikiFN($ID))) . '</a> ' .
1255
            $lang['current'];
1256
1257
        $r_rev = '';
1258
        $r_text = cleanText($text);
1259
        $r_head = $lang['yours'];
1260
    } else {
1261
        if($rev1 && isset($rev2) && $rev2) { // two specific revisions wanted
1262
            // make sure order is correct (older on the left)
1263
            if($rev1 < $rev2) {
1264
                $l_rev = $rev1;
1265
                $r_rev = $rev2;
1266
            } else {
1267
                $l_rev = $rev2;
1268
                $r_rev = $rev1;
1269
            }
1270
        } elseif($rev1) { // single revision given, compare to current
1271
            $r_rev = '';
1272
            $l_rev = $rev1;
1273
        } else { // no revision was given, compare previous to current
1274
            $r_rev = '';
1275
            $revs = $pagelog->getRevisions(0, 1);
1276
            $l_rev = $revs[0];
1277
            $REV = $l_rev; // store revision back in $REV
1278
        }
1279
1280
        // when both revisions are empty then the page was created just now
1281
        if(!$l_rev && !$r_rev) {
1282
            $l_text = '';
1283
        } else {
1284
            $l_text = rawWiki($ID, $l_rev);
1285
        }
1286
        $r_text = rawWiki($ID, $r_rev);
1287
1288
        list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev, null, false, $type == 'inline');
1289
    }
1290
1291
    /*
1292
     * Build navigation
1293
     */
1294
    $l_nav = '';
1295
    $r_nav = '';
1296
    if(!$text) {
1297
        list($l_nav, $r_nav) = html_diff_navigation($pagelog, $type, $l_rev, $r_rev);
1298
    }
1299
    /*
1300
     * Create diff object and the formatter
1301
     */
1302
    $diff = new Diff(explode("\n", $l_text), explode("\n", $r_text));
1303
1304
    if($type == 'inline') {
1305
        $diffformatter = new InlineDiffFormatter();
1306
    } else {
1307
        $diffformatter = new TableDiffFormatter();
1308
    }
1309
    /*
1310
     * Display intro
1311
     */
1312
    if($intro) print p_locale_xhtml('diff');
1313
1314
    /*
1315
     * Display type and exact reference
1316
     */
1317
    if(!$text) {
1318
        ptln('<div class="diffoptions group">');
1319
1320
1321
        $form = new Doku_Form(array('action' => wl()));
1322
        $form->addHidden('id', $ID);
1323
        $form->addHidden('rev2[0]', $l_rev);
1324
        $form->addHidden('rev2[1]', $r_rev);
1325
        $form->addHidden('do', 'diff');
1326
        $form->addElement(
1327
             form_makeListboxField(
1328
                 'difftype',
1329
                 array(
1330
                     'sidebyside' => $lang['diff_side'],
1331
                     'inline' => $lang['diff_inline']
1332
                 ),
1333
                 $type,
1334
                 $lang['diff_type'],
1335
                 '', '',
1336
                 array('class' => 'quickselect')
1337
             )
1338
        );
1339
        $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1340
        $form->printForm();
1341
1342
        ptln('<p>');
1343
        // link to exactly this view FS#2835
1344
        echo html_diff_navigationlink($type, 'difflink', $l_rev, $r_rev ? $r_rev : $INFO['currentrev']);
1345
        ptln('</p>');
1346
1347
        ptln('</div>'); // .diffoptions
1348
    }
1349
1350
    /*
1351
     * Display diff view table
1352
     */
1353
    ?>
1354
    <div class="table">
1355
    <table class="diff diff_<?php echo $type ?>">
1356
1357
        <?php
1358
        //navigation and header
1359
        if($type == 'inline') {
1360
            if(!$text) { ?>
1361
                <tr>
1362
                    <td class="diff-lineheader">-</td>
1363
                    <td class="diffnav"><?php echo $l_nav ?></td>
1364
                </tr>
1365
                <tr>
1366
                    <th class="diff-lineheader">-</th>
1367
                    <th <?php echo $l_minor ?>>
1368
                        <?php echo $l_head ?>
1369
                    </th>
1370
                </tr>
1371
            <?php } ?>
1372
            <tr>
1373
                <td class="diff-lineheader">+</td>
1374
                <td class="diffnav"><?php echo $r_nav ?></td>
1375
            </tr>
1376
            <tr>
1377
                <th class="diff-lineheader">+</th>
1378
                <th <?php echo $r_minor ?>>
1379
                    <?php echo $r_head ?>
1380
                </th>
1381
            </tr>
1382
        <?php } else {
1383
            if(!$text) { ?>
1384
                <tr>
1385
                    <td colspan="2" class="diffnav"><?php echo $l_nav ?></td>
1386
                    <td colspan="2" class="diffnav"><?php echo $r_nav ?></td>
1387
                </tr>
1388
            <?php } ?>
1389
            <tr>
1390
                <th colspan="2" <?php echo $l_minor ?>>
1391
                    <?php echo $l_head ?>
1392
                </th>
1393
                <th colspan="2" <?php echo $r_minor ?>>
1394
                    <?php echo $r_head ?>
1395
                </th>
1396
            </tr>
1397
        <?php }
1398
1399
        //diff view
1400
        echo html_insert_softbreaks($diffformatter->format($diff)); ?>
1401
1402
    </table>
1403
    </div>
1404
<?php
1405
}
1406
1407
/**
1408
 * Create html for revision navigation
1409
 *
1410
 * @param PageChangeLog $pagelog changelog object of current page
1411
 * @param string        $type    inline vs sidebyside
1412
 * @param int           $l_rev   left revision timestamp
1413
 * @param int           $r_rev   right revision timestamp
1414
 * @return string[] html of left and right navigation elements
1415
 */
1416
function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) {
1417
    global $INFO, $ID;
1418
1419
    // last timestamp is not in changelog, retrieve timestamp from metadata
1420
    // note: when page is removed, the metadata timestamp is zero
1421
    if(!$r_rev) {
1422
        if(isset($INFO['meta']['last_change']['date'])) {
1423
            $r_rev = $INFO['meta']['last_change']['date'];
1424
        } else {
1425
            $r_rev = 0;
1426
        }
1427
    }
1428
1429
    //retrieve revisions with additional info
1430
    list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev);
1431
    $l_revisions = array();
1432
    if(!$l_rev) {
1433
        $l_revisions[0] = array(0, "", false); //no left revision given, add dummy
1434
    }
1435
    foreach($l_revs as $rev) {
1436
        $info = $pagelog->getRevisionInfo($rev);
1437
        $l_revisions[$rev] = array(
1438
            $rev,
1439
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1440
            $r_rev ? $rev >= $r_rev : false //disable?
1441
        );
1442
    }
1443
    $r_revisions = array();
1444
    if(!$r_rev) {
1445
        $r_revisions[0] = array(0, "", false); //no right revision given, add dummy
1446
    }
1447
    foreach($r_revs as $rev) {
1448
        $info = $pagelog->getRevisionInfo($rev);
1449
        $r_revisions[$rev] = array(
1450
            $rev,
1451
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1452
            $rev <= $l_rev //disable?
1453
        );
1454
    }
1455
1456
    //determine previous/next revisions
1457
    $l_index = array_search($l_rev, $l_revs);
1458
    $l_prev = $l_revs[$l_index + 1];
1459
    $l_next = $l_revs[$l_index - 1];
1460
    if($r_rev) {
1461
        $r_index = array_search($r_rev, $r_revs);
1462
        $r_prev = $r_revs[$r_index + 1];
1463
        $r_next = $r_revs[$r_index - 1];
1464
    } else {
1465
        //removed page
1466
        if($l_next) {
1467
            $r_prev = $r_revs[0];
1468
        } else {
1469
            $r_prev = null;
1470
        }
1471
        $r_next = null;
1472
    }
1473
1474
    /*
1475
     * Left side:
1476
     */
1477
    $l_nav = '';
1478
    //move back
1479
    if($l_prev) {
1480
        $l_nav .= html_diff_navigationlink($type, 'diffbothprevrev', $l_prev, $r_prev);
1481
        $l_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_prev, $r_rev);
1482
    }
1483
    //dropdown
1484
    $form = new Doku_Form(array('action' => wl()));
1485
    $form->addHidden('id', $ID);
1486
    $form->addHidden('difftype', $type);
1487
    $form->addHidden('rev2[1]', $r_rev);
1488
    $form->addHidden('do', 'diff');
1489
    $form->addElement(
1490
         form_makeListboxField(
1491
             'rev2[0]',
1492
             $l_revisions,
1493
             $l_rev,
1494
             '', '', '',
1495
             array('class' => 'quickselect')
1496
         )
1497
    );
1498
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1499
    $l_nav .= $form->getForm();
1500
    //move forward
1501
    if($l_next && ($l_next < $r_rev || !$r_rev)) {
1502
        $l_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_next, $r_rev);
1503
    }
1504
1505
    /*
1506
     * Right side:
1507
     */
1508
    $r_nav = '';
1509
    //move back
1510
    if($l_rev < $r_prev) {
1511
        $r_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_rev, $r_prev);
1512
    }
1513
    //dropdown
1514
    $form = new Doku_Form(array('action' => wl()));
1515
    $form->addHidden('id', $ID);
1516
    $form->addHidden('rev2[0]', $l_rev);
1517
    $form->addHidden('difftype', $type);
1518
    $form->addHidden('do', 'diff');
1519
    $form->addElement(
1520
         form_makeListboxField(
1521
             'rev2[1]',
1522
             $r_revisions,
1523
             $r_rev,
1524
             '', '', '',
1525
             array('class' => 'quickselect')
1526
         )
1527
    );
1528
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1529
    $r_nav .= $form->getForm();
1530
    //move forward
1531
    if($r_next) {
1532
        if($pagelog->isCurrentRevision($r_next)) {
1533
            $r_nav .= html_diff_navigationlink($type, 'difflastrev', $l_rev); //last revision is diff with current page
1534
        } else {
1535
            $r_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_rev, $r_next);
1536
        }
1537
        $r_nav .= html_diff_navigationlink($type, 'diffbothnextrev', $l_next, $r_next);
1538
    }
1539
    return array($l_nav, $r_nav);
1540
}
1541
1542
/**
1543
 * Create html link to a diff defined by two revisions
1544
 *
1545
 * @param string $difftype display type
1546
 * @param string $linktype
1547
 * @param int $lrev oldest revision
1548
 * @param int $rrev newest revision or null for diff with current revision
1549
 * @return string html of link to a diff
1550
 */
1551
function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) {
1552
    global $ID, $lang;
1553
    if(!$rrev) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rrev of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1554
        $urlparam = array(
1555
            'do' => 'diff',
1556
            'rev' => $lrev,
1557
            'difftype' => $difftype,
1558
        );
1559
    } else {
1560
        $urlparam = array(
1561
            'do' => 'diff',
1562
            'rev2[0]' => $lrev,
1563
            'rev2[1]' => $rrev,
1564
            'difftype' => $difftype,
1565
        );
1566
    }
1567
    return  '<a class="' . $linktype . '" href="' . wl($ID, $urlparam) . '" title="' . $lang[$linktype] . '">' .
1568
                '<span>' . $lang[$linktype] . '</span>' .
1569
            '</a>' . "\n";
1570
}
1571
1572
/**
1573
 * Insert soft breaks in diff html
1574
 *
1575
 * @param string $diffhtml
1576
 * @return string
1577
 */
1578
function html_insert_softbreaks($diffhtml) {
1579
    // search the diff html string for both:
1580
    // - html tags, so these can be ignored
1581
    // - long strings of characters without breaking characters
1582
    return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/','html_softbreak_callback',$diffhtml);
1583
}
1584
1585
/**
1586
 * callback which adds softbreaks
1587
 *
1588
 * @param array $match array with first the complete match
1589
 * @return string the replacement
1590
 */
1591
function html_softbreak_callback($match){
1592
    // if match is an html tag, return it intact
1593
    if ($match[0]{0} == '<') return $match[0];
1594
1595
    // its a long string without a breaking character,
1596
    // make certain characters into breaking characters by inserting a
1597
    // word break opportunity (<wbr> tag) in front of them.
1598
    $regex = <<< REGEX
1599
(?(?=                                 # start a conditional expression with a positive look ahead ...
1600
&\#?\\w{1,6};)                        # ... for html entities - we don't want to split them (ok to catch some invalid combinations)
1601
&\#?\\w{1,6};                         # yes pattern - a quicker match for the html entity, since we know we have one
1602
|
1603
[?/,&\#;:]                            # no pattern - any other group of 'special' characters to insert a breaking character after
1604
)+                                    # end conditional expression
1605
REGEX;
1606
1607
    return preg_replace('<'.$regex.'>xu','\0<wbr>',$match[0]);
1608
}
1609
1610
/**
1611
 * show warning on conflict detection
1612
 *
1613
 * @author Andreas Gohr <[email protected]>
1614
 *
1615
 * @param string $text
1616
 * @param string $summary
1617
 */
1618
function html_conflict($text,$summary){
1619
    global $ID;
1620
    global $lang;
1621
1622
    print p_locale_xhtml('conflict');
1623
    $form = new Doku_Form(array('id' => 'dw__editform'));
1624
    $form->addHidden('id', $ID);
1625
    $form->addHidden('wikitext', $text);
1626
    $form->addHidden('summary', $summary);
1627
    $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('accesskey'=>'s')));
1628
    $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel']));
1629
    html_form('conflict', $form);
1630
    print '<br /><br /><br /><br />'.NL;
1631
}
1632
1633
/**
1634
 * Prints the global message array
1635
 *
1636
 * @author Andreas Gohr <[email protected]>
1637
 */
1638
function html_msgarea(){
1639
    global $MSG, $MSG_shown;
1640
    /** @var array $MSG */
1641
    // store if the global $MSG has already been shown and thus HTML output has been started
1642
    $MSG_shown = true;
1643
1644
    if(!isset($MSG)) return;
1645
1646
    $shown = array();
1647
    foreach($MSG as $msg){
1648
        $hash = md5($msg['msg']);
1649
        if(isset($shown[$hash])) continue; // skip double messages
1650
        if(info_msg_allowed($msg)){
1651
            print '<div class="'.$msg['lvl'].'">';
1652
            print $msg['msg'];
1653
            print '</div>';
1654
        }
1655
        $shown[$hash] = 1;
1656
    }
1657
1658
    unset($GLOBALS['MSG']);
1659
}
1660
1661
/**
1662
 * Prints the registration form
1663
 *
1664
 * @author Andreas Gohr <[email protected]>
1665
 */
1666
function html_register(){
1667
    global $lang;
1668
    global $conf;
1669
    global $INPUT;
1670
1671
    $base_attrs = array('size'=>50,'required'=>'required');
1672
    $email_attrs = $base_attrs + array('type'=>'email','class'=>'edit');
1673
1674
    print p_locale_xhtml('register');
1675
    print '<div class="centeralign">'.NL;
1676
    $form = new Doku_Form(array('id' => 'dw__register'));
1677
    $form->startFieldset($lang['btn_register']);
1678
    $form->addHidden('do', 'register');
1679
    $form->addHidden('save', '1');
1680
    $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block', $base_attrs));
1681
    if (!$conf['autopasswd']) {
1682
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', $base_attrs));
1683
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', $base_attrs));
1684
    }
1685
    $form->addElement(form_makeTextField('fullname', $INPUT->post->str('fullname'), $lang['fullname'], '', 'block', $base_attrs));
1686
    $form->addElement(form_makeField('email','email', $INPUT->post->str('email'), $lang['email'], '', 'block', $email_attrs));
1687
    $form->addElement(form_makeButton('submit', '', $lang['btn_register']));
1688
    $form->endFieldset();
1689
    html_form('register', $form);
1690
1691
    print '</div>'.NL;
1692
}
1693
1694
/**
1695
 * Print the update profile form
1696
 *
1697
 * @author Christopher Smith <[email protected]>
1698
 * @author Andreas Gohr <[email protected]>
1699
 */
1700
function html_updateprofile(){
1701
    global $lang;
1702
    global $conf;
1703
    global $INPUT;
1704
    global $INFO;
1705
    /** @var DokuWiki_Auth_Plugin $auth */
1706
    global $auth;
1707
1708
    print p_locale_xhtml('updateprofile');
1709
    print '<div class="centeralign">'.NL;
1710
1711
    $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true);
1712
    $email = $INPUT->post->str('email', $INFO['userinfo']['mail'], true);
1713
    $form = new Doku_Form(array('id' => 'dw__register'));
1714
    $form->startFieldset($lang['profile']);
1715
    $form->addHidden('do', 'profile');
1716
    $form->addHidden('save', '1');
1717
    $form->addElement(form_makeTextField('login', $_SERVER['REMOTE_USER'], $lang['user'], '', 'block', array('size'=>'50', 'disabled'=>'disabled')));
1718
    $attr = array('size'=>'50');
1719
    if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled';
1720
    $form->addElement(form_makeTextField('fullname', $fullname, $lang['fullname'], '', 'block', $attr));
1721
    $attr = array('size'=>'50', 'class'=>'edit');
1722
    if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled';
1723
    $form->addElement(form_makeField('email','email', $email, $lang['email'], '', 'block', $attr));
1724
    $form->addElement(form_makeTag('br'));
1725
    if ($auth->canDo('modPass')) {
1726
        $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50')));
1727
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1728
    }
1729
    if ($conf['profileconfirm']) {
1730
        $form->addElement(form_makeTag('br'));
1731
        $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required')));
1732
    }
1733
    $form->addElement(form_makeButton('submit', '', $lang['btn_save']));
1734
    $form->addElement(form_makeButton('reset', '', $lang['btn_reset']));
1735
1736
    $form->endFieldset();
1737
    html_form('updateprofile', $form);
1738
1739
    if ($auth->canDo('delUser') && actionOK('profile_delete')) {
1740
        $form_profiledelete = new Doku_Form(array('id' => 'dw__profiledelete'));
1741
        $form_profiledelete->startFieldset($lang['profdeleteuser']);
1742
        $form_profiledelete->addHidden('do', 'profile_delete');
1743
        $form_profiledelete->addHidden('delete', '1');
1744
        $form_profiledelete->addElement(form_makeCheckboxField('confirm_delete', '1', $lang['profconfdelete'],'dw__confirmdelete','', array('required' => 'required')));
1745
        if ($conf['profileconfirm']) {
1746
            $form_profiledelete->addElement(form_makeTag('br'));
1747
            $form_profiledelete->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required')));
1748
        }
1749
        $form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser']));
1750
        $form_profiledelete->endFieldset();
1751
1752
        html_form('profiledelete', $form_profiledelete);
1753
    }
1754
1755
    print '</div>'.NL;
1756
}
1757
1758
/**
1759
 * Preprocess edit form data
1760
 *
1761
 * @author   Andreas Gohr <[email protected]>
1762
 *
1763
 * @triggers HTML_EDITFORM_OUTPUT
1764
 */
1765
function html_edit(){
1766
    global $INPUT;
1767
    global $ID;
1768
    global $REV;
1769
    global $DATE;
1770
    global $PRE;
1771
    global $SUF;
1772
    global $INFO;
1773
    global $SUM;
1774
    global $lang;
1775
    global $conf;
1776
    global $TEXT;
1777
1778
    if ($INPUT->has('changecheck')) {
1779
        $check = $INPUT->str('changecheck');
1780
    } elseif(!$INFO['exists']){
1781
        // $TEXT has been loaded from page template
1782
        $check = md5('');
1783
    } else {
1784
        $check = md5($TEXT);
1785
    }
1786
    $mod = md5($TEXT) !== $check;
1787
1788
    $wr = $INFO['writable'] && !$INFO['locked'];
1789
    $include = 'edit';
1790
    if($wr){
1791
        if ($REV) $include = 'editrev';
1792
    }else{
1793
        // check pseudo action 'source'
1794
        if(!actionOK('source')){
1795
            msg('Command disabled: source',-1);
1796
            return;
1797
        }
1798
        $include = 'read';
1799
    }
1800
1801
    global $license;
1802
1803
    $form = new Doku_Form(array('id' => 'dw__editform'));
1804
    $form->addHidden('id', $ID);
1805
    $form->addHidden('rev', $REV);
1806
    $form->addHidden('date', $DATE);
1807
    $form->addHidden('prefix', $PRE . '.');
1808
    $form->addHidden('suffix', $SUF);
1809
    $form->addHidden('changecheck', $check);
1810
1811
    $data = array('form' => $form,
1812
                  'wr'   => $wr,
1813
                  'media_manager' => true,
1814
                  'target' => ($INPUT->has('target') && $wr) ? $INPUT->str('target') : 'section',
1815
                  'intro_locale' => $include);
1816
1817
    if ($data['target'] !== 'section') {
1818
        // Only emit event if page is writable, section edit data is valid and
1819
        // edit target is not section.
1820
        trigger_event('HTML_EDIT_FORMSELECTION', $data, 'html_edit_form', true);
1821
    } else {
1822
        html_edit_form($data);
1823
    }
1824
    if (isset($data['intro_locale'])) {
1825
        echo p_locale_xhtml($data['intro_locale']);
1826
    }
1827
1828
    $form->addHidden('target', $data['target']);
1829
    if ($INPUT->has('hid')) {
1830
        $form->addHidden('hid', $INPUT->str('hid'));
1831
    }
1832
    if ($INPUT->has('codeblockOffset')) {
1833
        $form->addHidden('codeblockOffset', $INPUT->str('codeblockOffset'));
1834
    }
1835
    $form->addElement(form_makeOpenTag('div', array('id'=>'wiki__editbar', 'class'=>'editBar')));
1836
    $form->addElement(form_makeOpenTag('div', array('id'=>'size__ctl')));
1837
    $form->addElement(form_makeCloseTag('div'));
1838
    if ($wr) {
1839
        $form->addElement(form_makeOpenTag('div', array('class'=>'editButtons')));
1840
        $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('id'=>'edbtn__save', 'accesskey'=>'s', 'tabindex'=>'4')));
1841
        $form->addElement(form_makeButton('submit', 'preview', $lang['btn_preview'], array('id'=>'edbtn__preview', 'accesskey'=>'p', 'tabindex'=>'5')));
1842
        $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel'], array('tabindex'=>'6')));
1843
        $form->addElement(form_makeCloseTag('div'));
1844
        $form->addElement(form_makeOpenTag('div', array('class'=>'summary')));
1845
        $form->addElement(form_makeTextField('summary', $SUM, $lang['summary'], 'edit__summary', 'nowrap', array('size'=>'50', 'tabindex'=>'2')));
1846
        $elem = html_minoredit();
1847
        if ($elem) $form->addElement($elem);
1848
        $form->addElement(form_makeCloseTag('div'));
1849
    }
1850
    $form->addElement(form_makeCloseTag('div'));
1851
    if($wr && $conf['license']){
1852
        $form->addElement(form_makeOpenTag('div', array('class'=>'license')));
1853
        $out  = $lang['licenseok'];
1854
        $out .= ' <a href="'.$license[$conf['license']]['url'].'" rel="license" class="urlextern"';
1855
        if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
1856
        $out .= '>'.$license[$conf['license']]['name'].'</a>';
1857
        $form->addElement($out);
1858
        $form->addElement(form_makeCloseTag('div'));
1859
    }
1860
1861
    if ($wr) {
1862
        // sets changed to true when previewed
1863
        echo '<script type="text/javascript">/*<![CDATA[*/'. NL;
1864
        echo 'textChanged = ' . ($mod ? 'true' : 'false');
1865
        echo '/*!]]>*/</script>' . NL;
1866
    } ?>
1867
    <div class="editBox" role="application">
1868
1869
    <div class="toolbar group">
1870
        <div id="tool__bar" class="tool__bar"><?php if ($wr && $data['media_manager']){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
1871
            target="_blank"><?php echo $lang['mediaselect'] ?></a><?php }?></div>
1872
    </div>
1873
    <div id="draft__status" class="draft__status">
1874
        <?php
1875
        $draft = new \dokuwiki\Draft($ID, $INFO['client']);
1876
        if ($draft->isDraftAvailable()) {
1877
            echo $draft->getDraftMessage();
1878
        }
1879
        ?>
1880
    </div>
1881
    <?php
1882
1883
    html_form('edit', $form);
1884
    print '</div>'.NL;
1885
}
1886
1887
/**
1888
 * Display the default edit form
1889
 *
1890
 * Is the default action for HTML_EDIT_FORMSELECTION.
1891
 *
1892
 * @param mixed[] $param
1893
 */
1894
function html_edit_form($param) {
1895
    global $TEXT;
1896
1897
    if ($param['target'] !== 'section') {
1898
        msg('No editor for edit target ' . hsc($param['target']) . ' found.', -1);
1899
    }
1900
1901
    $attr = array('tabindex'=>'1');
1902
    if (!$param['wr']) $attr['readonly'] = 'readonly';
1903
1904
    $param['form']->addElement(form_makeWikiText($TEXT, $attr));
1905
}
1906
1907
/**
1908
 * Adds a checkbox for minor edits for logged in users
1909
 *
1910
 * @author Andreas Gohr <[email protected]>
1911
 *
1912
 * @return array|bool
1913
 */
1914
function html_minoredit(){
1915
    global $conf;
1916
    global $lang;
1917
    global $INPUT;
1918
    // minor edits are for logged in users only
1919
    if(!$conf['useacl'] || !$_SERVER['REMOTE_USER']){
1920
        return false;
1921
    }
1922
1923
    $p = array();
1924
    $p['tabindex'] = 3;
1925
    if($INPUT->bool('minor')) $p['checked']='checked';
1926
    return form_makeCheckboxField('minor', '1', $lang['minoredit'], 'minoredit', 'nowrap', $p);
1927
}
1928
1929
/**
1930
 * prints some debug info
1931
 *
1932
 * @author Andreas Gohr <[email protected]>
1933
 */
1934
function html_debug(){
1935
    global $conf;
1936
    global $lang;
1937
    /** @var DokuWiki_Auth_Plugin $auth */
1938
    global $auth;
1939
    global $INFO;
1940
1941
    //remove sensitive data
1942
    $cnf = $conf;
1943
    debug_guard($cnf);
1944
    $nfo = $INFO;
1945
    debug_guard($nfo);
1946
    $ses = $_SESSION;
1947
    debug_guard($ses);
1948
1949
    print '<html><body>';
1950
1951
    print '<p>When reporting bugs please send all the following ';
1952
    print 'output as a mail to [email protected] ';
1953
    print 'The best way to do this is to save this page in your browser</p>';
1954
1955
    print '<b>$INFO:</b><pre>';
1956
    print_r($nfo);
1957
    print '</pre>';
1958
1959
    print '<b>$_SERVER:</b><pre>';
1960
    print_r($_SERVER);
1961
    print '</pre>';
1962
1963
    print '<b>$conf:</b><pre>';
1964
    print_r($cnf);
1965
    print '</pre>';
1966
1967
    print '<b>DOKU_BASE:</b><pre>';
1968
    print DOKU_BASE;
1969
    print '</pre>';
1970
1971
    print '<b>abs DOKU_BASE:</b><pre>';
1972
    print DOKU_URL;
1973
    print '</pre>';
1974
1975
    print '<b>rel DOKU_BASE:</b><pre>';
1976
    print dirname($_SERVER['PHP_SELF']).'/';
1977
    print '</pre>';
1978
1979
    print '<b>PHP Version:</b><pre>';
1980
    print phpversion();
1981
    print '</pre>';
1982
1983
    print '<b>locale:</b><pre>';
1984
    print setlocale(LC_ALL,0);
1985
    print '</pre>';
1986
1987
    print '<b>encoding:</b><pre>';
1988
    print $lang['encoding'];
1989
    print '</pre>';
1990
1991
    if($auth){
1992
        print '<b>Auth backend capabilities:</b><pre>';
1993
        foreach ($auth->getCapabilities() as $cando){
1994
            print '   '.str_pad($cando,16) . ' => ' . (int)$auth->canDo($cando) . NL;
1995
        }
1996
        print '</pre>';
1997
    }
1998
1999
    print '<b>$_SESSION:</b><pre>';
2000
    print_r($ses);
2001
    print '</pre>';
2002
2003
    print '<b>Environment:</b><pre>';
2004
    print_r($_ENV);
2005
    print '</pre>';
2006
2007
    print '<b>PHP settings:</b><pre>';
2008
    $inis = ini_get_all();
2009
    print_r($inis);
2010
    print '</pre>';
2011
2012
    if (function_exists('apache_get_version')) {
2013
        $apache = array();
2014
        $apache['version'] = apache_get_version();
2015
2016
        if (function_exists('apache_get_modules')) {
2017
            $apache['modules'] = apache_get_modules();
2018
        }
2019
        print '<b>Apache</b><pre>';
2020
        print_r($apache);
2021
        print '</pre>';
2022
    }
2023
2024
    print '</body></html>';
2025
}
2026
2027
/**
2028
 * Form to request a new password for an existing account
2029
 *
2030
 * @author Benoit Chesneau <[email protected]>
2031
 * @author Andreas Gohr <[email protected]>
2032
 */
2033
function html_resendpwd() {
2034
    global $lang;
2035
    global $conf;
2036
    global $INPUT;
2037
2038
    $token = preg_replace('/[^a-f0-9]+/','',$INPUT->str('pwauth'));
2039
2040
    if(!$conf['autopasswd'] && $token){
2041
        print p_locale_xhtml('resetpwd');
2042
        print '<div class="centeralign">'.NL;
2043
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
2044
        $form->startFieldset($lang['btn_resendpwd']);
2045
        $form->addHidden('token', $token);
2046
        $form->addHidden('do', 'resendpwd');
2047
2048
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50')));
2049
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
2050
2051
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2052
        $form->endFieldset();
2053
        html_form('resendpwd', $form);
2054
        print '</div>'.NL;
2055
    }else{
2056
        print p_locale_xhtml('resendpwd');
2057
        print '<div class="centeralign">'.NL;
2058
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
2059
        $form->startFieldset($lang['resendpwd']);
2060
        $form->addHidden('do', 'resendpwd');
2061
        $form->addHidden('save', '1');
2062
        $form->addElement(form_makeTag('br'));
2063
        $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block'));
2064
        $form->addElement(form_makeTag('br'));
2065
        $form->addElement(form_makeTag('br'));
2066
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2067
        $form->endFieldset();
2068
        html_form('resendpwd', $form);
2069
        print '</div>'.NL;
2070
    }
2071
}
2072
2073
/**
2074
 * Return the TOC rendered to XHTML
2075
 *
2076
 * @author Andreas Gohr <[email protected]>
2077
 *
2078
 * @param array $toc
2079
 * @return string html
2080
 */
2081
function html_TOC($toc){
2082
    if(!count($toc)) return '';
2083
    global $lang;
2084
    $out  = '<!-- TOC START -->'.DOKU_LF;
2085
    $out .= '<div id="dw__toc" class="dw__toc">'.DOKU_LF;
2086
    $out .= '<h3 class="toggle">';
2087
    $out .= $lang['toc'];
2088
    $out .= '</h3>'.DOKU_LF;
2089
    $out .= '<div>'.DOKU_LF;
2090
    $out .= html_buildlist($toc,'toc','html_list_toc','html_li_default',true);
2091
    $out .= '</div>'.DOKU_LF.'</div>'.DOKU_LF;
2092
    $out .= '<!-- TOC END -->'.DOKU_LF;
2093
    return $out;
2094
}
2095
2096
/**
2097
 * Callback for html_buildlist
2098
 *
2099
 * @param array $item
2100
 * @return string html
2101
 */
2102
function html_list_toc($item){
2103
    if(isset($item['hid'])){
2104
        $link = '#'.$item['hid'];
2105
    }else{
2106
        $link = $item['link'];
2107
    }
2108
2109
    return '<a href="'.$link.'">'.hsc($item['title']).'</a>';
2110
}
2111
2112
/**
2113
 * Helper function to build TOC items
2114
 *
2115
 * Returns an array ready to be added to a TOC array
2116
 *
2117
 * @param string $link  - where to link (if $hash set to '#' it's a local anchor)
2118
 * @param string $text  - what to display in the TOC
2119
 * @param int    $level - nesting level
2120
 * @param string $hash  - is prepended to the given $link, set blank if you want full links
2121
 * @return array the toc item
2122
 */
2123
function html_mktocitem($link, $text, $level, $hash='#'){
2124
    return  array( 'link'  => $hash.$link,
2125
            'title' => $text,
2126
            'type'  => 'ul',
2127
            'level' => $level);
2128
}
2129
2130
/**
2131
 * Output a Doku_Form object.
2132
 * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT
2133
 *
2134
 * @author Tom N Harris <[email protected]>
2135
 *
2136
 * @param string     $name The name of the form
2137
 * @param Doku_Form  $form The form
2138
 */
2139
function html_form($name, &$form) {
2140
    // Safety check in case the caller forgets.
2141
    $form->endFieldset();
2142
    trigger_event('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
2143
}
2144
2145
/**
2146
 * Form print function.
2147
 * Just calls printForm() on the data object.
2148
 *
2149
 * @param Doku_Form $data The form
2150
 */
2151
function html_form_output($data) {
2152
    $data->printForm();
2153
}
2154
2155
/**
2156
 * Embed a flash object in HTML
2157
 *
2158
 * This will create the needed HTML to embed a flash movie in a cross browser
2159
 * compatble way using valid XHTML
2160
 *
2161
 * The parameters $params, $flashvars and $atts need to be associative arrays.
2162
 * No escaping needs to be done for them. The alternative content *has* to be
2163
 * escaped because it is used as is. If no alternative content is given
2164
 * $lang['noflash'] is used.
2165
 *
2166
 * @author Andreas Gohr <[email protected]>
2167
 * @link   http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml
2168
 *
2169
 * @param string $swf      - the SWF movie to embed
2170
 * @param int $width       - width of the flash movie in pixels
2171
 * @param int $height      - height of the flash movie in pixels
2172
 * @param array $params    - additional parameters (<param>)
2173
 * @param array $flashvars - parameters to be passed in the flashvar parameter
2174
 * @param array $atts      - additional attributes for the <object> tag
2175
 * @param string $alt      - alternative content (is NOT automatically escaped!)
2176
 * @return string         - the XHTML markup
2177
 */
2178
function html_flashobject($swf,$width,$height,$params=null,$flashvars=null,$atts=null,$alt=''){
2179
    global $lang;
2180
2181
    $out = '';
2182
2183
    // prepare the object attributes
2184
    if(is_null($atts)) $atts = array();
2185
    $atts['width']  = (int) $width;
2186
    $atts['height'] = (int) $height;
2187
    if(!$atts['width'])  $atts['width']  = 425;
2188
    if(!$atts['height']) $atts['height'] = 350;
2189
2190
    // add object attributes for standard compliant browsers
2191
    $std = $atts;
2192
    $std['type'] = 'application/x-shockwave-flash';
2193
    $std['data'] = $swf;
2194
2195
    // add object attributes for IE
2196
    $ie  = $atts;
2197
    $ie['classid'] = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
2198
2199
    // open object (with conditional comments)
2200
    $out .= '<!--[if !IE]> -->'.NL;
2201
    $out .= '<object '.buildAttributes($std).'>'.NL;
2202
    $out .= '<!-- <![endif]-->'.NL;
2203
    $out .= '<!--[if IE]>'.NL;
2204
    $out .= '<object '.buildAttributes($ie).'>'.NL;
2205
    $out .= '    <param name="movie" value="'.hsc($swf).'" />'.NL;
2206
    $out .= '<!--><!-- -->'.NL;
2207
2208
    // print params
2209
    if(is_array($params)) foreach($params as $key => $val){
2210
        $out .= '  <param name="'.hsc($key).'" value="'.hsc($val).'" />'.NL;
2211
    }
2212
2213
    // add flashvars
2214
    if(is_array($flashvars)){
2215
        $out .= '  <param name="FlashVars" value="'.buildURLparams($flashvars).'" />'.NL;
2216
    }
2217
2218
    // alternative content
2219
    if($alt){
2220
        $out .= $alt.NL;
2221
    }else{
2222
        $out .= $lang['noflash'].NL;
2223
    }
2224
2225
    // finish
2226
    $out .= '</object>'.NL;
2227
    $out .= '<!-- <![endif]-->'.NL;
2228
2229
    return $out;
2230
}
2231
2232
/**
2233
 * Prints HTML code for the given tab structure
2234
 *
2235
 * @param array  $tabs        tab structure
2236
 * @param string $current_tab the current tab id
2237
 */
2238
function html_tabs($tabs, $current_tab = null) {
2239
    echo '<ul class="tabs">'.NL;
2240
2241
    foreach($tabs as $id => $tab) {
2242
        html_tab($tab['href'], $tab['caption'], $id === $current_tab);
2243
    }
2244
2245
    echo '</ul>'.NL;
2246
}
2247
2248
/**
2249
 * Prints a single tab
2250
 *
2251
 * @author Kate Arzamastseva <[email protected]>
2252
 * @author Adrian Lang <[email protected]>
2253
 *
2254
 * @param string $href - tab href
2255
 * @param string $caption - tab caption
2256
 * @param boolean $selected - is tab selected
2257
 */
2258
2259
function html_tab($href, $caption, $selected=false) {
2260
    $tab = '<li>';
2261
    if ($selected) {
2262
        $tab .= '<strong>';
2263
    } else {
2264
        $tab .= '<a href="' . hsc($href) . '">';
2265
    }
2266
    $tab .= hsc($caption)
2267
         .  '</' . ($selected ? 'strong' : 'a') . '>'
2268
         .  '</li>'.NL;
2269
    echo $tab;
2270
}
2271
2272
/**
2273
 * Display size change
2274
 *
2275
 * @param int $sizechange - size of change in Bytes
2276
 * @param Doku_Form $form - form to add elements to
2277
 */
2278
2279
function html_sizechange($sizechange, Doku_Form $form) {
2280
    if(isset($sizechange)) {
2281
        $class = 'sizechange';
2282
        $value = filesize_h(abs($sizechange));
2283
        if($sizechange > 0) {
2284
            $class .= ' positive';
2285
            $value = '+' . $value;
2286
        } elseif($sizechange < 0) {
2287
            $class .= ' negative';
2288
            $value = '-' . $value;
2289
        } else {
2290
            $value = '±' . $value;
2291
        }
2292
        $form->addElement(form_makeOpenTag('span', array('class' => $class)));
2293
        $form->addElement($value);
2294
        $form->addElement(form_makeCloseTag('span'));
2295
    }
2296
}
2297