little refactoring
[dokuwiki.git] / inc / ChangeLog / RevisionInfo.php
blob9a75530597eaefd9a3c8e004d7d06064be5804e4
1 <?php
3 namespace dokuwiki\ChangeLog;
5 /**
6 * Class RevisionInfo
8 * Provides methods to show Revision Information in DokuWiki Ui components:
9 * - Ui\Recent
10 * - Ui\PageRevisions
11 * - Ui\MediaRevisions
12 * - Ui\PageDiff
13 * - Ui\MediaDiff
15 class RevisionInfo
17 public const MODE_PAGE = 'page';
18 public const MODE_MEDIA = 'media';
20 /* @var array */
21 protected $info;
23 /**
24 * Constructor
26 * @param array $info Revision Information structure with entries:
27 * - date: unix timestamp
28 * - ip: IPv4 or IPv6 address
29 * - type: change type (log line type)
30 * - id: page id
31 * - user: user name
32 * - sum: edit summary (or action reason)
33 * - extra: extra data (varies by line type)
34 * - sizechange: change of filesize
35 * additionally,
36 * - current: (optional) whether current revision or not
37 * - timestamp: (optional) set only when external edits occurred
38 * - mode: (internal use) ether "media" or "page"
40 public function __construct($info = null)
42 if (!is_array($info) || !isset($info['id'])) {
43 $info = [
44 'mode' => self::MODE_PAGE,
45 'date' => false,
48 $this->info = $info;
51 /**
52 * Set or return whether this revision is current page or media file
54 * This method does not check exactly whether the revision is current or not. Instead,
55 * set value of associated "current" key for internal use. Some UI element like diff
56 * link button depend on relation to current page or media file. A changelog line does
57 * not indicate whether it corresponds to current page or media file.
59 * @param bool $value true if the revision is current, otherwise false
60 * @return bool
62 public function isCurrent($value = null)
64 return (bool) $this->val('current', $value);
67 /**
68 * Return or set a value of associated key of revision information
69 * but does not allow to change values of existing keys
71 * @param string $key
72 * @param mixed $value
73 * @return string|null
75 public function val($key, $value = null)
77 if (isset($value) && !array_key_exists($key, $this->info)) {
78 // setter, only for new keys
79 $this->info[$key] = $value;
81 if (array_key_exists($key, $this->info)) {
82 // getter
83 return $this->info[$key];
85 return null;
88 /**
89 * Set extra key-value to the revision information
90 * but does not allow to change values of existing keys
91 * @param array $info
92 * @return void
94 public function append(array $info)
96 foreach ($info as $key => $value) {
97 $this->val($key, $value);
103 * file icon of the page or media file
104 * used in [Ui\recent]
106 * @return string
108 public function showFileIcon()
110 $id = $this->val('id');
111 if ($this->val('mode') == self::MODE_MEDIA) {
112 // media file revision
113 return media_printicon($id);
114 } elseif ($this->val('mode') == self::MODE_PAGE) {
115 // page revision
116 return '<img class="icon" src="' . DOKU_BASE . 'lib/images/fileicons/file.png" alt="' . $id . '" />';
121 * edit date and time of the page or media file
122 * used in [Ui\recent, Ui\Revisions]
124 * @param bool $checkTimestamp enable timestamp check, alter formatted string when timestamp is false
125 * @return string
127 public function showEditDate($checkTimestamp = false)
129 $formatted = dformat($this->val('date'));
130 if ($checkTimestamp && $this->val('timestamp') === false) {
131 // exact date is unknown for externally deleted file
132 // when unknown, alter formatted string "YYYY-mm-DD HH:MM" to "____-__-__ __:__"
133 $formatted = preg_replace('/[0-9a-zA-Z]/', '_', $formatted);
135 return '<span class="date">' . $formatted . '</span>';
139 * edit summary
140 * used in [Ui\recent, Ui\Revisions]
142 * @return string
144 public function showEditSummary()
146 return '<span class="sum">' . ' – ' . hsc($this->val('sum')) . '</span>';
150 * editor of the page or media file
151 * used in [Ui\recent, Ui\Revisions]
153 * @return string
155 public function showEditor()
157 if ($this->val('user')) {
158 $html = '<bdi>' . editorinfo($this->val('user')) . '</bdi>';
159 if (auth_ismanager()) {
160 $html .= ' <bdo dir="ltr">(' . $this->val('ip') . ')</bdo>';
162 } else {
163 $html = '<bdo dir="ltr">' . $this->val('ip') . '</bdo>';
165 return '<span class="user">' . $html . '</span>';
169 * name of the page or media file
170 * used in [Ui\recent, Ui\Revisions]
172 * @return string
174 public function showFileName()
176 $id = $this->val('id');
177 $rev = $this->isCurrent() ? '' : $this->val('date');
179 if ($this->val('mode') == self::MODE_MEDIA) {
180 // media file revision
181 $params = ['tab_details' => 'view', 'ns' => getNS($id), 'image' => $id];
182 if ($rev) $params += ['rev' => $rev];
183 $href = media_managerURL($params, '&');
184 $display_name = $id;
185 $exists = file_exists(mediaFN($id, $rev));
186 } elseif ($this->val('mode') == self::MODE_PAGE) {
187 // page revision
188 $params = $rev ? ['rev' => $rev] : [];
189 $href = wl($id, $params, false, '&');
190 $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
191 if (!$display_name) $display_name = $id;
192 $exists = page_exists($id, $rev);
195 if ($exists) {
196 $class = 'wikilink1';
197 } elseif ($this->isCurrent()) {
198 //show only not-existing link for current page, which allows for directly create a new page/upload
199 $class = 'wikilink2';
200 } else {
201 //revision is not in attic
202 return $display_name;
204 if ($this->val('type') == DOKU_CHANGE_TYPE_DELETE) {
205 $class = 'wikilink2';
207 return '<a href="' . $href . '" class="' . $class . '">' . $display_name . '</a>';
211 * Revision Title for PageDiff table headline
213 * @return string
215 public function showRevisionTitle()
217 global $lang;
219 if (!$this->val('date')) return '&mdash;';
221 $id = $this->val('id');
222 $rev = $this->isCurrent() ? '' : $this->val('date');
223 $params = ($rev) ? ['rev' => $rev] : [];
225 // revision info may have timestamp key when external edits occurred
226 $date = ($this->val('timestamp') === false)
227 ? $lang['unknowndate']
228 : dformat($this->val('date'));
231 if ($this->val('mode') == self::MODE_MEDIA) {
232 // media file revision
233 $href = ml($id, $params, false, '&');
234 $exists = file_exists(mediaFN($id, $rev));
235 } elseif ($this->val('mode') == self::MODE_PAGE) {
236 // page revision
237 $href = wl($id, $params, false, '&');
238 $exists = page_exists($id, $rev);
240 if ($exists) {
241 $class = 'wikilink1';
242 } elseif ($this->isCurrent()) {
243 //show only not-existing link for current page, which allows for directly create a new page/upload
244 $class = 'wikilink2';
245 } else {
246 //revision is not in attic
247 return $id . ' [' . $date . ']';
249 if ($this->val('type') == DOKU_CHANGE_TYPE_DELETE) {
250 $class = 'wikilink2';
252 return '<bdi><a class="' . $class . '" href="' . $href . '">' . $id . ' [' . $date . ']' . '</a></bdi>';
256 * diff link icon in recent changes list, to compare (this) current revision with previous one
257 * all items in "recent changes" are current revision of the page or media
259 * @return string
261 public function showIconCompareWithPrevious()
263 global $lang;
264 $id = $this->val('id');
266 $href = '';
267 if ($this->val('mode') == self::MODE_MEDIA) {
268 // media file revision
269 // unlike page, media file does not copied to media_attic when uploaded.
270 // diff icon will not be shown when external edit occurred
271 // because no attic file to be compared with current.
272 $revs = (new MediaChangeLog($id))->getRevisions(0, 1);
273 $showLink = (count($revs) && file_exists(mediaFN($id, $revs[0])) && file_exists(mediaFN($id)));
274 if ($showLink) {
275 $param = ['tab_details' => 'history', 'mediado' => 'diff', 'ns' => getNS($id), 'image' => $id];
276 $href = media_managerURL($param, '&');
278 } elseif ($this->val('mode') == self::MODE_PAGE) {
279 // page revision
280 // when a page just created anyway, it is natural to expect no older revisions
281 // even if it had once existed but deleted before. Simply ignore to check changelog.
282 if ($this->val('type') !== DOKU_CHANGE_TYPE_CREATE) {
283 $href = wl($id, ['do' => 'diff'], false, '&');
287 if ($href) {
288 return '<a href="' . $href . '" class="diff_link">'
289 . '<img src="' . DOKU_BASE . 'lib/images/diff.png" width="15" height="11"'
290 . ' title="' . $lang['diff'] . '" alt="' . $lang['diff'] . '" />'
291 . '</a>';
292 } else {
293 return '<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />';
298 * diff link icon in revisions list, compare this revision with current one
299 * the icon does not displayed for the current revision
301 * @return string
303 public function showIconCompareWithCurrent()
305 global $lang;
306 $id = $this->val('id');
307 $rev = $this->isCurrent() ? '' : $this->val('date');
309 $href = '';
310 if ($this->val('mode') == self::MODE_MEDIA) {
311 // media file revision
312 if (!$this->isCurrent() && file_exists(mediaFN($id, $rev))) {
313 $param = ['mediado' => 'diff', 'image' => $id, 'rev' => $rev];
314 $href = media_managerURL($param, '&');
316 } elseif ($this->val('mode') == self::MODE_PAGE) {
317 // page revision
318 if (!$this->isCurrent()) {
319 $href = wl($id, ['rev' => $rev, 'do' => 'diff'], false, '&');
323 if ($href) {
324 return '<a href="' . $href . '" class="diff_link">'
325 . '<img src="' . DOKU_BASE . 'lib/images/diff.png" width="15" height="11"'
326 . ' title="' . $lang['diff'] . '" alt="' . $lang['diff'] . '" />'
327 . '</a>';
328 } else {
329 return '<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />';
334 * icon for revision action
335 * used in [Ui\recent]
337 * @return string
339 public function showIconRevisions()
341 global $lang;
343 if (!actionOK('revisions')) {
344 return '';
347 $id = $this->val('id');
348 if ($this->val('mode') == self::MODE_MEDIA) {
349 // media file revision
350 $param = ['tab_details' => 'history', 'ns' => getNS($id), 'image' => $id];
351 $href = media_managerURL($param, '&');
352 } elseif ($this->val('mode') == self::MODE_PAGE) {
353 // page revision
354 $href = wl($id, ['do' => 'revisions'], false, '&');
356 return '<a href="' . $href . '" class="revisions_link">'
357 . '<img src="' . DOKU_BASE . 'lib/images/history.png" width="12" height="14"'
358 . ' title="' . $lang['btn_revs'] . '" alt="' . $lang['btn_revs'] . '" />'
359 . '</a>';
363 * size change
364 * used in [Ui\recent, Ui\Revisions]
366 * @return string
368 public function showSizeChange()
370 $class = 'sizechange';
371 $value = filesize_h(abs($this->val('sizechange')));
372 if ($this->val('sizechange') > 0) {
373 $class .= ' positive';
374 $value = '+' . $value;
375 } elseif ($this->val('sizechange') < 0) {
376 $class .= ' negative';
377 $value = '-' . $value;
378 } else {
379 $value = '±' . $value;
381 return '<span class="' . $class . '">' . $value . '</span>';
385 * current indicator, used in revision list
386 * not used in Ui\Recent because recent files are always current one
388 * @return string
390 public function showCurrentIndicator()
392 global $lang;
393 return $this->isCurrent() ? '(' . $lang['current'] . ')' : '';