xref: /dokuwiki/inc/ChangeLog/RevisionInfo.php (revision de8ed963685edd0f0fc714932fe885d312cca026)
1<?php
2
3namespace dokuwiki\ChangeLog;
4
5/**
6 * Class RevisionInfo
7 *
8 * Provides methods to show Revision Information in DokuWiki Ui compoments:
9 *  - Ui\Recent
10 *  - Ui\PageRevisions
11 *  - Ui\MediaRevisions
12 */
13class RevisionInfo
14{
15    protected $info;
16
17    /**
18     * Constructor
19     *
20     * @param array $info Revision Infomation structure with entries:
21     *      - date:  unix timestamp
22     *      - ip:    IPv4 or IPv6 address
23     *      - type:  change type (log line type)
24     *      - id:    page id
25     *      - user:  user name
26     *      - sum:   edit summary (or action reason)
27     *      - extra: extra data (varies by line type)
28     *      - sizechange: change of filesize
29     *      additionally,
30     *      - current:   (optional) whether current revison or not
31     *      - timestamp: (optional) set only when external edits occurred
32     */
33    public function __construct(array $info)
34    {
35        $info['item'] = strrpos($info['id'], '.') ? 'media' : 'page';
36        // current is always true for irems shown in Ui\Recents
37        $info['current'] = $info['current'] ?? true;
38        // revision info may have timestamp key when external edits occurred
39        $info['timestamp'] = $info['timestamp'] ?? true;
40
41        $this->info = $info;
42    }
43
44    /**
45     * fileicon of the page or media file
46     * used in [Ui\recent]
47     *
48     * @return string
49     */
50    public function itemIcon()
51    {
52        $id = $this->info['id'];
53        $html = '';
54        switch ($this->info['item']) {
55            case 'media': // media file revision
56                $html = media_printicon($id);
57                break;
58            case 'page': // page revision
59                $html = '<img class="icon" src="'.DOKU_BASE.'lib/images/fileicons/file.png" alt="'.$id.'" />';
60        }
61        return $html;
62    }
63
64    /**
65     * edit date and time of the page or media file
66     * used in [Ui\recent, Ui\Revisions]
67     *
68     * @param bool $checkTimestamp  enable timestamp check, alter formatted string when timestamp is false
69     * @return string
70     */
71    public function editDate($checkTimestamp = false)
72    {
73        $formatted = dformat($this->info['date']);
74        if ($checkTimestamp && $this->info['timestamp'] === false) {
75            // exact date is unknown for item has externally deleted or older file restored
76            // when unknown, alter formatted string "YYYY-mm-DD HH:MM" to "____-__-__ __:__"
77            $formatted = preg_replace('/[0-9a-zA-Z]/','_', $formatted);
78        }
79        return '<span class="date">'. $formatted .'</span>';
80    }
81
82    /**
83     * edit summary
84     * used in [Ui\recent, Ui\Revisions]
85     *
86     * @return string
87     */
88    public function editSummary()
89    {
90        return '<span class="sum">'.' – '. hsc($this->info['sum']).'</span>';
91    }
92
93    /**
94     * editor of the page or media file
95     * used in [Ui\recent, Ui\Revisions]
96     *
97     * @return string
98     */
99    public function editor()
100    {
101        $html = '<span class="user">';
102        if ($this->info['user']) {
103            $html.= '<bdi>'. editorinfo($this->info['user']) .'</bdi>';
104            if (auth_ismanager()) $html.= ' <bdo dir="ltr">('. $this->info['ip'] .')</bdo>';
105        } else {
106            $html.= '<bdo dir="ltr">'. $this->info['ip'] .'</bdo>';
107        }
108        $html.= '</span>';
109        return $html;
110    }
111
112    /**
113     * name of the page or media file
114     * used in [Ui\recent, Ui\Revisions]
115     *
116     * @return string
117     */
118    public function itemName()
119    {
120        $id = $this->info['id'];
121        $rev = ($this->info['current']) ? '' : $this->info['date'];
122
123        switch ($this->info['item']) {
124            case 'media': // media file revision
125                $params = ['tab_details'=> 'view', 'ns'=> getNS($id), 'image'=> $id];
126                if ($rev) $params += ['rev'=> $rev];
127                $href = media_managerURL($params, '&');
128                $class = file_exists(mediaFN($id, $rev)) ? 'wikilink1' : 'wikilink2';
129                return '<a href="'.$href.'" class="'.$class.'">'.$id.'</a>';
130            case 'page': // page revision
131                $params = $rev ? ['rev'=> $rev] : [];
132                $href = wl($id, $params, false, '&');
133                $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
134                if (!$display_name) $display_name = $id;
135                $class = page_exists($id, $rev) ? 'wikilink1' : 'wikilink2';
136                if ($this->info['type'] == DOKU_CHANGE_TYPE_DELETE) {
137                    $class = 'wikilink2';
138                }
139                return '<a href="'.$href.'" class="'.$class.'">'.$display_name.'</a>';
140        }
141
142        return '';
143    }
144
145    /**
146     * difflink icon in recents list
147     * all items in the recents are "current" revision of the page or media
148     *
149     * @return string
150     */
151    public function difflinkRecent()
152    {
153        global $lang;
154        $id = $this->info['id'];
155
156        $href = '';
157        switch ($this->info['item']) {
158            case 'media': // media file revision
159                $revs = (new MediaChangeLog($id))->getRevisions(0, 1);
160                $showLink = (count($revs) && file_exists(mediaFN($id)));
161                if ($showLink) {
162                    $href = media_managerURL(
163                        ['tab_details'=>'history', 'mediado'=>'diff', 'image'=> $id, 'ns'=> getNS($id)], '&'
164                    );
165                }
166                break;
167            case 'page': // page revision
168                if($this->info['type'] !== DOKU_CHANGE_TYPE_CREATE) {
169                    $href = wl($id, "do=diff", false, '&');
170                }
171        }
172
173        if ($href) {
174            $html = '<a href="'.$href.'" class="diff_link">'
175                  . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
176                  . ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />'
177                  . '</a>';
178        } else {
179            $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
180        }
181        return $html;
182    }
183
184    /**
185     * difflink icon in revsions list
186     * the icon does not displayed for the current revision
187     *
188     * @return string
189     */
190    public function difflinkRevision()
191    {
192        global $lang;
193        $id = $this->info['id'];
194        $rev = $this->info['date'];
195
196        switch ($this->info['item']) {
197            case 'media': // media file revision
198                if ($this->info['current'] || !file_exists(mediaFN($id, $rev))) {
199                    $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
200                } else {
201                    $href = media_managerURL(['image'=> $id, 'rev'=> $rev, 'mediado'=>'diff'], '&');
202                    $html = '<a href="'.$href.'" class="diff_link">'
203                          . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
204                          . ' title="'. $lang['diff'] .'" alt="'.$lang['diff'] .'" />'
205                          . '</a> ';
206                }
207                return $html;
208            case 'page': // page revision
209                if ($this->info['current'] || !page_exists($id, $rev)) {
210                    $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
211                } else {
212                    $href = wl($id, "rev=$rev,do=diff", false, '&');
213                    $html = '<a href="'.$href.'" class="diff_link">'
214                          . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
215                          . ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />'
216                          . '</a>';
217                }
218                return $html;
219        }
220        return '';
221    }
222
223    /**
224     * icon revision link
225     * used in [Ui\recent]
226     *
227     * @return string
228     */
229    public function revisionlink()
230    {
231        global $lang;
232
233        if (!actionOK('revisions')) {
234            return '';  //FIXME check page, media
235        }
236
237        $id = $this->info['id'];
238        $href = '';
239        switch ($this->info['item']) {
240            case 'media': // media file revision
241                $href = media_managerURL(['tab_details'=>'history', 'image'=> $id, 'ns'=> getNS($id)], '&');
242                break;
243            case 'page': // page revision
244                $href = wl($id, "do=revisions", false, '&');
245        }
246        return '<a href="'.$href.'" class="revisions_link">'
247              . '<img src="'.DOKU_BASE.'lib/images/history.png" width="12" height="14"'
248              . ' title="'.$lang['btn_revs'].'" alt="'.$lang['btn_revs'].'" />'
249              . '</a>';
250    }
251
252    /**
253     * size change
254     * used in [Ui\recent, Ui\Revisions]
255     *
256     * @return string
257     */
258    public function sizeChange()
259    {
260        $class = 'sizechange';
261        $value = filesize_h(abs($this->info['sizechange']));
262        if ($this->info['sizechange'] > 0) {
263            $class .= ' positive';
264            $value = '+' . $value;
265        } elseif ($this->info['sizechange'] < 0) {
266            $class .= ' negative';
267            $value = '-' . $value;
268        } else {
269            $value = '±' . $value;
270        }
271        return '<span class="'.$class.'">'.$value.'</span>';
272    }
273
274    /**
275     * current indicator, used in revison list
276     * not used in Ui\Recents because recent items are always current one
277     *
278     * @return string
279     */
280    public function currentIndicator()
281    {
282        global $lang;
283        return ($this->info['current']) ? '('.$lang['current'].')' : '';
284    }
285
286
287}
288