xref: /dokuwiki/inc/Ui/Diff.php (revision 179b4660137f502a186abc8ff59180efd8707d10)
163ab9afeSSatoshi Sahara<?php
263ab9afeSSatoshi Sahara
363ab9afeSSatoshi Saharanamespace dokuwiki\Ui;
463ab9afeSSatoshi Sahara
563ab9afeSSatoshi Sahara/**
663ab9afeSSatoshi Sahara * DokuWiki Diff Interface
763ab9afeSSatoshi Sahara * parent class of PageDiff and MediaDiff
863ab9afeSSatoshi Sahara *
963ab9afeSSatoshi Sahara * @package dokuwiki\Ui
1063ab9afeSSatoshi Sahara */
1163ab9afeSSatoshi Saharaabstract class Diff extends Ui
1263ab9afeSSatoshi Sahara{
13edb50e6aSSatoshi Sahara    /* @var string */
14edb50e6aSSatoshi Sahara    protected $id;   // page id or media id
15e71e09a6SSatoshi Sahara    protected $item; // page or media
16edb50e6aSSatoshi Sahara
17b4b4c5c6SSatoshi Sahara    /* @var int */
18b4b4c5c6SSatoshi Sahara    protected $old_rev;  // older revision, timestamp of left side
19b4b4c5c6SSatoshi Sahara    protected $new_rev;  // newer revision, timestamp of right side
200bb448f0SSatoshi Sahara    protected $last_rev; // current revision, or last revision when it had removed
21b4b4c5c6SSatoshi Sahara
22edb50e6aSSatoshi Sahara    /* @var array */
23edb50e6aSSatoshi Sahara    protected $preference = [];
24edb50e6aSSatoshi Sahara
258068440fSSatoshi Sahara    /* @var ChangeLog */
268068440fSSatoshi Sahara    protected $changelog; // PageChangeLog or MediaChangeLog object
278068440fSSatoshi Sahara
28edb50e6aSSatoshi Sahara    /**
29edb50e6aSSatoshi Sahara     * Diff Ui constructor
30edb50e6aSSatoshi Sahara     *
31edb50e6aSSatoshi Sahara     * @param string $id  page id or media id
32edb50e6aSSatoshi Sahara     */
33edb50e6aSSatoshi Sahara    public function __construct($id)
34edb50e6aSSatoshi Sahara    {
35edb50e6aSSatoshi Sahara        $this->id = $id;
368068440fSSatoshi Sahara        $this->setChangeLog();
37edb50e6aSSatoshi Sahara    }
38edb50e6aSSatoshi Sahara
39edb50e6aSSatoshi Sahara    /**
408068440fSSatoshi Sahara     * set class property changelog
418068440fSSatoshi Sahara     */
428068440fSSatoshi Sahara    abstract protected function setChangeLog();
438068440fSSatoshi Sahara
448068440fSSatoshi Sahara    /**
45b4b4c5c6SSatoshi Sahara     * Set a pair of revisions to be compared
46b4b4c5c6SSatoshi Sahara     *
47b4b4c5c6SSatoshi Sahara     * @param int $old_rev
48b4b4c5c6SSatoshi Sahara     * @param int $new_rev
49b4b4c5c6SSatoshi Sahara     * @return $this
50b4b4c5c6SSatoshi Sahara     */
51b4b4c5c6SSatoshi Sahara    public function compare($old_rev, $new_rev)
52b4b4c5c6SSatoshi Sahara    {
53b4b4c5c6SSatoshi Sahara        $this->old_rev = $old_rev;
54b4b4c5c6SSatoshi Sahara        $this->new_rev = $new_rev;
55b4b4c5c6SSatoshi Sahara        return $this;
56b4b4c5c6SSatoshi Sahara    }
57b4b4c5c6SSatoshi Sahara
58b4b4c5c6SSatoshi Sahara    /**
59edb50e6aSSatoshi Sahara     * Gets or Sets preference of the Ui\Diff object
60edb50e6aSSatoshi Sahara     *
61edb50e6aSSatoshi Sahara     * @param string|array $prefs  a key name or key-value pair(s)
62edb50e6aSSatoshi Sahara     * @param mixed $value         value used when the first args is string
63edb50e6aSSatoshi Sahara     * @return array|$this
64edb50e6aSSatoshi Sahara     */
65edb50e6aSSatoshi Sahara    public function preference($prefs = null, $value = null)
66edb50e6aSSatoshi Sahara    {
67edb50e6aSSatoshi Sahara        // set
68295564cdSSatoshi Sahara        if (is_string($prefs) && isset($value)) {
69295564cdSSatoshi Sahara            $this->preference[$prefs] = $value;
70295564cdSSatoshi Sahara            return $this;
71295564cdSSatoshi Sahara        } elseif (is_array($prefs)) {
72edb50e6aSSatoshi Sahara            foreach ($prefs as $name => $value) {
73edb50e6aSSatoshi Sahara                $this->preference[$name] = $value;
74edb50e6aSSatoshi Sahara            }
75edb50e6aSSatoshi Sahara            return $this;
76edb50e6aSSatoshi Sahara        }
77edb50e6aSSatoshi Sahara        // get
78edb50e6aSSatoshi Sahara        return $this->preference;
79edb50e6aSSatoshi Sahara    }
80edb50e6aSSatoshi Sahara
81b4b4c5c6SSatoshi Sahara    /**
82b4b4c5c6SSatoshi Sahara     * Retrieve requested revision(s) and difftype from Ui\Revisions
83b4b4c5c6SSatoshi Sahara     *
84b4b4c5c6SSatoshi Sahara     * @return void
85b4b4c5c6SSatoshi Sahara     */
86b4b4c5c6SSatoshi Sahara    protected function preProcess()
87b4b4c5c6SSatoshi Sahara    {
88b4b4c5c6SSatoshi Sahara        global $INPUT;
89b4b4c5c6SSatoshi Sahara
90b4b4c5c6SSatoshi Sahara        // difflink icon click, eg. ?rev=123456789&do=diff
91b4b4c5c6SSatoshi Sahara        if ($INPUT->has('rev')) {
92b4b4c5c6SSatoshi Sahara            $this->old_rev = $INPUT->int('rev');
93b4b4c5c6SSatoshi Sahara            $this->new_rev = ''; // current revision
94b4b4c5c6SSatoshi Sahara        }
95b4b4c5c6SSatoshi Sahara
96b4b4c5c6SSatoshi Sahara        // submit button with two checked boxes
97b4b4c5c6SSatoshi Sahara        $rev2 = $INPUT->arr('rev2', []);
98b4b4c5c6SSatoshi Sahara        if (count($rev2) > 1) {
99b4b4c5c6SSatoshi Sahara            if ($rev2[0] == 'current') {
100b4b4c5c6SSatoshi Sahara                [$this->old_rev, $this->new_rev] = [$rev2[1], ''];
101b4b4c5c6SSatoshi Sahara            } elseif ($rev2[1] == 'current') {
102b4b4c5c6SSatoshi Sahara                [$this->old_rev, $this->new_rev] = [$rev2[0], ''];
103b4b4c5c6SSatoshi Sahara            } elseif ($rev2[0] < $rev2[1]) {
104b4b4c5c6SSatoshi Sahara                [$this->old_rev, $this->new_rev] = [$rev2[0], $rev2[1]];
105b4b4c5c6SSatoshi Sahara            } else {
106b4b4c5c6SSatoshi Sahara                [$this->old_rev, $this->new_rev] = [$rev2[1], $rev2[0]];
107b4b4c5c6SSatoshi Sahara            }
108b4b4c5c6SSatoshi Sahara        }
109b4b4c5c6SSatoshi Sahara
110b4b4c5c6SSatoshi Sahara        // diff view type
111b4b4c5c6SSatoshi Sahara        if ($INPUT->has('difftype')) {
112b4b4c5c6SSatoshi Sahara            // retrieve requested $difftype
113b4b4c5c6SSatoshi Sahara            $this->preference['difftype'] = $INPUT->str('difftype');
114b4b4c5c6SSatoshi Sahara        } else {
115b4b4c5c6SSatoshi Sahara            // read preference from DokuWiki cookie. PageDiff only
11691e70b5fSSatoshi Sahara            get_doku_pref('difftype', $mode);
11791e70b5fSSatoshi Sahara            if (isset($mode)) $this->preference['difftype'] = $mode;
118b4b4c5c6SSatoshi Sahara        }
119b4b4c5c6SSatoshi Sahara    }
120b4b4c5c6SSatoshi Sahara
121*179b4660SSatoshi Sahara    /**
122*179b4660SSatoshi Sahara     * get extended revision info
123*179b4660SSatoshi Sahara     *
124*179b4660SSatoshi Sahara     * @param int|string $rev  revision identifier, '' means current one
125*179b4660SSatoshi Sahara     * @return array  revision info structure of a page or media file
126*179b4660SSatoshi Sahara     */
127*179b4660SSatoshi Sahara    protected function getExtendedRevisionInfo($rev)
128*179b4660SSatoshi Sahara    {
129*179b4660SSatoshi Sahara        $changelog =& $this->changelog;
130*179b4660SSatoshi Sahara
131*179b4660SSatoshi Sahara        if ($rev) {
132*179b4660SSatoshi Sahara            $info = $changelog->getRevisionInfo($rev);
133*179b4660SSatoshi Sahara        } elseif (file_exists($filename = $this->itemFN($this->id))) {
134*179b4660SSatoshi Sahara            $rev = filemtime(fullpath($filename));
135*179b4660SSatoshi Sahara            $info = $changelog->getRevisionInfo($rev) + array(
136*179b4660SSatoshi Sahara                'current' => true,
137*179b4660SSatoshi Sahara            );
138*179b4660SSatoshi Sahara        } else { // once exists, but now removed
139*179b4660SSatoshi Sahara            $info = array(
140*179b4660SSatoshi Sahara                'current' => true,
141*179b4660SSatoshi Sahara            );
142*179b4660SSatoshi Sahara        }
143*179b4660SSatoshi Sahara        return array('item' => $this->item) + $info;
144*179b4660SSatoshi Sahara    }
145*179b4660SSatoshi Sahara
146b4b4c5c6SSatoshi Sahara
147edb50e6aSSatoshi Sahara
14863ab9afeSSatoshi Sahara    /**
149ec019cbfSSatoshi Sahara     * Build header of diff HTML
15063ab9afeSSatoshi Sahara     *
15163ab9afeSSatoshi Sahara     * @param string $l_rev   Left revisions
15263ab9afeSSatoshi Sahara     * @param string $r_rev   Right revision
15363ab9afeSSatoshi Sahara     * @return string[] HTML snippets for diff header
15463ab9afeSSatoshi Sahara     */
1558068440fSSatoshi Sahara    public function buildDiffHead($l_rev, $r_rev)
15663ab9afeSSatoshi Sahara    {
15763ab9afeSSatoshi Sahara        global $lang;
158edb50e6aSSatoshi Sahara
159e71e09a6SSatoshi Sahara        $changelog =& $this->changelog;
160e71e09a6SSatoshi Sahara
161e71e09a6SSatoshi Sahara        switch ($this->item) {
162e71e09a6SSatoshi Sahara            case 'page':
1630bb448f0SSatoshi Sahara                $isMedia = false;
1640bb448f0SSatoshi Sahara                $ui = new PageRevisions($this->id);
165edb50e6aSSatoshi Sahara                break;
166e71e09a6SSatoshi Sahara            case 'media':
1670bb448f0SSatoshi Sahara                $isMedia = true;
1680bb448f0SSatoshi Sahara                $ui = new MediaRevisions($this->id);
169edb50e6aSSatoshi Sahara                break;
17063ab9afeSSatoshi Sahara        }
171edb50e6aSSatoshi Sahara
172edb50e6aSSatoshi Sahara        $head_separator = ($this->preference['difftype'] === 'inline') ? ' ' : '<br />';
1730bb448f0SSatoshi Sahara
1740bb448f0SSatoshi Sahara        // assign minor edit checker to the variable
175e71e09a6SSatoshi Sahara        $isMinorEdit = function ($info) {
176e71e09a6SSatoshi Sahara            return ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT);
1770bb448f0SSatoshi Sahara        };
1780bb448f0SSatoshi Sahara
1790bb448f0SSatoshi Sahara        // assign title builder to the variable
180e71e09a6SSatoshi Sahara        $itemTitle = function ($id, $rev = '') use ($isMedia) {
1810bb448f0SSatoshi Sahara            return ($isMedia) ? dformat($rev) : $id.' ['.dformat($rev).']';
1820bb448f0SSatoshi Sahara        };
18363ab9afeSSatoshi Sahara
184edb50e6aSSatoshi Sahara        // left side
18563ab9afeSSatoshi Sahara        if (!$l_rev) {
1860bb448f0SSatoshi Sahara            $l_minor = '';
18763ab9afeSSatoshi Sahara            $l_head = '&mdash;';
18863ab9afeSSatoshi Sahara        } else {
189e71e09a6SSatoshi Sahara            $info = $changelog->getRevisionInfo($l_rev);
1900bb448f0SSatoshi Sahara            $objRevInfo = $ui->getObjRevInfo($info);
191e71e09a6SSatoshi Sahara            $l_minor = $isMinorEdit($info) ? ' class="minor"' : '';
192e71e09a6SSatoshi Sahara            $l_head = '<bdi>'
193e71e09a6SSatoshi Sahara                    .'<a class="wikilink1" href="'.$this->itemUrl($this->id, "rev=$l_rev").'">'
194e71e09a6SSatoshi Sahara                    .$itemTitle($this->id, $l_rev).'</a></bdi>'.$head_separator
1950bb448f0SSatoshi Sahara                    .$objRevInfo->editor().' '.$objRevInfo->editSummary();
19663ab9afeSSatoshi Sahara        }
19763ab9afeSSatoshi Sahara
198edb50e6aSSatoshi Sahara        // right side
19963ab9afeSSatoshi Sahara        if ($r_rev) {
200e71e09a6SSatoshi Sahara            $info  = $changelog->getRevisionInfo($r_rev);
2010bb448f0SSatoshi Sahara            $objRevInfo = $ui->getObjRevInfo($info);
202e71e09a6SSatoshi Sahara            $r_minor = $isMinorEdit($info) ? ' class="minor"' : '';
203e71e09a6SSatoshi Sahara            $r_head = '<bdi>'
204e71e09a6SSatoshi Sahara                    .'<a class="wikilink1" href="'.$this->itemUrl($this->id, "rev=$r_rev").'">'
205e71e09a6SSatoshi Sahara                    .$itemTitle($this->id, $r_rev).'</a></bdi>'.$head_separator
2060bb448f0SSatoshi Sahara                    .$objRevInfo->editor().' '.$objRevInfo->editSummary();
2070bb448f0SSatoshi Sahara        } elseif ($this->last_rev) {
2080bb448f0SSatoshi Sahara            $_rev = $this->last_rev;
209e71e09a6SSatoshi Sahara            $info = $changelog->getRevisionInfo($_rev);
2100bb448f0SSatoshi Sahara            $objRevInfo = $ui->getObjRevInfo($info);
211e71e09a6SSatoshi Sahara            $r_minor = $isMinorEdit($info) ? ' class="minor"' : '';
212e71e09a6SSatoshi Sahara            $r_head  = '<bdi>'
213e71e09a6SSatoshi Sahara                     .'<a class="wikilink1" href="'.$this->itemUrl($this->id).'">'
214e71e09a6SSatoshi Sahara                     .$itemTitle($this->id, $_rev).'</a></bdi> '.'('.$lang['current'].')'.$head_separator
2150bb448f0SSatoshi Sahara                     .$objRevInfo->editor().' '.$objRevInfo->editSummary();
21663ab9afeSSatoshi Sahara        } else {
2170bb448f0SSatoshi Sahara            $r_minor = '';
21863ab9afeSSatoshi Sahara            $r_head = '&mdash; ('.$lang['current'].')';
21963ab9afeSSatoshi Sahara        }
22063ab9afeSSatoshi Sahara
22163ab9afeSSatoshi Sahara        return array($l_head, $r_head, $l_minor, $r_minor);
22263ab9afeSSatoshi Sahara    }
22363ab9afeSSatoshi Sahara
224e71e09a6SSatoshi Sahara    /**
225e71e09a6SSatoshi Sahara     * item url generator
226e71e09a6SSatoshi Sahara     *
227e71e09a6SSatoshi Sahara     * @param string $id  page id or media id
228e71e09a6SSatoshi Sahara     * @param string|array $urlParameters  URL parameters, associative array recommended
229e71e09a6SSatoshi Sahara     * @return string
230e71e09a6SSatoshi Sahara     */
231e71e09a6SSatoshi Sahara    protected function itemUrl($id, $urlParameters = '')
232e71e09a6SSatoshi Sahara    {
233e71e09a6SSatoshi Sahara        switch ($this->item) {
234e71e09a6SSatoshi Sahara            case 'page':  return wl($id, $urlParameters, $absolute = false, '&');
235e71e09a6SSatoshi Sahara            case 'media': return ml($id, $urlParameters, $direct = true, '&', $absolute = false);
236e71e09a6SSatoshi Sahara        }
237e71e09a6SSatoshi Sahara    }
238e71e09a6SSatoshi Sahara
239*179b4660SSatoshi Sahara    /**
240*179b4660SSatoshi Sahara     * item filename resolver
241*179b4660SSatoshi Sahara     *
242*179b4660SSatoshi Sahara     * @param string $id  page id or media id
243*179b4660SSatoshi Sahara     * @param string|int $rev empty string or revision timestamp
244*179b4660SSatoshi Sahara     * @return string
245*179b4660SSatoshi Sahara     */
246*179b4660SSatoshi Sahara    protected function itemFN($id, $rev = '')
247*179b4660SSatoshi Sahara    {
248*179b4660SSatoshi Sahara        switch ($this->item) {
249*179b4660SSatoshi Sahara            case 'page':  return wikiFN($id, $rev);
250*179b4660SSatoshi Sahara            case 'media': return mediaFN($id, $rev);
251*179b4660SSatoshi Sahara        }
252*179b4660SSatoshi Sahara    }
253*179b4660SSatoshi Sahara
25463ab9afeSSatoshi Sahara}
255