MediaWiki REL1_39
ImageHistoryList.php
Go to the documentation of this file.
1<?php
21use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
24
31 use ProtectedHookAccessorTrait;
32
36 protected $title;
37
41 protected $img;
42
46 protected $imagePage;
47
51 protected $current;
52
53 protected $repo, $showThumb;
54 protected $preventClickjacking = false;
55
59 public function __construct( $imagePage ) {
60 $context = $imagePage->getContext();
61 $this->current = $imagePage->getPage()->getFile();
62 $this->img = $imagePage->getDisplayedFile();
63 $this->title = $imagePage->getTitle();
64 $this->imagePage = $imagePage;
65 $this->showThumb = $context->getConfig()->get( MainConfigNames::ShowArchiveThumbnails ) &&
66 $this->img->canRender();
67 $this->setContext( $context );
68 }
69
73 public function getImagePage() {
74 return $this->imagePage;
75 }
76
80 public function getFile() {
81 return $this->img;
82 }
83
88 public function beginImageHistoryList( $navLinks = '' ) {
89 // Styles for class=history-deleted
90 $this->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
91
92 $html = '';
93 $canDelete = $this->current->isLocal() &&
94 $this->getAuthority()->isAllowedAny( 'delete', 'deletedhistory' );
95
96 foreach ( [
97 '',
98 $canDelete ? '' : null,
99 'filehist-datetime',
100 $this->showThumb ? 'filehist-thumb' : null,
101 'filehist-dimensions',
102 'filehist-user',
103 'filehist-comment',
104 ] as $key ) {
105 if ( $key !== null ) {
106 $html .= Html::element( 'th', [], $key ? $this->msg( $key )->text() : '' );
107 }
108 }
109
110 return Html::element( 'h2', [ 'id' => 'filehistory' ], $this->msg( 'filehist' )->text() )
111 . "\n"
112 . Html::openElement( 'div', [ 'id' => 'mw-imagepage-section-filehistory' ] ) . "\n"
113 . $this->msg( 'filehist-help' )->parseAsBlock()
114 . $navLinks . "\n"
115 . Html::openElement( 'table', [ 'class' => 'wikitable filehistory' ] ) . "\n"
116 . Html::rawElement( 'tr', [], $html ) . "\n";
117 }
118
123 public function endImageHistoryList( $navLinks = '' ) {
124 return Html::closeElement( 'table' ) . "\n" .
125 $navLinks . "\n" .
126 Html::closeElement( 'div' ) . "\n";
127 }
128
136 public function imageHistoryLine( $iscur, $file, $formattedComment ) {
137 $user = $this->getUser();
138 $lang = $this->getLanguage();
139 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
140 $timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
141 // @phan-suppress-next-line PhanUndeclaredMethod
142 $img = $iscur ? $file->getName() : $file->getArchiveName();
143 $uploader = $file->getUploader( File::FOR_THIS_USER, $user );
144
145 $local = $this->current->isLocal();
146 $row = '';
147
148 // Deletion link
149 if ( $local && ( $this->getAuthority()->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
150 $row .= Html::openElement( 'td' );
151 # Link to remove from history
152 if ( $this->getAuthority()->isAllowed( 'delete' ) ) {
153 $row .= $linkRenderer->makeKnownLink(
154 $this->title,
155 $this->msg( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' )->text(),
156 [],
157 [ 'action' => 'delete', 'oldimage' => $iscur ? null : $img ]
158 );
159 }
160 # Link to hide content. Don't show useless link to people who cannot hide revisions.
161 $canHide = $this->getAuthority()->isAllowed( 'deleterevision' );
162 if ( $canHide || ( $this->getAuthority()->isAllowed( 'deletedhistory' )
163 && $file->getVisibility() ) ) {
164 if ( $this->getAuthority()->isAllowed( 'delete' ) ) {
165 $row .= Html::element( 'br' );
166 }
167 // If file is top revision or locked from this user, don't link
168 if ( $iscur || !$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
169 $row .= Linker::revDeleteLinkDisabled( $canHide );
170 } else {
171 $row .= Linker::revDeleteLink(
172 [
173 'type' => 'oldimage',
174 'target' => $this->title->getPrefixedText(),
175 'ids' => explode( '!', $img, 2 )[0],
176 ],
177 $file->isDeleted( File::DELETED_RESTRICTED ),
178 $canHide
179 );
180 }
181 }
182 $row .= Html::closeElement( 'td' );
183 }
184
185 // Reversion link/current indicator
186 $row .= Html::openElement( 'td' );
187 if ( $iscur ) {
188 $row .= $this->msg( 'filehist-current' )->escaped();
189 } elseif ( $local && $this->getAuthority()->probablyCan( 'edit', $this->title )
190 && $this->getAuthority()->probablyCan( 'upload', $this->title )
191 ) {
192 if ( $file->isDeleted( File::DELETED_FILE ) ) {
193 $row .= $this->msg( 'filehist-revert' )->escaped();
194 } else {
195 $row .= $linkRenderer->makeKnownLink(
196 $this->title,
197 $this->msg( 'filehist-revert' )->text(),
198 [],
199 [
200 'action' => 'revert',
201 'oldimage' => $img,
202 ]
203 );
204 }
205 }
206 $row .= Html::closeElement( 'td' );
207
208 // Date/time and image link
209 $selected = $file->getTimestamp() === $this->img->getTimestamp();
210 $row .= Html::openElement( 'td', [
211 'class' => $selected ? 'filehistory-selected' : null,
212 'style' => 'white-space: nowrap;'
213 ] );
214 if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
215 # Don't link to unviewable files
216 $row .= Html::element( 'span', [ 'class' => 'history-deleted' ],
217 $lang->userTimeAndDate( $timestamp, $user )
218 );
219 } elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
220 $timeAndDate = $lang->userTimeAndDate( $timestamp, $user );
221 if ( $local ) {
222 $this->setPreventClickjacking( true );
223 # Make a link to review the image
224 $url = $linkRenderer->makeKnownLink(
225 SpecialPage::getTitleFor( 'Revisiondelete' ),
226 $timeAndDate,
227 [],
228 [
229 'target' => $this->title->getPrefixedText(),
230 'file' => $img,
231 'token' => $user->getEditToken( $img )
232 ]
233 );
234 } else {
235 $url = htmlspecialchars( $timeAndDate );
236 }
237 $row .= Html::rawElement( 'span', [ 'class' => 'history-deleted' ], $url );
238 } elseif ( !$file->exists() ) {
239 $row .= Html::element( 'span', [ 'class' => 'mw-file-missing' ],
240 $lang->userTimeAndDate( $timestamp, $user )
241 );
242 } else {
243 $url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
244 $row .= Html::element( 'a', [ 'href' => $url ],
245 $lang->userTimeAndDate( $timestamp, $user )
246 );
247 }
248 $row .= Html::closeElement( 'td' );
249
250 // Thumbnail
251 if ( $this->showThumb ) {
252 $row .= Html::rawElement( 'td', [],
253 $this->getThumbForLine( $file, $iscur ) ?? $this->msg( 'filehist-nothumb' )->escaped()
254 );
255 }
256
257 // Image dimensions + size
258 $row .= Html::openElement( 'td' );
259 $row .= htmlspecialchars( $file->getDimensionsString() );
260 $row .= $this->msg( 'word-separator' )->escaped();
261 $row .= Html::element( 'span', [ 'style' => 'white-space: nowrap;' ],
262 $this->msg( 'parentheses' )->sizeParams( $file->getSize() )->text()
263 );
264 $row .= Html::closeElement( 'td' );
265
266 // Uploading user
267 $row .= Html::openElement( 'td' );
268 // Hide deleted usernames
269 if ( $uploader && $local ) {
270 $row .= Linker::userLink( $uploader->getId(), $uploader->getName() );
271 $row .= Html::rawElement( 'span', [ 'style' => 'white-space: nowrap;' ],
272 Linker::userToolLinks( $uploader->getId(), $uploader->getName() )
273 );
274 } elseif ( $uploader ) {
275 $row .= htmlspecialchars( $uploader->getName() );
276 } else {
277 $row .= Html::element( 'span', [ 'class' => 'history-deleted' ],
278 $this->msg( 'rev-deleted-user' )->text()
279 );
280 }
281 $row .= Html::closeElement( 'td' );
282
283 // Don't show deleted descriptions
284 if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
285 $row .= Html::rawElement( 'td', [],
286 Html::element( 'span', [ 'class' => 'history-deleted' ],
287 $this->msg( 'rev-deleted-comment' )->text()
288 )
289 );
290 } else {
291 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
292 $row .= Html::rawElement( 'td', [ 'dir' => $contLang->getDir() ], $formattedComment );
293 }
294
295 $rowClass = null;
296 $this->getHookRunner()->onImagePageFileHistoryLine( $this, $file, $row, $rowClass );
297
298 return Html::rawElement( 'tr', [ 'class' => $rowClass ], $row ) . "\n";
299 }
300
306 protected function getThumbForLine( $file, $iscur ) {
307 $user = $this->getUser();
308 if ( !$file->allowInlineDisplay() ||
309 $file->isDeleted( File::DELETED_FILE ) ||
310 !$file->userCan( File::DELETED_FILE, $user )
311 ) {
312 return null;
313 }
314
315 $thumbnail = $file->transform(
316 [
317 'width' => '120',
318 'height' => '120',
319 'isFilePageThumb' => $iscur // old revisions are already versioned
320 ]
321 );
322 if ( !$thumbnail ) {
323 return null;
324 }
325
326 $lang = $this->getLanguage();
327 $timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
328 $alt = $this->msg(
329 'filehist-thumbtext',
330 $lang->userTimeAndDate( $timestamp, $user ),
331 $lang->userDate( $timestamp, $user ),
332 $lang->userTime( $timestamp, $user )
333 )->text();
334 return $thumbnail->toHtml( [ 'alt' => $alt, 'file-link' => true ] );
335 }
336
341 protected function preventClickjacking( $enable = true ) {
342 $this->preventClickjacking = $enable;
343 }
344
349 protected function setPreventClickjacking( bool $enable ) {
350 $this->preventClickjacking = $enable;
351 }
352
356 public function getPreventClickjacking() {
357 return $this->preventClickjacking;
358 }
359}
getUser()
getAuthority()
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
getContext()
Gets the context this Article is executed in.
Definition Article.php:2013
getTitle()
Get the title object of the article.
Definition Article.php:230
getPage()
Get the WikiPage object of this instance.
Definition Article.php:240
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
setContext(IContextSource $context)
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:67
getName()
Return the name of this file.
Definition File.php:333
Builds the image revision log shown on image pages.
endImageHistoryList( $navLinks='')
beginImageHistoryList( $navLinks='')
preventClickjacking( $enable=true)
getThumbForLine( $file, $iscur)
setPreventClickjacking(bool $enable)
imageHistoryLine( $iscur, $file, $formattedComment)
__construct( $imagePage)
Rendering of file description pages.
Definition ImagePage.php:31
getDisplayedFile()
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition Linker.php:1114
static revDeleteLinkDisabled( $delete=true)
Creates a dead (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2229
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null, $useParentheses=true)
Generate standard user tool links (talk, contributions, block link, etc.)
Definition Linker.php:1159
static revDeleteLink( $query=[], $restricted=false, $delete=true)
Creates a (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2205
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Represents a title within MediaWiki.
Definition Title.php:49
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42
if(!isset( $args[0])) $lang