Failed Conditions
Push — issue2517 ( 359362...5fdc2f )
by Henry
08:09 queued 05:10
created

inc/html.php (18 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
use dokuwiki\ChangeLog\MediaChangeLog;
0 ignored issues
show
This use statement conflicts with another class in this namespace, MediaChangeLog.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use dokuwiki\ChangeLog\PageChangeLog;
0 ignored issues
show
This use statement conflicts with another class in this namespace, PageChangeLog.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
11
use dokuwiki\Extension\AuthPlugin;
12
use dokuwiki\Extension\Event;
13
14
if (!defined('SEC_EDIT_PATTERN')) {
15
    define('SEC_EDIT_PATTERN', '#<!-- EDIT({.*?}) -->#');
16
}
17
18
19
/**
20
 * Convenience function to quickly build a wikilink
21
 *
22
 * @author Andreas Gohr <[email protected]>
23
 * @param string  $id      id of the target page
24
 * @param string  $name    the name of the link, i.e. the text that is displayed
25
 * @param string|array  $search  search string(s) that shall be highlighted in the target page
26
 * @return string the HTML code of the link
27
 */
28
function html_wikilink($id,$name=null,$search=''){
29
    /** @var Doku_Renderer_xhtml $xhtml_renderer */
30
    static $xhtml_renderer = null;
31
    if(is_null($xhtml_renderer)){
32
        $xhtml_renderer = p_get_renderer('xhtml');
33
    }
34
35
    return $xhtml_renderer->internallink($id,$name,$search,true,'navigation');
36
}
37
38
/**
39
 * The loginform
40
 *
41
 * @author   Andreas Gohr <[email protected]>
42
 *
43
 * @param bool $svg Whether to show svg icons in the register and resendpwd links or not
44
 */
45
function html_login($svg = false){
46
    global $lang;
47
    global $conf;
48
    global $ID;
49
    global $INPUT;
50
51
    print p_locale_xhtml('login');
52
    print '<div class="centeralign">'.NL;
53
    $form = new Doku_Form(array('id' => 'dw__login'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
54
    $form->startFieldset($lang['btn_login']);
55
    $form->addHidden('id', $ID);
56
    $form->addHidden('do', 'login');
57
    $form->addElement(form_makeTextField(
58
        'u',
59
        ((!$INPUT->bool('http_credentials')) ? $INPUT->str('u') : ''),
60
        $lang['user'],
61
        'focus__this',
62
        'block')
63
    );
64
    $form->addElement(form_makePasswordField('p', $lang['pass'], '', 'block'));
65
    if($conf['rememberme']) {
66
        $form->addElement(form_makeCheckboxField('r', '1', $lang['remember'], 'remember__me', 'simple'));
67
    }
68
    $form->addElement(form_makeButton('submit', '', $lang['btn_login']));
69
    $form->endFieldset();
70
71
    if(actionOK('register')){
72
        $registerLink = (new \dokuwiki\Menu\Item\Register())->asHtmlLink('', $svg);
73
        $form->addElement('<p>'.$lang['reghere'].': '. $registerLink .'</p>');
74
    }
75
76
    if (actionOK('resendpwd')) {
77
        $resendPwLink = (new \dokuwiki\Menu\Item\Resendpwd())->asHtmlLink('', $svg);
78
        $form->addElement('<p>'.$lang['pwdforget'].': '. $resendPwLink .'</p>');
79
    }
80
81
    html_form('login', $form);
82
    print '</div>'.NL;
83
}
84
85
86
/**
87
 * Denied page content
88
 *
89
 * @return string html
90
 */
91
function html_denied() {
92
    print p_locale_xhtml('denied');
93
94
    if(empty($_SERVER['REMOTE_USER']) && actionOK('login')){
95
        html_login();
96
    }
97
}
98
99
/**
100
 * inserts section edit buttons if wanted or removes the markers
101
 *
102
 * @author Andreas Gohr <[email protected]>
103
 *
104
 * @param string $text
105
 * @param bool   $show show section edit buttons?
106
 * @return string
107
 */
108
function html_secedit($text,$show=true){
109
    global $INFO;
110
111
    if(!$INFO['writable'] || !$show || $INFO['rev']){
112
        return preg_replace(SEC_EDIT_PATTERN,'',$text);
113
    }
114
115
    return preg_replace_callback(SEC_EDIT_PATTERN,
116
                'html_secedit_button', $text);
117
}
118
119
/**
120
 * prepares section edit button data for event triggering
121
 * used as a callback in html_secedit
122
 *
123
 * @author Andreas Gohr <[email protected]>
124
 *
125
 * @param array $matches matches with regexp
126
 * @return string
127
 * @triggers HTML_SECEDIT_BUTTON
128
 */
129
function html_secedit_button($matches){
130
    $json = htmlspecialchars_decode($matches[1], ENT_QUOTES);
131
    $data = json_decode($json, true);
132
    if ($data == NULL) {
133
        return;
134
    }
135
    $data ['target'] = strtolower($data['target']);
136
    $data ['hid'] = strtolower($data['hid']);
137
138
    return Event::createAndTrigger('HTML_SECEDIT_BUTTON', $data,
139
                         'html_secedit_get_button');
140
}
141
142
/**
143
 * prints a section editing button
144
 * used as default action form HTML_SECEDIT_BUTTON
145
 *
146
 * @author Adrian Lang <[email protected]>
147
 *
148
 * @param array $data name, section id and target
149
 * @return string html
150
 */
151
function html_secedit_get_button($data) {
152
    global $ID;
153
    global $INFO;
154
155
    if (!isset($data['name']) || $data['name'] === '') return '';
156
157
    $name = $data['name'];
158
    unset($data['name']);
159
160
    $secid = $data['secid'];
161
    unset($data['secid']);
162
163
    return "<div class='secedit editbutton_" . $data['target'] .
164
                       " editbutton_" . $secid . "'>" .
165
           html_btn('secedit', $ID, '',
166
                    array_merge(array('do'  => 'edit',
167
                                      'rev' => $INFO['lastmod'],
168
                                      'summary' => '['.$name.'] '), $data),
169
                    'post', $name) . '</div>';
170
}
171
172
/**
173
 * Just the back to top button (in its own form)
174
 *
175
 * @author Andreas Gohr <[email protected]>
176
 *
177
 * @return string html
178
 */
179
function html_topbtn(){
180
    global $lang;
181
182
    $ret = '<a class="nolink" href="#dokuwiki__top">' .
183
        '<button class="button" onclick="window.scrollTo(0, 0)" title="' . $lang['btn_top'] . '">' .
184
        $lang['btn_top'] .
185
        '</button></a>';
186
187
    return $ret;
188
}
189
190
/**
191
 * Displays a button (using its own form)
192
 * If tooltip exists, the access key tooltip is replaced.
193
 *
194
 * @author Andreas Gohr <[email protected]>
195
 *
196
 * @param string         $name
197
 * @param string         $id
198
 * @param string         $akey   access key
199
 * @param string[] $params key-value pairs added as hidden inputs
200
 * @param string         $method
201
 * @param string         $tooltip
202
 * @param bool|string    $label  label text, false: lookup btn_$name in localization
203
 * @param string         $svg (optional) svg code, inserted into the button
204
 * @return string
205
 */
206
function html_btn($name, $id, $akey, $params, $method='get', $tooltip='', $label=false, $svg=null){
207
    global $conf;
208
    global $lang;
209
210
    if (!$label)
211
        $label = $lang['btn_'.$name];
212
213
    $ret = '';
214
215
    //filter id (without urlencoding)
216
    $id = idfilter($id,false);
217
218
    //make nice URLs even for buttons
219
    if($conf['userewrite'] == 2){
220
        $script = DOKU_BASE.DOKU_SCRIPT.'/'.$id;
221
    }elseif($conf['userewrite']){
222
        $script = DOKU_BASE.$id;
223
    }else{
224
        $script = DOKU_BASE.DOKU_SCRIPT;
225
        $params['id'] = $id;
226
    }
227
228
    $ret .= '<form class="button btn_'.$name.'" method="'.$method.'" action="'.$script.'"><div class="no">';
229
230
    if(is_array($params)){
231
        foreach($params as $key => $val) {
232
            $ret .= '<input type="hidden" name="'.$key.'" ';
233
            $ret .= 'value="'.hsc($val).'" />';
234
        }
235
    }
236
237
    if ($tooltip!='') {
238
        $tip = hsc($tooltip);
239
    }else{
240
        $tip = hsc($label);
241
    }
242
243
    $ret .= '<button type="submit" ';
244
    if($akey){
245
        $tip .= ' ['.strtoupper($akey).']';
246
        $ret .= 'accesskey="'.$akey.'" ';
247
    }
248
    $ret .= 'title="'.$tip.'">';
249
    if ($svg) {
250
        $ret .= '<span>' . hsc($label) . '</span>';
251
        $ret .= inlineSVG($svg);
252
    } else {
253
        $ret .= hsc($label);
254
    }
255
    $ret .= '</button>';
256
    $ret .= '</div></form>';
257
258
    return $ret;
259
}
260
/**
261
 * show a revision warning
262
 *
263
 * @author Szymon Olewniczak <[email protected]>
264
 */
265
function html_showrev() {
266
    print p_locale_xhtml('showrev');
267
}
268
269
/**
270
 * Show a wiki page
271
 *
272
 * @author Andreas Gohr <[email protected]>
273
 *
274
 * @param null|string $txt wiki text or null for showing $ID
275
 */
276
function html_show($txt=null){
277
    global $ID;
278
    global $REV;
279
    global $HIGH;
280
    global $INFO;
281
    global $DATE_AT;
282
    //disable section editing for old revisions or in preview
283
    if($txt || $REV){
284
        $secedit = false;
285
    }else{
286
        $secedit = true;
287
    }
288
289
    if (!is_null($txt)){
290
        //PreviewHeader
291
        echo '<br id="scroll__here" />';
292
        echo p_locale_xhtml('preview');
293
        echo '<div class="preview"><div class="pad">';
294
        $html = html_secedit(p_render('xhtml',p_get_instructions($txt),$info),$secedit);
295
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
296
        echo $html;
297
        echo '<div class="clearer"></div>';
298
        echo '</div></div>';
299
300
    }else{
301
        if ($REV||$DATE_AT){
302
            $data = array('rev' => &$REV, 'date_at' => &$DATE_AT);
303
            Event::createAndTrigger('HTML_SHOWREV_OUTPUT', $data, 'html_showrev');
304
        }
305
        $html = p_wiki_xhtml($ID,$REV,true,$DATE_AT);
306
        $html = html_secedit($html,$secedit);
307
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
308
        $html = html_hilight($html,$HIGH);
309
        echo $html;
310
    }
311
}
312
313
/**
314
 * ask the user about how to handle an exisiting draft
315
 *
316
 * @author Andreas Gohr <[email protected]>
317
 */
318
function html_draft(){
319
    global $INFO;
320
    global $ID;
321
    global $lang;
322
    $draft = new \dokuwiki\Draft($ID, $INFO['client']);
323
    $text  = $draft->getDraftText();
324
325
    print p_locale_xhtml('draft');
326
    html_diff($text, false);
327
    $form = new Doku_Form(array('id' => 'dw__editform'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
328
    $form->addHidden('id', $ID);
329
    $form->addHidden('date', $draft->getDraftDate());
330
    $form->addHidden('wikitext', $text);
331
    $form->addElement(form_makeOpenTag('div', array('id'=>'draft__status')));
332
    $form->addElement($draft->getDraftMessage());
333
    $form->addElement(form_makeCloseTag('div'));
334
    $form->addElement(form_makeButton('submit', 'recover', $lang['btn_recover'], array('tabindex'=>'1')));
335
    $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_draftdel'], array('tabindex'=>'2')));
336
    $form->addElement(form_makeButton('submit', 'show', $lang['btn_cancel'], array('tabindex'=>'3')));
337
    html_form('draft', $form);
338
}
339
340
/**
341
 * Highlights searchqueries in HTML code
342
 *
343
 * @author Andreas Gohr <[email protected]>
344
 * @author Harry Fuecks <[email protected]>
345
 *
346
 * @param string $html
347
 * @param array|string $phrases
348
 * @return string html
349
 */
350
function html_hilight($html,$phrases){
351
    $phrases = (array) $phrases;
352
    $phrases = array_map('preg_quote_cb', $phrases);
353
    $phrases = array_map('ft_snippet_re_preprocess', $phrases);
354
    $phrases = array_filter($phrases);
355
    $regex = join('|',$phrases);
356
357
    if ($regex === '') return $html;
358
    if (!\dokuwiki\Utf8\Clean::isUtf8($regex)) return $html;
359
    $html = @preg_replace_callback("/((<[^>]*)|$regex)/ui",'html_hilight_callback',$html);
360
    return $html;
361
}
362
363
/**
364
 * Callback used by html_hilight()
365
 *
366
 * @author Harry Fuecks <[email protected]>
367
 *
368
 * @param array $m matches
369
 * @return string html
370
 */
371
function html_hilight_callback($m) {
372
    $hlight = unslash($m[0]);
373
    if ( !isset($m[2])) {
374
        $hlight = '<span class="search_hit">'.$hlight.'</span>';
375
    }
376
    return $hlight;
377
}
378
379
/**
380
 * Display error on locked pages
381
 *
382
 * @author Andreas Gohr <[email protected]>
383
 */
384
function html_locked(){
385
    global $ID;
386
    global $conf;
387
    global $lang;
388
    global $INFO;
389
390
    $locktime = filemtime(wikiLockFN($ID));
391
    $expire = dformat($locktime + $conf['locktime']);
392
    $min    = round(($conf['locktime'] - (time() - $locktime) )/60);
393
394
    print p_locale_xhtml('locked');
395
    print '<ul>';
396
    print '<li><div class="li"><strong>'.$lang['lockedby'].'</strong> '.editorinfo($INFO['locked']).'</div></li>';
397
    print '<li><div class="li"><strong>'.$lang['lockexpire'].'</strong> '.$expire.' ('.$min.' min)</div></li>';
398
    print '</ul>';
399
}
400
401
/**
402
 * list old revisions
403
 *
404
 * @author Andreas Gohr <[email protected]>
405
 * @author Ben Coburn <[email protected]>
406
 * @author Kate Arzamastseva <[email protected]>
407
 *
408
 * @param int $first skip the first n changelog lines
409
 * @param bool|string $media_id id of media, or false for current page
410
 */
411
function html_revisions($first=0, $media_id = false){
412
    global $ID;
413
    global $INFO;
414
    global $conf;
415
    global $lang;
416
    $id = $ID;
417
    if ($media_id) {
418
        $id = $media_id;
419
        $changelog = new MediaChangeLog($id);
420
    } else {
421
        $changelog = new PageChangeLog($id);
422
    }
423
424
    /* we need to get one additional log entry to be able to
425
     * decide if this is the last page or is there another one.
426
     * see html_recent()
427
     */
428
429
    $revisions = $changelog->getRevisions($first, $conf['recent']+1);
430
431
    if(count($revisions)==0 && $first!=0){
432
        $first=0;
433
        $revisions = $changelog->getRevisions($first, $conf['recent']+1);
434
    }
435
    $hasNext = false;
436
    if (count($revisions)>$conf['recent']) {
437
        $hasNext = true;
438
        array_pop($revisions); // remove extra log entry
439
    }
440
441
    if (!$media_id) print p_locale_xhtml('revisions');
442
443
    $params = array('id' => 'page__revisions', 'class' => 'changes');
444
    if($media_id) {
445
        $params['action'] = media_managerURL(array('image' => $media_id), '&');
446
    }
447
448
    if(!$media_id) {
449
        $exists = $INFO['exists'];
450
        $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
451
        if(!$display_name) {
452
            $display_name = $id;
453
        }
454
    } else {
455
        $exists = file_exists(mediaFN($id));
456
        $display_name = $id;
457
    }
458
459
    $form = new Doku_Form($params);
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
460
    $form->addElement(form_makeOpenTag('ul'));
461
462
    if($exists && $first == 0) {
463
        $minor = false;
464
        if($media_id) {
465
            $date = dformat(@filemtime(mediaFN($id)));
466
            $href = media_managerURL(array('image' => $id, 'tab_details' => 'view'), '&');
467
468
            $changelog->setChunkSize(1024);
469
            $revinfo = $changelog->getRevisionInfo(@filemtime(fullpath(mediaFN($id))));
470
471
            $summary = $revinfo['sum'];
472
            if($revinfo['user']) {
473
                $editor = $revinfo['user'];
474
            } else {
475
                $editor = $revinfo['ip'];
476
            }
477
            $sizechange = $revinfo['sizechange'];
478
        } else {
479
            $date = dformat($INFO['lastmod']);
480
            if(isset($INFO['meta']) && isset($INFO['meta']['last_change'])) {
481
                if($INFO['meta']['last_change']['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
482
                    $minor = true;
483
                }
484
                if(isset($INFO['meta']['last_change']['sizechange'])) {
485
                    $sizechange = $INFO['meta']['last_change']['sizechange'];
486
                } else {
487
                    $sizechange = null;
488
                }
489
            }
490
            $pagelog = new PageChangeLog($ID);
491
            $latestrev = $pagelog->getRevisions(-1, 1);
492
            $latestrev = array_pop($latestrev);
493
            $href = wl($id,"rev=$latestrev",false,'&');
494
            $summary = $INFO['sum'];
495
            $editor = $INFO['editor'];
496
        }
497
498
        $form->addElement(form_makeOpenTag('li', array('class' => ($minor ? 'minor' : ''))));
499
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
500
        $form->addElement(form_makeTag('input', array(
501
                        'type' => 'checkbox',
502
                        'name' => 'rev2[]',
503
                        'value' => 'current')));
504
505
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
506
        $form->addElement($date);
507
        $form->addElement(form_makeCloseTag('span'));
508
509
        $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
510
511
        $form->addElement(form_makeOpenTag('a', array(
512
                        'class' => 'wikilink1',
513
                        'href'  => $href)));
514
        $form->addElement($display_name);
515
        $form->addElement(form_makeCloseTag('a'));
516
517
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
518
519
        if($summary) {
520
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
521
            if(!$media_id) $form->addElement(' – ');
522
            $form->addElement('<bdi>' . hsc($summary) . '</bdi>');
523
            $form->addElement(form_makeCloseTag('span'));
524
        }
525
526
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
527
        $form->addElement((empty($editor))?('('.$lang['external_edit'].')'):'<bdi>'.editorinfo($editor).'</bdi>');
528
        $form->addElement(form_makeCloseTag('span'));
529
530
        html_sizechange($sizechange, $form);
531
532
        $form->addElement('('.$lang['current'].')');
533
534
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
535
536
        $form->addElement(form_makeCloseTag('div'));
537
        $form->addElement(form_makeCloseTag('li'));
538
    }
539
540
    foreach($revisions as $rev) {
541
        $date = dformat($rev);
542
        $info = $changelog->getRevisionInfo($rev);
543
        if($media_id) {
544
            $exists = file_exists(mediaFN($id, $rev));
545
        } else {
546
            $exists = page_exists($id, $rev);
547
        }
548
549
        $class = '';
550
        if($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
551
            $class = 'minor';
552
        }
553
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
554
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
555
        if($exists){
556
            $form->addElement(form_makeTag('input', array(
557
                            'type' => 'checkbox',
558
                            'name' => 'rev2[]',
559
                            'value' => $rev)));
560
        }else{
561
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
562
        }
563
564
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
565
        $form->addElement($date);
566
        $form->addElement(form_makeCloseTag('span'));
567
568
        if($exists){
569
            if (!$media_id) {
570
                $href = wl($id,"rev=$rev,do=diff", false, '&');
571
            } else {
572
                $href = media_managerURL(array('image' => $id, 'rev' => $rev, 'mediado' => 'diff'), '&');
573
            }
574
            $form->addElement(form_makeOpenTag('a', array(
575
                            'class' => 'diff_link',
576
                            'href' => $href)));
577
            $form->addElement(form_makeTag('img', array(
578
                            'src'    => DOKU_BASE.'lib/images/diff.png',
579
                            'width'  => 15,
580
                            'height' => 11,
581
                            'title'  => $lang['diff'],
582
                            'alt'    => $lang['diff'])));
583
            $form->addElement(form_makeCloseTag('a'));
584
585
            if (!$media_id) {
586
                $href = wl($id,"rev=$rev",false,'&');
587
            } else {
588
                $href = media_managerURL(array('image' => $id, 'tab_details' => 'view', 'rev' => $rev), '&');
589
            }
590
            $form->addElement(form_makeOpenTag('a', array(
591
                            'class' => 'wikilink1',
592
                            'href' => $href)));
593
            $form->addElement($display_name);
594
            $form->addElement(form_makeCloseTag('a'));
595
        }else{
596
            $form->addElement('<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />');
597
            $form->addElement($display_name);
598
        }
599
600
        if ($media_id) $form->addElement(form_makeOpenTag('div'));
601
602
        if ($info['sum']) {
603
            $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
604
            if(!$media_id) $form->addElement(' – ');
605
            $form->addElement('<bdi>'.hsc($info['sum']).'</bdi>');
606
            $form->addElement(form_makeCloseTag('span'));
607
        }
608
609
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
610
        if($info['user']){
611
            $form->addElement('<bdi>'.editorinfo($info['user']).'</bdi>');
612
            if(auth_ismanager()){
613
                $form->addElement(' <bdo dir="ltr">('.$info['ip'].')</bdo>');
614
            }
615
        }else{
616
            $form->addElement('<bdo dir="ltr">'.$info['ip'].'</bdo>');
617
        }
618
        $form->addElement(form_makeCloseTag('span'));
619
620
        html_sizechange($info['sizechange'], $form);
621
622
        if ($media_id) $form->addElement(form_makeCloseTag('div'));
623
624
        $form->addElement(form_makeCloseTag('div'));
625
        $form->addElement(form_makeCloseTag('li'));
626
    }
627
    $form->addElement(form_makeCloseTag('ul'));
628
    if (!$media_id) {
629
        $form->addElement(form_makeButton('submit', 'diff', $lang['diff2']));
630
    } else {
631
        $form->addHidden('mediado', 'diff');
632
        $form->addElement(form_makeButton('submit', '', $lang['diff2']));
633
    }
634
    html_form('revisions', $form);
635
636
    print '<div class="pagenav">';
637
    $last = $first + $conf['recent'];
638
    if ($first > 0) {
639
        $first -= $conf['recent'];
640
        if ($first < 0) $first = 0;
641
        print '<div class="pagenav-prev">';
642
        if ($media_id) {
643
            print html_btn('newer',$media_id,"p",media_managerURL(array('first' => $first), '&amp;', false, true));
644
        } else {
645
            print html_btn('newer',$id,"p",array('do' => 'revisions', 'first' => $first));
646
        }
647
        print '</div>';
648
    }
649
    if ($hasNext) {
650
        print '<div class="pagenav-next">';
651
        if ($media_id) {
652
            print html_btn('older',$media_id,"n",media_managerURL(array('first' => $last), '&amp;', false, true));
653
        } else {
654
            print html_btn('older',$id,"n",array('do' => 'revisions', 'first' => $last));
655
        }
656
        print '</div>';
657
    }
658
    print '</div>';
659
660
}
661
662
/**
663
 * display recent changes
664
 *
665
 * @author Andreas Gohr <[email protected]>
666
 * @author Matthias Grimm <[email protected]>
667
 * @author Ben Coburn <[email protected]>
668
 * @author Kate Arzamastseva <[email protected]>
669
 *
670
 * @param int $first
671
 * @param string $show_changes
672
 */
673
function html_recent($first = 0, $show_changes = 'both') {
674
    global $conf;
675
    global $lang;
676
    global $ID;
677
    /* we need to get one additionally log entry to be able to
678
     * decide if this is the last page or is there another one.
679
     * This is the cheapest solution to get this information.
680
     */
681
    $flags = 0;
682
    if($show_changes == 'mediafiles' && $conf['mediarevisions']) {
683
        $flags = RECENTS_MEDIA_CHANGES;
684
    } elseif($show_changes == 'pages') {
685
        $flags = 0;
686
    } elseif($conf['mediarevisions']) {
687
        $show_changes = 'both';
688
        $flags = RECENTS_MEDIA_PAGES_MIXED;
689
    }
690
691
    $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
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...
692
    if(count($recents) == 0 && $first != 0) {
693
        $first = 0;
694
        $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
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...
695
    }
696
    $hasNext = false;
697
    if(count($recents) > $conf['recent']) {
698
        $hasNext = true;
699
        array_pop($recents); // remove extra log entry
700
    }
701
702
    print p_locale_xhtml('recent');
703
704
    if(getNS($ID) != '') {
705
        print '<div class="level1"><p>' .
706
            sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent')) .
707
            '</p></div>';
708
    }
709
710
    $form = new Doku_Form(array('id' => 'dw__recent', 'method' => 'GET', 'class' => 'changes'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
711
    $form->addHidden('sectok', null);
712
    $form->addHidden('do', 'recent');
713
    $form->addHidden('id', $ID);
714
715
    if($conf['mediarevisions']) {
716
        $form->addElement('<div class="changeType">');
717
        $form->addElement(form_makeListboxField(
718
                    'show_changes',
719
                    array(
720
                        'pages'      => $lang['pages_changes'],
721
                        'mediafiles' => $lang['media_changes'],
722
                        'both'       => $lang['both_changes']
723
                    ),
724
                    $show_changes,
725
                    $lang['changes_type'],
726
                    '', '',
727
                    array('class' => 'quickselect')));
728
729
        $form->addElement(form_makeButton('submit', 'recent', $lang['btn_apply']));
730
        $form->addElement('</div>');
731
    }
732
733
    $form->addElement(form_makeOpenTag('ul'));
734
735
    foreach($recents as $recent) {
736
        $date = dformat($recent['date']);
737
738
        $class = '';
739
        if($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
740
            $class = 'minor';
741
        }
742
        $form->addElement(form_makeOpenTag('li', array('class' => $class)));
743
        $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
744
745
        if(!empty($recent['media'])) {
746
            $form->addElement(media_printicon($recent['id']));
747
        } else {
748
            $icon = DOKU_BASE . 'lib/images/fileicons/file.png';
749
            $form->addElement('<img src="' . $icon . '" alt="' . $recent['id'] . '" class="icon" />');
750
        }
751
752
        $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
753
        $form->addElement($date);
754
        $form->addElement(form_makeCloseTag('span'));
755
756
        $diff = false;
757
        $href = '';
758
759
        if(!empty($recent['media'])) {
760
            $changelog = new MediaChangeLog($recent['id']);
761
            $revs = $changelog->getRevisions(0, 1);
762
            $diff = (count($revs) && file_exists(mediaFN($recent['id'])));
763
            if($diff) {
764
                $href = media_managerURL(array(
765
                                            'tab_details' => 'history',
766
                                            'mediado' => 'diff',
767
                                            'image' => $recent['id'],
768
                                            'ns' => getNS($recent['id'])
769
                                        ), '&');
770
            }
771
        } else {
772
            $href = wl($recent['id'], "do=diff", false, '&');
773
        }
774
775
        if(!empty($recent['media']) && !$diff) {
776
            $form->addElement('<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />');
777
        } else {
778
            $form->addElement(form_makeOpenTag('a', array('class' => 'diff_link', 'href' => $href)));
779
            $form->addElement(form_makeTag('img', array(
780
                            'src'    => DOKU_BASE . 'lib/images/diff.png',
781
                            'width'  => 15,
782
                            'height' => 11,
783
                            'title'  => $lang['diff'],
784
                            'alt'    => $lang['diff']
785
                        )));
786
            $form->addElement(form_makeCloseTag('a'));
787
        }
788
789
        if(!empty($recent['media'])) {
790
            $href = media_managerURL(
791
                array(
792
                    'tab_details' => 'history',
793
                    'image' => $recent['id'],
794
                    'ns' => getNS($recent['id'])
795
                ),
796
                '&'
797
            );
798
        } else {
799
            $href = wl($recent['id'], "do=revisions", false, '&');
800
        }
801
        $form->addElement(form_makeOpenTag('a', array(
802
                        'class' => 'revisions_link',
803
                        'href'  => $href)));
804
        $form->addElement(form_makeTag('img', array(
805
                        'src'    => DOKU_BASE . 'lib/images/history.png',
806
                        'width'  => 12,
807
                        'height' => 14,
808
                        'title'  => $lang['btn_revs'],
809
                        'alt'    => $lang['btn_revs']
810
                    )));
811
        $form->addElement(form_makeCloseTag('a'));
812
813
        if(!empty($recent['media'])) {
814
            $href = media_managerURL(
815
                array(
816
                    'tab_details' => 'view',
817
                    'image' => $recent['id'],
818
                    'ns' => getNS($recent['id'])
819
                ),
820
                '&'
821
            );
822
            $class = file_exists(mediaFN($recent['id'])) ? 'wikilink1' : 'wikilink2';
823
            $form->addElement(form_makeOpenTag('a', array(
824
                        'class' => $class,
825
                        'href'  => $href)));
826
            $form->addElement($recent['id']);
827
            $form->addElement(form_makeCloseTag('a'));
828
        } else {
829
            $form->addElement(html_wikilink(':' . $recent['id'], useHeading('navigation') ? null : $recent['id']));
830
        }
831
        $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
832
        $form->addElement(' – ' . hsc($recent['sum']));
833
        $form->addElement(form_makeCloseTag('span'));
834
835
        $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
836
        if($recent['user']) {
837
            $form->addElement('<bdi>' . editorinfo($recent['user']) . '</bdi>');
838
            if(auth_ismanager()) {
839
                $form->addElement(' <bdo dir="ltr">(' . $recent['ip'] . ')</bdo>');
840
            }
841
        } else {
842
            $form->addElement('<bdo dir="ltr">' . $recent['ip'] . '</bdo>');
843
        }
844
        $form->addElement(form_makeCloseTag('span'));
845
846
        html_sizechange($recent['sizechange'], $form);
847
848
        $form->addElement(form_makeCloseTag('div'));
849
        $form->addElement(form_makeCloseTag('li'));
850
    }
851
    $form->addElement(form_makeCloseTag('ul'));
852
853
    $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav')));
854
    $last = $first + $conf['recent'];
855
    if($first > 0) {
856
        $first -= $conf['recent'];
857
        if($first < 0) $first = 0;
858
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-prev')));
859
        $form->addElement(form_makeOpenTag('button', array(
860
                        'type'      => 'submit',
861
                        'name'      => 'first[' . $first . ']',
862
                        'accesskey' => 'n',
863
                        'title'     => $lang['btn_newer'] . ' [N]',
864
                        'class'     => 'button show'
865
                    )));
866
        $form->addElement($lang['btn_newer']);
867
        $form->addElement(form_makeCloseTag('button'));
868
        $form->addElement(form_makeCloseTag('div'));
869
    }
870
    if($hasNext) {
871
        $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-next')));
872
        $form->addElement(form_makeOpenTag('button', array(
873
                        'type'      => 'submit',
874
                        'name'      => 'first[' . $last . ']',
875
                        'accesskey' => 'p',
876
                        'title'     => $lang['btn_older'] . ' [P]',
877
                        'class'     => 'button show'
878
                    )));
879
        $form->addElement($lang['btn_older']);
880
        $form->addElement(form_makeCloseTag('button'));
881
        $form->addElement(form_makeCloseTag('div'));
882
    }
883
    $form->addElement(form_makeCloseTag('div'));
884
    html_form('recent', $form);
885
}
886
887
/**
888
 * Display page index
889
 *
890
 * @author Andreas Gohr <[email protected]>
891
 *
892
 * @param string $ns
893
 */
894
function html_index($ns){
895
    global $conf;
896
    global $ID;
897
    $ns  = cleanID($ns);
898
    if(empty($ns)){
899
        $ns = getNS($ID);
900
        if($ns === false) $ns ='';
901
    }
902
    $ns  = utf8_encodeFN(str_replace(':','/',$ns));
903
904
    echo p_locale_xhtml('index');
905
    echo '<div id="index__tree" class="index__tree">';
906
907
    $data = array();
908
    search($data,$conf['datadir'],'search_index',array('ns' => $ns));
909
    echo html_buildlist($data,'idx','html_list_index','html_li_index');
910
911
    echo '</div>';
912
}
913
914
/**
915
 * Index item formatter
916
 *
917
 * User function for html_buildlist()
918
 *
919
 * @author Andreas Gohr <[email protected]>
920
 *
921
 * @param array $item
922
 * @return string
923
 */
924
function html_list_index($item){
925
    global $ID, $conf;
926
927
    // prevent searchbots needlessly following links
928
    $nofollow = ($ID != $conf['start'] || $conf['sitemap']) ? 'rel="nofollow"' : '';
929
930
    $ret = '';
931
    $base = ':'.$item['id'];
932
    $base = substr($base,strrpos($base,':')+1);
933
    if($item['type']=='d'){
934
        // FS#2766, no need for search bots to follow namespace links in the index
935
        $link = wl($ID, 'idx=' . rawurlencode($item['id']));
936
        $ret .= '<a href="' . $link . '" title="' . $item['id'] . '" class="idx_dir" ' . $nofollow . '><strong>';
937
        $ret .= $base;
938
        $ret .= '</strong></a>';
939
    }else{
940
        // default is noNSorNS($id), but we want noNS($id) when useheading is off FS#2605
941
        $ret .= html_wikilink(':'.$item['id'], useHeading('navigation') ? null : noNS($item['id']));
942
    }
943
    return $ret;
944
}
945
946
/**
947
 * Index List item
948
 *
949
 * This user function is used in html_buildlist to build the
950
 * <li> tags for namespaces when displaying the page index
951
 * it gives different classes to opened or closed "folders"
952
 *
953
 * @author Andreas Gohr <[email protected]>
954
 *
955
 * @param array $item
956
 * @return string html
957
 */
958
function html_li_index($item){
959
    global $INFO;
960
    global $ACT;
961
962
    $class = '';
963
    $id = '';
964
965
    if($item['type'] == "f"){
966
        // scroll to the current item
967
        if($item['id'] == $INFO['id'] && $ACT == 'index') {
968
            $id = ' id="scroll__here"';
969
            $class = ' bounce';
970
        }
971
        return '<li class="level'.$item['level'].$class.'" '.$id.'>';
972
    }elseif($item['open']){
973
        return '<li class="open">';
974
    }else{
975
        return '<li class="closed">';
976
    }
977
}
978
979
/**
980
 * Default List item
981
 *
982
 * @author Andreas Gohr <[email protected]>
983
 *
984
 * @param array $item
985
 * @return string html
986
 */
987
function html_li_default($item){
988
    return '<li class="level'.$item['level'].'">';
989
}
990
991
/**
992
 * Build an unordered list
993
 *
994
 * Build an unordered list from the given $data array
995
 * Each item in the array has to have a 'level' property
996
 * the item itself gets printed by the given $func user
997
 * function. The second and optional function is used to
998
 * print the <li> tag. Both user function need to accept
999
 * a single item.
1000
 *
1001
 * Both user functions can be given as array to point to
1002
 * a member of an object.
1003
 *
1004
 * @author Andreas Gohr <[email protected]>
1005
 *
1006
 * @param array    $data  array with item arrays
1007
 * @param string   $class class of ul wrapper
1008
 * @param callable $func  callback to print an list item
1009
 * @param callable $lifunc callback to the opening li tag
1010
 * @param bool     $forcewrapper Trigger building a wrapper ul if the first level is
1011
 *                               0 (we have a root object) or 1 (just the root content)
1012
 * @return string html of an unordered list
1013
 */
1014
function html_buildlist($data,$class,$func,$lifunc='html_li_default',$forcewrapper=false){
1015
    if (count($data) === 0) {
1016
        return '';
1017
    }
1018
1019
    $firstElement = reset($data);
1020
    $start_level = $firstElement['level'];
1021
    $level = $start_level;
1022
    $ret   = '';
1023
    $open  = 0;
1024
1025
    foreach ($data as $item){
1026
1027
        if( $item['level'] > $level ){
1028
            //open new list
1029
            for($i=0; $i<($item['level'] - $level); $i++){
1030
                if ($i) $ret .= "<li class=\"clear\">";
1031
                $ret .= "\n<ul class=\"$class\">\n";
1032
                $open++;
1033
            }
1034
            $level = $item['level'];
1035
1036
        }elseif( $item['level'] < $level ){
1037
            //close last item
1038
            $ret .= "</li>\n";
1039
            while( $level > $item['level'] && $open > 0 ){
1040
                //close higher lists
1041
                $ret .= "</ul>\n</li>\n";
1042
                $level--;
1043
                $open--;
1044
            }
1045
        } elseif ($ret !== '') {
1046
            //close previous item
1047
            $ret .= "</li>\n";
1048
        }
1049
1050
        //print item
1051
        $ret .= call_user_func($lifunc,$item);
1052
        $ret .= '<div class="li">';
1053
1054
        $ret .= call_user_func($func,$item);
1055
        $ret .= '</div>';
1056
    }
1057
1058
    //close remaining items and lists
1059
    $ret .= "</li>\n";
1060
    while($open-- > 0) {
1061
        $ret .= "</ul></li>\n";
1062
    }
1063
1064
    if ($forcewrapper || $start_level < 2) {
1065
        // Trigger building a wrapper ul if the first level is
1066
        // 0 (we have a root object) or 1 (just the root content)
1067
        $ret = "\n<ul class=\"$class\">\n".$ret."</ul>\n";
1068
    }
1069
1070
    return $ret;
1071
}
1072
1073
/**
1074
 * display backlinks
1075
 *
1076
 * @author Andreas Gohr <[email protected]>
1077
 * @author Michael Klier <[email protected]>
1078
 */
1079
function html_backlinks(){
1080
    global $ID;
1081
    global $lang;
1082
1083
    print p_locale_xhtml('backlinks');
1084
1085
    $data = ft_backlinks($ID);
1086
1087
    if(!empty($data)) {
1088
        print '<ul class="idx">';
1089
        foreach($data as $blink){
1090
            print '<li><div class="li">';
1091
            print html_wikilink(':'.$blink,useHeading('navigation')?null:$blink);
1092
            print '</div></li>';
1093
        }
1094
        print '</ul>';
1095
    } else {
1096
        print '<div class="level1"><p>' . $lang['nothingfound'] . '</p></div>';
1097
    }
1098
}
1099
1100
/**
1101
 * Get header of diff HTML
1102
 *
1103
 * @param string $l_rev   Left revisions
1104
 * @param string $r_rev   Right revision
1105
 * @param string $id      Page id, if null $ID is used
1106
 * @param bool   $media   If it is for media files
1107
 * @param bool   $inline  Return the header on a single line
1108
 * @return string[] HTML snippets for diff header
1109
 */
1110
function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) {
1111
    global $lang;
1112
    if ($id === null) {
1113
        global $ID;
1114
        $id = $ID;
1115
    }
1116
    $head_separator = $inline ? ' ' : '<br />';
1117
    $media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN';
1118
    $ml_or_wl = $media ? 'ml' : 'wl';
1119
    $l_minor = $r_minor = '';
1120
1121
    if($media) {
1122
        $changelog = new MediaChangeLog($id);
1123
    } else {
1124
        $changelog = new PageChangeLog($id);
1125
    }
1126
    if(!$l_rev){
1127
        $l_head = '&mdash;';
1128
    }else{
1129
        $l_info   = $changelog->getRevisionInfo($l_rev);
1130
        if($l_info['user']){
1131
            $l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>';
1132
            if(auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>';
1133
        } else {
1134
            $l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>';
1135
        }
1136
        $l_user  = '<span class="user">'.$l_user.'</span>';
1137
        $l_sum   = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : '';
1138
        if ($l_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"';
1139
1140
        $l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']';
1141
        $l_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$l_rev").'">'.
1142
        $l_head_title.'</a></bdi>'.
1143
        $head_separator.$l_user.' '.$l_sum;
1144
    }
1145
1146
    if($r_rev){
1147
        $r_info   = $changelog->getRevisionInfo($r_rev);
1148
        if($r_info['user']){
1149
            $r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>';
1150
            if(auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>';
1151
        } else {
1152
            $r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>';
1153
        }
1154
        $r_user = '<span class="user">'.$r_user.'</span>';
1155
        $r_sum  = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : '';
1156
        if ($r_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1157
1158
        $r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']';
1159
        $r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$r_rev").'">'.
1160
        $r_head_title.'</a></bdi>'.
1161
        $head_separator.$r_user.' '.$r_sum;
1162
    }elseif($_rev = @filemtime($media_or_wikiFN($id))){
1163
        $_info   = $changelog->getRevisionInfo($_rev);
1164
        if($_info['user']){
1165
            $_user = '<bdi>'.editorinfo($_info['user']).'</bdi>';
1166
            if(auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>';
1167
        } else {
1168
            $_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>';
1169
        }
1170
        $_user = '<span class="user">'.$_user.'</span>';
1171
        $_sum  = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : '';
1172
        if ($_info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
1173
1174
        $r_head_title = ($media) ? dformat($_rev) : $id.' ['.dformat($_rev).']';
1175
        $r_head  = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id).'">'.
1176
        $r_head_title.'</a></bdi> '.
1177
        '('.$lang['current'].')'.
1178
        $head_separator.$_user.' '.$_sum;
1179
    }else{
1180
        $r_head = '&mdash; ('.$lang['current'].')';
1181
    }
1182
1183
    return array($l_head, $r_head, $l_minor, $r_minor);
1184
}
1185
1186
/**
1187
 * Show diff
1188
 * between current page version and provided $text
1189
 * or between the revisions provided via GET or POST
1190
 *
1191
 * @author Andreas Gohr <[email protected]>
1192
 * @param  string $text  when non-empty: compare with this text with most current version
1193
 * @param  bool   $intro display the intro text
1194
 * @param  string $type  type of the diff (inline or sidebyside)
1195
 */
1196
function html_diff($text = '', $intro = true, $type = null) {
1197
    global $ID;
1198
    global $REV;
1199
    global $lang;
1200
    global $INPUT;
1201
    global $INFO;
1202
    $pagelog = new PageChangeLog($ID);
1203
1204
    /*
1205
     * Determine diff type
1206
     */
1207
    if(!$type) {
1208
        $type = $INPUT->str('difftype');
1209
        if(empty($type)) {
1210
            $type = get_doku_pref('difftype', $type);
1211
            if(empty($type) && $INFO['ismobile']) {
1212
                $type = 'inline';
1213
            }
1214
        }
1215
    }
1216
    if($type != 'inline') $type = 'sidebyside';
1217
1218
    /*
1219
     * Determine requested revision(s)
1220
     */
1221
    // we're trying to be clever here, revisions to compare can be either
1222
    // given as rev and rev2 parameters, with rev2 being optional. Or in an
1223
    // array in rev2.
1224
    $rev1 = $REV;
1225
1226
    $rev2 = $INPUT->ref('rev2');
1227
    if(is_array($rev2)) {
1228
        $rev1 = (int) $rev2[0];
1229
        $rev2 = (int) $rev2[1];
1230
1231
        if(!$rev1) {
1232
            $rev1 = $rev2;
1233
            unset($rev2);
1234
        }
1235
    } else {
1236
        $rev2 = $INPUT->int('rev2');
1237
    }
1238
1239
    /*
1240
     * Determine left and right revision, its texts and the header
1241
     */
1242
    $r_minor = '';
1243
    $l_minor = '';
1244
1245
    if($text) { // compare text to the most current revision
1246
        $l_rev = '';
1247
        $l_text = rawWiki($ID, '');
1248
        $l_head = '<a class="wikilink1" href="' . wl($ID) . '">' .
1249
            $ID . ' ' . dformat((int) @filemtime(wikiFN($ID))) . '</a> ' .
1250
            $lang['current'];
1251
1252
        $r_rev = '';
1253
        $r_text = cleanText($text);
1254
        $r_head = $lang['yours'];
1255
    } else {
1256
        if($rev1 && isset($rev2) && $rev2) { // two specific revisions wanted
1257
            // make sure order is correct (older on the left)
1258
            if($rev1 < $rev2) {
1259
                $l_rev = $rev1;
1260
                $r_rev = $rev2;
1261
            } else {
1262
                $l_rev = $rev2;
1263
                $r_rev = $rev1;
1264
            }
1265
        } elseif($rev1) { // single revision given, compare to current
1266
            $r_rev = '';
1267
            $l_rev = $rev1;
1268
        } else { // no revision was given, compare previous to current
1269
            $r_rev = '';
1270
            $revs = $pagelog->getRevisions(0, 1);
1271
            $l_rev = $revs[0];
1272
            $REV = $l_rev; // store revision back in $REV
1273
        }
1274
1275
        // when both revisions are empty then the page was created just now
1276
        if(!$l_rev && !$r_rev) {
1277
            $l_text = '';
1278
        } else {
1279
            $l_text = rawWiki($ID, $l_rev);
1280
        }
1281
        $r_text = rawWiki($ID, $r_rev);
1282
1283
        list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev, null, false, $type == 'inline');
1284
    }
1285
1286
    /*
1287
     * Build navigation
1288
     */
1289
    $l_nav = '';
1290
    $r_nav = '';
1291
    if(!$text) {
1292
        list($l_nav, $r_nav) = html_diff_navigation($pagelog, $type, $l_rev, $r_rev);
1293
    }
1294
    /*
1295
     * Create diff object and the formatter
1296
     */
1297
    $diff = new Diff(explode("\n", $l_text), explode("\n", $r_text));
1298
1299
    if($type == 'inline') {
1300
        $diffformatter = new InlineDiffFormatter();
1301
    } else {
1302
        $diffformatter = new TableDiffFormatter();
1303
    }
1304
    /*
1305
     * Display intro
1306
     */
1307
    if($intro) print p_locale_xhtml('diff');
1308
1309
    /*
1310
     * Display type and exact reference
1311
     */
1312
    if(!$text) {
1313
        ptln('<div class="diffoptions group">');
1314
1315
1316
        $form = new Doku_Form(array('action' => wl()));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1317
        $form->addHidden('id', $ID);
1318
        $form->addHidden('rev2[0]', $l_rev);
1319
        $form->addHidden('rev2[1]', $r_rev);
1320
        $form->addHidden('do', 'diff');
1321
        $form->addElement(
1322
             form_makeListboxField(
1323
                 'difftype',
1324
                 array(
1325
                     'sidebyside' => $lang['diff_side'],
1326
                     'inline' => $lang['diff_inline']
1327
                 ),
1328
                 $type,
1329
                 $lang['diff_type'],
1330
                 '', '',
1331
                 array('class' => 'quickselect')
1332
             )
1333
        );
1334
        $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1335
        $form->printForm();
1336
1337
        ptln('<p>');
1338
        // link to exactly this view FS#2835
1339
        echo html_diff_navigationlink($type, 'difflink', $l_rev, $r_rev ? $r_rev : $INFO['currentrev']);
1340
        ptln('</p>');
1341
1342
        ptln('</div>'); // .diffoptions
1343
    }
1344
1345
    /*
1346
     * Display diff view table
1347
     */
1348
    ?>
1349
    <div class="table">
1350
    <table class="diff diff_<?php echo $type ?>">
1351
1352
        <?php
1353
        //navigation and header
1354
        if($type == 'inline') {
1355
            if(!$text) { ?>
1356
                <tr>
1357
                    <td class="diff-lineheader">-</td>
1358
                    <td class="diffnav"><?php echo $l_nav ?></td>
1359
                </tr>
1360
                <tr>
1361
                    <th class="diff-lineheader">-</th>
1362
                    <th <?php echo $l_minor ?>>
1363
                        <?php echo $l_head ?>
1364
                    </th>
1365
                </tr>
1366
            <?php } ?>
1367
            <tr>
1368
                <td class="diff-lineheader">+</td>
1369
                <td class="diffnav"><?php echo $r_nav ?></td>
1370
            </tr>
1371
            <tr>
1372
                <th class="diff-lineheader">+</th>
1373
                <th <?php echo $r_minor ?>>
1374
                    <?php echo $r_head ?>
1375
                </th>
1376
            </tr>
1377
        <?php } else {
1378
            if(!$text) { ?>
1379
                <tr>
1380
                    <td colspan="2" class="diffnav"><?php echo $l_nav ?></td>
1381
                    <td colspan="2" class="diffnav"><?php echo $r_nav ?></td>
1382
                </tr>
1383
            <?php } ?>
1384
            <tr>
1385
                <th colspan="2" <?php echo $l_minor ?>>
1386
                    <?php echo $l_head ?>
1387
                </th>
1388
                <th colspan="2" <?php echo $r_minor ?>>
1389
                    <?php echo $r_head ?>
1390
                </th>
1391
            </tr>
1392
        <?php }
1393
1394
        //diff view
1395
        echo html_insert_softbreaks($diffformatter->format($diff)); ?>
1396
1397
    </table>
1398
    </div>
1399
<?php
1400
}
1401
1402
/**
1403
 * Create html for revision navigation
1404
 *
1405
 * @param PageChangeLog $pagelog changelog object of current page
1406
 * @param string        $type    inline vs sidebyside
1407
 * @param int           $l_rev   left revision timestamp
1408
 * @param int           $r_rev   right revision timestamp
1409
 * @return string[] html of left and right navigation elements
1410
 */
1411
function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) {
1412
    global $INFO, $ID;
1413
1414
    // last timestamp is not in changelog, retrieve timestamp from metadata
1415
    // note: when page is removed, the metadata timestamp is zero
1416
    if(!$r_rev) {
1417
        if(isset($INFO['meta']['last_change']['date'])) {
1418
            $r_rev = $INFO['meta']['last_change']['date'];
1419
        } else {
1420
            $r_rev = 0;
1421
        }
1422
    }
1423
1424
    //retrieve revisions with additional info
1425
    list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev);
1426
    $l_revisions = array();
1427
    if(!$l_rev) {
1428
        $l_revisions[0] = array(0, "", false); //no left revision given, add dummy
1429
    }
1430
    foreach($l_revs as $rev) {
1431
        $info = $pagelog->getRevisionInfo($rev);
1432
        $l_revisions[$rev] = array(
1433
            $rev,
1434
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1435
            $r_rev ? $rev >= $r_rev : false //disable?
1436
        );
1437
    }
1438
    $r_revisions = array();
1439
    if(!$r_rev) {
1440
        $r_revisions[0] = array(0, "", false); //no right revision given, add dummy
1441
    }
1442
    foreach($r_revs as $rev) {
1443
        $info = $pagelog->getRevisionInfo($rev);
1444
        $r_revisions[$rev] = array(
1445
            $rev,
1446
            dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'],
1447
            $rev <= $l_rev //disable?
1448
        );
1449
    }
1450
1451
    //determine previous/next revisions
1452
    $l_index = array_search($l_rev, $l_revs);
1453
    $l_prev = $l_revs[$l_index + 1];
1454
    $l_next = $l_revs[$l_index - 1];
1455
    if($r_rev) {
1456
        $r_index = array_search($r_rev, $r_revs);
1457
        $r_prev = $r_revs[$r_index + 1];
1458
        $r_next = $r_revs[$r_index - 1];
1459
    } else {
1460
        //removed page
1461
        if($l_next) {
1462
            $r_prev = $r_revs[0];
1463
        } else {
1464
            $r_prev = null;
1465
        }
1466
        $r_next = null;
1467
    }
1468
1469
    /*
1470
     * Left side:
1471
     */
1472
    $l_nav = '';
1473
    //move back
1474
    if($l_prev) {
1475
        $l_nav .= html_diff_navigationlink($type, 'diffbothprevrev', $l_prev, $r_prev);
1476
        $l_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_prev, $r_rev);
1477
    }
1478
    //dropdown
1479
    $form = new Doku_Form(array('action' => wl()));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1480
    $form->addHidden('id', $ID);
1481
    $form->addHidden('difftype', $type);
1482
    $form->addHidden('rev2[1]', $r_rev);
1483
    $form->addHidden('do', 'diff');
1484
    $form->addElement(
1485
         form_makeListboxField(
1486
             'rev2[0]',
1487
             $l_revisions,
1488
             $l_rev,
1489
             '', '', '',
1490
             array('class' => 'quickselect')
1491
         )
1492
    );
1493
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1494
    $l_nav .= $form->getForm();
1495
    //move forward
1496
    if($l_next && ($l_next < $r_rev || !$r_rev)) {
1497
        $l_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_next, $r_rev);
1498
    }
1499
1500
    /*
1501
     * Right side:
1502
     */
1503
    $r_nav = '';
1504
    //move back
1505
    if($l_rev < $r_prev) {
1506
        $r_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_rev, $r_prev);
1507
    }
1508
    //dropdown
1509
    $form = new Doku_Form(array('action' => wl()));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1510
    $form->addHidden('id', $ID);
1511
    $form->addHidden('rev2[0]', $l_rev);
1512
    $form->addHidden('difftype', $type);
1513
    $form->addHidden('do', 'diff');
1514
    $form->addElement(
1515
         form_makeListboxField(
1516
             'rev2[1]',
1517
             $r_revisions,
1518
             $r_rev,
1519
             '', '', '',
1520
             array('class' => 'quickselect')
1521
         )
1522
    );
1523
    $form->addElement(form_makeButton('submit', 'diff', 'Go'));
1524
    $r_nav .= $form->getForm();
1525
    //move forward
1526
    if($r_next) {
1527
        if($pagelog->isCurrentRevision($r_next)) {
1528
            $r_nav .= html_diff_navigationlink($type, 'difflastrev', $l_rev); //last revision is diff with current page
1529
        } else {
1530
            $r_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_rev, $r_next);
1531
        }
1532
        $r_nav .= html_diff_navigationlink($type, 'diffbothnextrev', $l_next, $r_next);
1533
    }
1534
    return array($l_nav, $r_nav);
1535
}
1536
1537
/**
1538
 * Create html link to a diff defined by two revisions
1539
 *
1540
 * @param string $difftype display type
1541
 * @param string $linktype
1542
 * @param int $lrev oldest revision
1543
 * @param int $rrev newest revision or null for diff with current revision
1544
 * @return string html of link to a diff
1545
 */
1546
function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) {
1547
    global $ID, $lang;
1548
    if(!$rrev) {
1549
        $urlparam = array(
1550
            'do' => 'diff',
1551
            'rev' => $lrev,
1552
            'difftype' => $difftype,
1553
        );
1554
    } else {
1555
        $urlparam = array(
1556
            'do' => 'diff',
1557
            'rev2[0]' => $lrev,
1558
            'rev2[1]' => $rrev,
1559
            'difftype' => $difftype,
1560
        );
1561
    }
1562
    return  '<a class="' . $linktype . '" href="' . wl($ID, $urlparam) . '" title="' . $lang[$linktype] . '">' .
1563
                '<span>' . $lang[$linktype] . '</span>' .
1564
            '</a>' . "\n";
1565
}
1566
1567
/**
1568
 * Insert soft breaks in diff html
1569
 *
1570
 * @param string $diffhtml
1571
 * @return string
1572
 */
1573
function html_insert_softbreaks($diffhtml) {
1574
    // search the diff html string for both:
1575
    // - html tags, so these can be ignored
1576
    // - long strings of characters without breaking characters
1577
    return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/','html_softbreak_callback',$diffhtml);
1578
}
1579
1580
/**
1581
 * callback which adds softbreaks
1582
 *
1583
 * @param array $match array with first the complete match
1584
 * @return string the replacement
1585
 */
1586
function html_softbreak_callback($match){
1587
    // if match is an html tag, return it intact
1588
    if ($match[0]{0} == '<') return $match[0];
1589
1590
    // its a long string without a breaking character,
1591
    // make certain characters into breaking characters by inserting a
1592
    // word break opportunity (<wbr> tag) in front of them.
1593
    $regex = <<< REGEX
1594
(?(?=              # start a conditional expression with a positive look ahead ...
1595
&\#?\\w{1,6};)     # ... for html entities - we don't want to split them (ok to catch some invalid combinations)
1596
&\#?\\w{1,6};      # yes pattern - a quicker match for the html entity, since we know we have one
1597
|
1598
[?/,&\#;:]         # no pattern - any other group of 'special' characters to insert a breaking character after
1599
)+                 # end conditional expression
1600
REGEX;
1601
1602
    return preg_replace('<'.$regex.'>xu','\0<wbr>',$match[0]);
1603
}
1604
1605
/**
1606
 * show warning on conflict detection
1607
 *
1608
 * @author Andreas Gohr <[email protected]>
1609
 *
1610
 * @param string $text
1611
 * @param string $summary
1612
 */
1613
function html_conflict($text,$summary){
1614
    global $ID;
1615
    global $lang;
1616
1617
    print p_locale_xhtml('conflict');
1618
    $form = new Doku_Form(array('id' => 'dw__editform'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1619
    $form->addHidden('id', $ID);
1620
    $form->addHidden('wikitext', $text);
1621
    $form->addHidden('summary', $summary);
1622
    $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('accesskey'=>'s')));
1623
    $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel']));
1624
    html_form('conflict', $form);
1625
    print '<br /><br /><br /><br />'.NL;
1626
}
1627
1628
/**
1629
 * Prints the global message array
1630
 *
1631
 * @author Andreas Gohr <[email protected]>
1632
 */
1633
function html_msgarea(){
1634
    global $MSG, $MSG_shown;
1635
    /** @var array $MSG */
1636
    // store if the global $MSG has already been shown and thus HTML output has been started
1637
    $MSG_shown = true;
1638
1639
    if(!isset($MSG)) return;
1640
1641
    $shown = array();
1642
    foreach($MSG as $msg){
1643
        $hash = md5($msg['msg']);
1644
        if(isset($shown[$hash])) continue; // skip double messages
1645
        if(info_msg_allowed($msg)){
1646
            print '<div class="'.$msg['lvl'].'">';
1647
            print $msg['msg'];
1648
            print '</div>';
1649
        }
1650
        $shown[$hash] = 1;
1651
    }
1652
1653
    unset($GLOBALS['MSG']);
1654
}
1655
1656
/**
1657
 * Prints the registration form
1658
 *
1659
 * @author Andreas Gohr <[email protected]>
1660
 */
1661
function html_register(){
1662
    global $lang;
1663
    global $conf;
1664
    global $INPUT;
1665
1666
    $base_attrs = array('size'=>50,'required'=>'required');
1667
    $email_attrs = $base_attrs + array('type'=>'email','class'=>'edit');
1668
1669
    print p_locale_xhtml('register');
1670
    print '<div class="centeralign">'.NL;
1671
    $form = new Doku_Form(array('id' => 'dw__register'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1672
    $form->startFieldset($lang['btn_register']);
1673
    $form->addHidden('do', 'register');
1674
    $form->addHidden('save', '1');
1675
    $form->addElement(
1676
        form_makeTextField(
1677
            'login',
1678
            $INPUT->post->str('login'),
1679
            $lang['user'],
1680
            '',
1681
            'block',
1682
            $base_attrs
1683
        )
1684
    );
1685
    if (!$conf['autopasswd']) {
1686
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', $base_attrs));
1687
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', $base_attrs));
1688
    }
1689
    $form->addElement(
1690
        form_makeTextField(
1691
            'fullname',
1692
            $INPUT->post->str('fullname'),
1693
            $lang['fullname'],
1694
            '',
1695
            'block',
1696
            $base_attrs
1697
        )
1698
    );
1699
    $form->addElement(
1700
        form_makeField(
1701
            'email',
1702
            'email',
1703
            $INPUT->post->str('email'),
1704
            $lang['email'],
1705
            '',
1706
            'block',
1707
            $email_attrs
1708
        )
1709
    );
1710
    $form->addElement(form_makeButton('submit', '', $lang['btn_register']));
1711
    $form->endFieldset();
1712
    html_form('register', $form);
1713
1714
    print '</div>'.NL;
1715
}
1716
1717
/**
1718
 * Print the update profile form
1719
 *
1720
 * @author Christopher Smith <[email protected]>
1721
 * @author Andreas Gohr <[email protected]>
1722
 */
1723
function html_updateprofile(){
1724
    global $lang;
1725
    global $conf;
1726
    global $INPUT;
1727
    global $INFO;
1728
    /** @var AuthPlugin $auth */
1729
    global $auth;
1730
1731
    print p_locale_xhtml('updateprofile');
1732
    print '<div class="centeralign">'.NL;
1733
1734
    $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true);
1735
    $email = $INPUT->post->str('email', $INFO['userinfo']['mail'], true);
1736
    $form = new Doku_Form(array('id' => 'dw__register'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1737
    $form->startFieldset($lang['profile']);
1738
    $form->addHidden('do', 'profile');
1739
    $form->addHidden('save', '1');
1740
    $form->addElement(
1741
        form_makeTextField(
1742
            'login',
1743
            $_SERVER['REMOTE_USER'],
1744
            $lang['user'],
1745
            '',
1746
            'block',
1747
            array('size' => '50', 'disabled' => 'disabled')
1748
        )
1749
    );
1750
    $attr = array('size'=>'50');
1751
    if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled';
1752
    $form->addElement(form_makeTextField('fullname', $fullname, $lang['fullname'], '', 'block', $attr));
1753
    $attr = array('size'=>'50', 'class'=>'edit');
1754
    if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled';
1755
    $form->addElement(form_makeField('email','email', $email, $lang['email'], '', 'block', $attr));
1756
    $form->addElement(form_makeTag('br'));
1757
    if ($auth->canDo('modPass')) {
1758
        $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50')));
1759
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1760
    }
1761
    if ($conf['profileconfirm']) {
1762
        $form->addElement(form_makeTag('br'));
1763
        $form->addElement(
1764
            form_makePasswordField(
1765
                'oldpass',
1766
                $lang['oldpass'],
1767
                '',
1768
                'block',
1769
                array('size' => '50', 'required' => 'required')
1770
            )
1771
        );
1772
    }
1773
    $form->addElement(form_makeButton('submit', '', $lang['btn_save']));
1774
    $form->addElement(form_makeButton('reset', '', $lang['btn_reset']));
1775
1776
    $form->endFieldset();
1777
    html_form('updateprofile', $form);
1778
1779
    if ($auth->canDo('delUser') && actionOK('profile_delete')) {
1780
        $form_profiledelete = new Doku_Form(array('id' => 'dw__profiledelete'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1781
        $form_profiledelete->startFieldset($lang['profdeleteuser']);
1782
        $form_profiledelete->addHidden('do', 'profile_delete');
1783
        $form_profiledelete->addHidden('delete', '1');
1784
        $form_profiledelete->addElement(
1785
            form_makeCheckboxField(
1786
                'confirm_delete',
1787
                '1',
1788
                $lang['profconfdelete'],
1789
                'dw__confirmdelete',
1790
                '',
1791
                array('required' => 'required')
1792
            )
1793
        );
1794
        if ($conf['profileconfirm']) {
1795
            $form_profiledelete->addElement(form_makeTag('br'));
1796
            $form_profiledelete->addElement(
1797
                form_makePasswordField(
1798
                    'oldpass',
1799
                    $lang['oldpass'],
1800
                    '',
1801
                    'block',
1802
                    array('size' => '50', 'required' => 'required')
1803
                )
1804
            );
1805
        }
1806
        $form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser']));
1807
        $form_profiledelete->endFieldset();
1808
1809
        html_form('profiledelete', $form_profiledelete);
1810
    }
1811
1812
    print '</div>'.NL;
1813
}
1814
1815
/**
1816
 * Preprocess edit form data
1817
 *
1818
 * @author   Andreas Gohr <[email protected]>
1819
 *
1820
 * @triggers HTML_EDITFORM_OUTPUT
1821
 */
1822
function html_edit(){
1823
    global $INPUT;
1824
    global $ID;
1825
    global $REV;
1826
    global $DATE;
1827
    global $PRE;
1828
    global $SUF;
1829
    global $INFO;
1830
    global $SUM;
1831
    global $lang;
1832
    global $conf;
1833
    global $TEXT;
1834
1835
    if ($INPUT->has('changecheck')) {
1836
        $check = $INPUT->str('changecheck');
1837
    } elseif(!$INFO['exists']){
1838
        // $TEXT has been loaded from page template
1839
        $check = md5('');
1840
    } else {
1841
        $check = md5($TEXT);
1842
    }
1843
    $mod = md5($TEXT) !== $check;
1844
1845
    $wr = $INFO['writable'] && !$INFO['locked'];
1846
    $include = 'edit';
1847
    if($wr){
1848
        if ($REV) $include = 'editrev';
1849
    }else{
1850
        // check pseudo action 'source'
1851
        if(!actionOK('source')){
1852
            msg('Command disabled: source',-1);
1853
            return;
1854
        }
1855
        $include = 'read';
1856
    }
1857
1858
    global $license;
1859
1860
    $form = new Doku_Form(array('id' => 'dw__editform'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
1861
    $form->addHidden('id', $ID);
1862
    $form->addHidden('rev', $REV);
1863
    $form->addHidden('date', $DATE);
1864
    $form->addHidden('prefix', $PRE . '.');
1865
    $form->addHidden('suffix', $SUF);
1866
    $form->addHidden('changecheck', $check);
1867
1868
    $data = array('form' => $form,
1869
                  'wr'   => $wr,
1870
                  'media_manager' => true,
1871
                  'target' => ($INPUT->has('target') && $wr) ? $INPUT->str('target') : 'section',
1872
                  'intro_locale' => $include);
1873
1874
    if ($data['target'] !== 'section') {
1875
        // Only emit event if page is writable, section edit data is valid and
1876
        // edit target is not section.
1877
        Event::createAndTrigger('HTML_EDIT_FORMSELECTION', $data, 'html_edit_form', true);
1878
    } else {
1879
        html_edit_form($data);
1880
    }
1881
    if (isset($data['intro_locale'])) {
1882
        echo p_locale_xhtml($data['intro_locale']);
1883
    }
1884
1885
    $form->addHidden('target', $data['target']);
1886
    if ($INPUT->has('hid')) {
1887
        $form->addHidden('hid', $INPUT->str('hid'));
1888
    }
1889
    if ($INPUT->has('codeblockOffset')) {
1890
        $form->addHidden('codeblockOffset', $INPUT->str('codeblockOffset'));
1891
    }
1892
    $form->addElement(form_makeOpenTag('div', array('id'=>'wiki__editbar', 'class'=>'editBar')));
1893
    $form->addElement(form_makeOpenTag('div', array('id'=>'size__ctl')));
1894
    $form->addElement(form_makeCloseTag('div'));
1895
    if ($wr) {
1896
        $form->addElement(form_makeOpenTag('div', array('class'=>'editButtons')));
1897
        $form->addElement(
1898
            form_makeButton(
1899
                'submit',
1900
                'save',
1901
                $lang['btn_save'],
1902
                array('id' => 'edbtn__save', 'accesskey' => 's', 'tabindex' => '4')
1903
            )
1904
        );
1905
        $form->addElement(
1906
            form_makeButton(
1907
                'submit',
1908
                'preview',
1909
                $lang['btn_preview'],
1910
                array('id' => 'edbtn__preview', 'accesskey' => 'p', 'tabindex' => '5')
1911
            )
1912
        );
1913
        $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel'], array('tabindex'=>'6')));
1914
        $form->addElement(form_makeCloseTag('div'));
1915
        $form->addElement(form_makeOpenTag('div', array('class'=>'summary')));
1916
        $form->addElement(
1917
            form_makeTextField(
1918
                'summary',
1919
                $SUM,
1920
                $lang['summary'],
1921
                'edit__summary',
1922
                'nowrap',
1923
                array('size' => '50', 'tabindex' => '2')
1924
            )
1925
        );
1926
        $elem = html_minoredit();
1927
        if ($elem) $form->addElement($elem);
1928
        $form->addElement(form_makeCloseTag('div'));
1929
    }
1930
    $form->addElement(form_makeCloseTag('div'));
1931
    if($wr && $conf['license']){
1932
        $form->addElement(form_makeOpenTag('div', array('class'=>'license')));
1933
        $out  = $lang['licenseok'];
1934
        $out .= ' <a href="'.$license[$conf['license']]['url'].'" rel="license" class="urlextern"';
1935
        if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
1936
        $out .= '>'.$license[$conf['license']]['name'].'</a>';
1937
        $form->addElement($out);
1938
        $form->addElement(form_makeCloseTag('div'));
1939
    }
1940
1941
    if ($wr) {
1942
        // sets changed to true when previewed
1943
        echo '<script type="text/javascript">/*<![CDATA[*/'. NL;
1944
        echo 'textChanged = ' . ($mod ? 'true' : 'false');
1945
        echo '/*!]]>*/</script>' . NL;
1946
    } ?>
1947
    <div class="editBox" role="application">
1948
1949
    <div class="toolbar group">
1950
        <div id="tool__bar" class="tool__bar"><?php
1951
            if ($wr && $data['media_manager']){
1952
                ?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
1953
                target="_blank"><?php echo $lang['mediaselect'] ?></a><?php
1954
            }?>
1955
        </div>
1956
    </div>
1957
    <div id="draft__status" class="draft__status">
1958
        <?php
1959
        $draft = new \dokuwiki\Draft($ID, $INFO['client']);
1960
        if ($draft->isDraftAvailable()) {
1961
            echo $draft->getDraftMessage();
1962
        }
1963
        ?>
1964
    </div>
1965
    <?php
1966
1967
    html_form('edit', $form);
1968
    print '</div>'.NL;
1969
}
1970
1971
/**
1972
 * Display the default edit form
1973
 *
1974
 * Is the default action for HTML_EDIT_FORMSELECTION.
1975
 *
1976
 * @param mixed[] $param
1977
 */
1978
function html_edit_form($param) {
1979
    global $TEXT;
1980
1981
    if ($param['target'] !== 'section') {
1982
        msg('No editor for edit target ' . hsc($param['target']) . ' found.', -1);
1983
    }
1984
1985
    $attr = array('tabindex'=>'1');
1986
    if (!$param['wr']) $attr['readonly'] = 'readonly';
1987
1988
    $param['form']->addElement(form_makeWikiText($TEXT, $attr));
1989
}
1990
1991
/**
1992
 * Adds a checkbox for minor edits for logged in users
1993
 *
1994
 * @author Andreas Gohr <[email protected]>
1995
 *
1996
 * @return array|bool
1997
 */
1998
function html_minoredit(){
1999
    global $conf;
2000
    global $lang;
2001
    global $INPUT;
2002
    // minor edits are for logged in users only
2003
    if(!$conf['useacl'] || !$_SERVER['REMOTE_USER']){
2004
        return false;
2005
    }
2006
2007
    $p = array();
2008
    $p['tabindex'] = 3;
2009
    if($INPUT->bool('minor')) $p['checked']='checked';
2010
    return form_makeCheckboxField('minor', '1', $lang['minoredit'], 'minoredit', 'nowrap', $p);
2011
}
2012
2013
/**
2014
 * prints some debug info
2015
 *
2016
 * @author Andreas Gohr <[email protected]>
2017
 */
2018
function html_debug(){
2019
    global $conf;
2020
    global $lang;
2021
    /** @var AuthPlugin $auth */
2022
    global $auth;
2023
    global $INFO;
2024
2025
    //remove sensitive data
2026
    $cnf = $conf;
2027
    debug_guard($cnf);
2028
    $nfo = $INFO;
2029
    debug_guard($nfo);
2030
    $ses = $_SESSION;
2031
    debug_guard($ses);
2032
2033
    print '<html><body>';
2034
2035
    print '<p>When reporting bugs please send all the following ';
2036
    print 'output as a mail to [email protected] ';
2037
    print 'The best way to do this is to save this page in your browser</p>';
2038
2039
    print '<b>$INFO:</b><pre>';
2040
    print_r($nfo);
2041
    print '</pre>';
2042
2043
    print '<b>$_SERVER:</b><pre>';
2044
    print_r($_SERVER);
2045
    print '</pre>';
2046
2047
    print '<b>$conf:</b><pre>';
2048
    print_r($cnf);
2049
    print '</pre>';
2050
2051
    print '<b>DOKU_BASE:</b><pre>';
2052
    print DOKU_BASE;
2053
    print '</pre>';
2054
2055
    print '<b>abs DOKU_BASE:</b><pre>';
2056
    print DOKU_URL;
2057
    print '</pre>';
2058
2059
    print '<b>rel DOKU_BASE:</b><pre>';
2060
    print dirname($_SERVER['PHP_SELF']).'/';
2061
    print '</pre>';
2062
2063
    print '<b>PHP Version:</b><pre>';
2064
    print phpversion();
2065
    print '</pre>';
2066
2067
    print '<b>locale:</b><pre>';
2068
    print setlocale(LC_ALL,0);
2069
    print '</pre>';
2070
2071
    print '<b>encoding:</b><pre>';
2072
    print $lang['encoding'];
2073
    print '</pre>';
2074
2075
    if($auth){
2076
        print '<b>Auth backend capabilities:</b><pre>';
2077
        foreach ($auth->getCapabilities() as $cando){
2078
            print '   '.str_pad($cando,16) . ' => ' . (int)$auth->canDo($cando) . NL;
2079
        }
2080
        print '</pre>';
2081
    }
2082
2083
    print '<b>$_SESSION:</b><pre>';
2084
    print_r($ses);
2085
    print '</pre>';
2086
2087
    print '<b>Environment:</b><pre>';
2088
    print_r($_ENV);
2089
    print '</pre>';
2090
2091
    print '<b>PHP settings:</b><pre>';
2092
    $inis = ini_get_all();
2093
    print_r($inis);
2094
    print '</pre>';
2095
2096
    if (function_exists('apache_get_version')) {
2097
        $apache = array();
2098
        $apache['version'] = apache_get_version();
2099
2100
        if (function_exists('apache_get_modules')) {
2101
            $apache['modules'] = apache_get_modules();
2102
        }
2103
        print '<b>Apache</b><pre>';
2104
        print_r($apache);
2105
        print '</pre>';
2106
    }
2107
2108
    print '</body></html>';
2109
}
2110
2111
/**
2112
 * Form to request a new password for an existing account
2113
 *
2114
 * @author Benoit Chesneau <[email protected]>
2115
 * @author Andreas Gohr <[email protected]>
2116
 */
2117
function html_resendpwd() {
2118
    global $lang;
2119
    global $conf;
2120
    global $INPUT;
2121
2122
    $token = preg_replace('/[^a-f0-9]+/','',$INPUT->str('pwauth'));
2123
2124
    if(!$conf['autopasswd'] && $token){
2125
        print p_locale_xhtml('resetpwd');
2126
        print '<div class="centeralign">'.NL;
2127
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
2128
        $form->startFieldset($lang['btn_resendpwd']);
2129
        $form->addHidden('token', $token);
2130
        $form->addHidden('do', 'resendpwd');
2131
2132
        $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50')));
2133
        $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
2134
2135
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2136
        $form->endFieldset();
2137
        html_form('resendpwd', $form);
2138
        print '</div>'.NL;
2139
    }else{
2140
        print p_locale_xhtml('resendpwd');
2141
        print '<div class="centeralign">'.NL;
2142
        $form = new Doku_Form(array('id' => 'dw__resendpwd'));
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

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

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

Loading history...
2143
        $form->startFieldset($lang['resendpwd']);
2144
        $form->addHidden('do', 'resendpwd');
2145
        $form->addHidden('save', '1');
2146
        $form->addElement(form_makeTag('br'));
2147
        $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block'));
2148
        $form->addElement(form_makeTag('br'));
2149
        $form->addElement(form_makeTag('br'));
2150
        $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
2151
        $form->endFieldset();
2152
        html_form('resendpwd', $form);
2153
        print '</div>'.NL;
2154
    }
2155
}
2156
2157
/**
2158
 * Return the TOC rendered to XHTML
2159
 *
2160
 * @author Andreas Gohr <[email protected]>
2161
 *
2162
 * @param array $toc
2163
 * @return string html
2164
 */
2165
function html_TOC($toc){
2166
    if(!count($toc)) return '';
2167
    global $lang;
2168
    $out  = '<!-- TOC START -->'.DOKU_LF;
2169
    $out .= '<div id="dw__toc" class="dw__toc">'.DOKU_LF;
2170
    $out .= '<h3 class="toggle">';
2171
    $out .= $lang['toc'];
2172
    $out .= '</h3>'.DOKU_LF;
2173
    $out .= '<div>'.DOKU_LF;
2174
    $out .= html_buildlist($toc,'toc','html_list_toc','html_li_default',true);
2175
    $out .= '</div>'.DOKU_LF.'</div>'.DOKU_LF;
2176
    $out .= '<!-- TOC END -->'.DOKU_LF;
2177
    return $out;
2178
}
2179
2180
/**
2181
 * Callback for html_buildlist
2182
 *
2183
 * @param array $item
2184
 * @return string html
2185
 */
2186
function html_list_toc($item){
2187
    if(isset($item['hid'])){
2188
        $link = '#'.$item['hid'];
2189
    }else{
2190
        $link = $item['link'];
2191
    }
2192
2193
    return '<a href="'.$link.'">'.hsc($item['title']).'</a>';
2194
}
2195
2196
/**
2197
 * Helper function to build TOC items
2198
 *
2199
 * Returns an array ready to be added to a TOC array
2200
 *
2201
 * @param string $link  - where to link (if $hash set to '#' it's a local anchor)
2202
 * @param string $text  - what to display in the TOC
2203
 * @param int    $level - nesting level
2204
 * @param string $hash  - is prepended to the given $link, set blank if you want full links
2205
 * @return array the toc item
2206
 */
2207
function html_mktocitem($link, $text, $level, $hash='#'){
2208
    return  array( 'link'  => $hash.$link,
2209
            'title' => $text,
2210
            'type'  => 'ul',
2211
            'level' => $level);
2212
}
2213
2214
/**
2215
 * Output a Doku_Form object.
2216
 * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT
2217
 *
2218
 * @author Tom N Harris <[email protected]>
2219
 *
2220
 * @param string     $name The name of the form
2221
 * @param Doku_Form  $form The form
2222
 */
2223
function html_form($name, &$form) {
2224
    // Safety check in case the caller forgets.
2225
    $form->endFieldset();
2226
    Event::createAndTrigger('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
2227
}
2228
2229
/**
2230
 * Form print function.
2231
 * Just calls printForm() on the data object.
2232
 *
2233
 * @param Doku_Form $data The form
2234
 */
2235
function html_form_output($data) {
2236
    $data->printForm();
2237
}
2238
2239
/**
2240
 * Embed a flash object in HTML
2241
 *
2242
 * This will create the needed HTML to embed a flash movie in a cross browser
2243
 * compatble way using valid XHTML
2244
 *
2245
 * The parameters $params, $flashvars and $atts need to be associative arrays.
2246
 * No escaping needs to be done for them. The alternative content *has* to be
2247
 * escaped because it is used as is. If no alternative content is given
2248
 * $lang['noflash'] is used.
2249
 *
2250
 * @author Andreas Gohr <[email protected]>
2251
 * @link   http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml
2252
 *
2253
 * @param string $swf      - the SWF movie to embed
2254
 * @param int $width       - width of the flash movie in pixels
2255
 * @param int $height      - height of the flash movie in pixels
2256
 * @param array $params    - additional parameters (<param>)
2257
 * @param array $flashvars - parameters to be passed in the flashvar parameter
2258
 * @param array $atts      - additional attributes for the <object> tag
2259
 * @param string $alt      - alternative content (is NOT automatically escaped!)
2260
 * @return string         - the XHTML markup
2261
 */
2262
function html_flashobject($swf,$width,$height,$params=null,$flashvars=null,$atts=null,$alt=''){
2263
    global $lang;
2264
2265
    $out = '';
2266
2267
    // prepare the object attributes
2268
    if(is_null($atts)) $atts = array();
2269
    $atts['width']  = (int) $width;
2270
    $atts['height'] = (int) $height;
2271
    if(!$atts['width'])  $atts['width']  = 425;
2272
    if(!$atts['height']) $atts['height'] = 350;
2273
2274
    // add object attributes for standard compliant browsers
2275
    $std = $atts;
2276
    $std['type'] = 'application/x-shockwave-flash';
2277
    $std['data'] = $swf;
2278
2279
    // add object attributes for IE
2280
    $ie  = $atts;
2281
    $ie['classid'] = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
2282
2283
    // open object (with conditional comments)
2284
    $out .= '<!--[if !IE]> -->'.NL;
2285
    $out .= '<object '.buildAttributes($std).'>'.NL;
2286
    $out .= '<!-- <![endif]-->'.NL;
2287
    $out .= '<!--[if IE]>'.NL;
2288
    $out .= '<object '.buildAttributes($ie).'>'.NL;
2289
    $out .= '    <param name="movie" value="'.hsc($swf).'" />'.NL;
2290
    $out .= '<!--><!-- -->'.NL;
2291
2292
    // print params
2293
    if(is_array($params)) foreach($params as $key => $val){
2294
        $out .= '  <param name="'.hsc($key).'" value="'.hsc($val).'" />'.NL;
2295
    }
2296
2297
    // add flashvars
2298
    if(is_array($flashvars)){
2299
        $out .= '  <param name="FlashVars" value="'.buildURLparams($flashvars).'" />'.NL;
2300
    }
2301
2302
    // alternative content
2303
    if($alt){
2304
        $out .= $alt.NL;
2305
    }else{
2306
        $out .= $lang['noflash'].NL;
2307
    }
2308
2309
    // finish
2310
    $out .= '</object>'.NL;
2311
    $out .= '<!-- <![endif]-->'.NL;
2312
2313
    return $out;
2314
}
2315
2316
/**
2317
 * Prints HTML code for the given tab structure
2318
 *
2319
 * @param array  $tabs        tab structure
2320
 * @param string $current_tab the current tab id
2321
 */
2322
function html_tabs($tabs, $current_tab = null) {
2323
    echo '<ul class="tabs">'.NL;
2324
2325
    foreach($tabs as $id => $tab) {
2326
        html_tab($tab['href'], $tab['caption'], $id === $current_tab);
2327
    }
2328
2329
    echo '</ul>'.NL;
2330
}
2331
2332
/**
2333
 * Prints a single tab
2334
 *
2335
 * @author Kate Arzamastseva <[email protected]>
2336
 * @author Adrian Lang <[email protected]>
2337
 *
2338
 * @param string $href - tab href
2339
 * @param string $caption - tab caption
2340
 * @param boolean $selected - is tab selected
2341
 */
2342
2343
function html_tab($href, $caption, $selected=false) {
2344
    $tab = '<li>';
2345
    if ($selected) {
2346
        $tab .= '<strong>';
2347
    } else {
2348
        $tab .= '<a href="' . hsc($href) . '">';
2349
    }
2350
    $tab .= hsc($caption)
2351
         .  '</' . ($selected ? 'strong' : 'a') . '>'
2352
         .  '</li>'.NL;
2353
    echo $tab;
2354
}
2355
2356
/**
2357
 * Display size change
2358
 *
2359
 * @param int $sizechange - size of change in Bytes
2360
 * @param Doku_Form $form - form to add elements to
2361
 */
2362
2363
function html_sizechange($sizechange, Doku_Form $form) {
2364
    if(isset($sizechange)) {
2365
        $class = 'sizechange';
2366
        $value = filesize_h(abs($sizechange));
2367
        if($sizechange > 0) {
2368
            $class .= ' positive';
2369
            $value = '+' . $value;
2370
        } elseif($sizechange < 0) {
2371
            $class .= ' negative';
2372
            $value = '-' . $value;
2373
        } else {
2374
            $value = '±' . $value;
2375
        }
2376
        $form->addElement(form_makeOpenTag('span', array('class' => $class)));
2377
        $form->addElement($value);
2378
        $form->addElement(form_makeCloseTag('span'));
2379
    }
2380
}
2381