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