xref: /dokuwiki/inc/Ui/Diff.php (revision 48d75c0057e32072269dab43372c65184dcf6649)
1<?php
2
3namespace dokuwiki\Ui;
4
5use dokuwiki\ChangeLog\PageChangeLog;
6use dokuwiki\ChangeLog\MediaChangeLog;
7
8/**
9 * DokuWiki Diff Interface
10 * parent class of PageDiff and MediaDiff
11 *
12 * @package dokuwiki\Ui
13 */
14abstract class Diff extends Ui
15{
16    /* @var string */
17    protected $id;  // page id or media id
18
19    /* @var int */
20    protected $old_rev; // older revision, timestamp of left side
21    protected $new_rev; // newer revision, timestamp of right side
22
23    /* @var array */
24    protected $preference = [];
25
26    /* @var ChangeLog */
27    protected $changelog; // PageChangeLog or MediaChangeLog object
28
29    /**
30     * Diff Ui constructor
31     *
32     * @param string $id  page id or media id
33     */
34    public function __construct($id)
35    {
36        $this->id = $id;
37        $this->setChangeLog();
38    }
39
40    /**
41     * set class property changelog
42     */
43    abstract protected function setChangeLog();
44
45    /**
46     * Set a pair of revisions to be compared
47     *
48     * @param int $old_rev
49     * @param int $new_rev
50     * @return $this
51     */
52    public function compare($old_rev, $new_rev)
53    {
54        $this->old_rev = $old_rev;
55        $this->new_rev = $new_rev;
56        return $this;
57    }
58
59    /**
60     * Gets or Sets preference of the Ui\Diff object
61     *
62     * @param string|array $prefs  a key name or key-value pair(s)
63     * @param mixed $value         value used when the first args is string
64     * @return array|$this
65     */
66    public function preference($prefs = null, $value = null)
67    {
68        // set
69        if (is_string($prefs) && isset($value)) {
70            $this->preference[$prefs] = $value;
71            return $this;
72        } elseif (is_array($prefs)) {
73            foreach ($prefs as $name => $value) {
74                $this->preference[$name] = $value;
75            }
76            return $this;
77        }
78        // get
79        return $this->preference;
80    }
81
82    /**
83     * Retrieve requested revision(s) and difftype from Ui\Revisions
84     *
85     * @return void
86     */
87    protected function preProcess()
88    {
89        global $INPUT;
90
91        // difflink icon click, eg. ?rev=123456789&do=diff
92        if ($INPUT->has('rev')) {
93            $this->old_rev = $INPUT->int('rev');
94            $this->new_rev = ''; // current revision
95        }
96
97        // submit button with two checked boxes
98        $rev2 = $INPUT->arr('rev2', []);
99        if (count($rev2) > 1) {
100            if ($rev2[0] == 'current') {
101                [$this->old_rev, $this->new_rev] = [$rev2[1], ''];
102            } elseif ($rev2[1] == 'current') {
103                [$this->old_rev, $this->new_rev] = [$rev2[0], ''];
104            } elseif ($rev2[0] < $rev2[1]) {
105                [$this->old_rev, $this->new_rev] = [$rev2[0], $rev2[1]];
106            } else {
107                [$this->old_rev, $this->new_rev] = [$rev2[1], $rev2[0]];
108            }
109        }
110
111        // diff view type
112        if ($INPUT->has('difftype')) {
113            // retrieve requested $difftype
114            $this->preference['difftype'] = $INPUT->str('difftype');
115        } else {
116            // read preference from DokuWiki cookie. PageDiff only
117            get_doku_pref('difftype', $mode);
118            if (isset($mode)) $this->preference['difftype'] = $mode;
119        }
120    }
121
122
123
124    /**
125     * Build header of diff HTML
126     *
127     * @param string $l_rev   Left revisions
128     * @param string $r_rev   Right revision
129     * @return string[] HTML snippets for diff header
130     */
131    public function buildDiffHead($l_rev, $r_rev)
132    {
133        global $lang;
134
135        // detect PageDiff or MediaDiff
136        switch (get_class($this->changelog)) {
137            case PageChangeLog::class :
138                $media_or_wikiFN = 'wikiFN';
139                $ml_or_wl = 'wl';
140                $media = false;
141                break;
142            case MediaChangeLog::class :
143                $media_or_wikiFN = 'mediaFN';
144                $ml_or_wl = 'ml';
145                $media = true;
146                break;
147        }
148
149        $head_separator = ($this->preference['difftype'] === 'inline') ? ' ' : '<br />';
150        $l_minor = $r_minor = '';
151
152        // left side
153        if (!$l_rev) {
154            $l_head = '&mdash;';
155        } else {
156            $l_info = $this->changelog->getRevisionInfo($l_rev);
157            if ($l_info['user']) {
158                $l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>';
159                if (auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>';
160            } else {
161                $l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>';
162            }
163            $l_user = '<span class="user">'.$l_user.'</span>';
164            $l_sum  = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : '';
165            if ($l_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"';
166
167            $l_head_title = ($media) ? dformat($l_rev) : $this->id.' ['.dformat($l_rev).']';
168            $l_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($this->id,"rev=$l_rev").'">'
169                . $l_head_title.'</a></bdi>'.$head_separator.$l_user.' '.$l_sum;
170        }
171
172        // right side
173        if ($r_rev) {
174            $r_info  = $this->changelog->getRevisionInfo($r_rev);
175            if ($r_info['user']) {
176                $r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>';
177                if (auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>';
178            } else {
179                $r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>';
180            }
181            $r_user = '<span class="user">'.$r_user.'</span>';
182            $r_sum  = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : '';
183            if ($r_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
184
185            $r_head_title = ($media) ? dformat($r_rev) : $this->id.' ['.dformat($r_rev).']';
186            $r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($this->id,"rev=$r_rev").'">'
187                . $r_head_title.'</a></bdi>'.$head_separator.$r_user.' '.$r_sum;
188        } elseif ($_rev = @filemtime($media_or_wikiFN($this->id))) {
189            $_info = $this->changelog->getRevisionInfo($_rev);
190            if ($_info['user']) {
191                $_user = '<bdi>'.editorinfo($_info['user']).'</bdi>';
192                if (auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>';
193            } else {
194                $_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>';
195            }
196            $_user = '<span class="user">'.$_user.'</span>';
197            $_sum  = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : '';
198            if ($_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
199
200            $r_head_title = ($media) ? dformat($_rev) : $this->id.' ['.dformat($_rev).']';
201            $r_head  = '<bdi><a class="wikilink1" href="'.$ml_or_wl($this->id).'">'
202                . $r_head_title.'</a></bdi> '.'('.$lang['current'].')'.$head_separator.$_user.' '.$_sum;
203        } else {
204            $r_head = '&mdash; ('.$lang['current'].')';
205        }
206
207        return array($l_head, $r_head, $l_minor, $r_minor);
208    }
209
210}
211