MediaWiki REL1_38
ImageHistoryList.php
Go to the documentation of this file.
1<?php
21use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
23
30 use ProtectedHookAccessorTrait;
31
35 protected $title;
36
40 protected $img;
41
45 protected $imagePage;
46
50 protected $current;
51
52 protected $repo, $showThumb;
53 protected $preventClickjacking = false;
54
58 public function __construct( $imagePage ) {
60 $this->current = $imagePage->getPage()->getFile();
61 $this->img = $imagePage->getDisplayedFile();
62 $this->title = $imagePage->getTitle();
63 $this->imagePage = $imagePage;
64 $this->showThumb = $context->getConfig()->get( 'ShowArchiveThumbnails' ) &&
65 $this->img->canRender();
66 $this->setContext( $context );
67 }
68
72 public function getImagePage() {
73 return $this->imagePage;
74 }
75
79 public function getFile() {
80 return $this->img;
81 }
82
87 public function beginImageHistoryList( $navLinks = '' ) {
88 // Styles for class=history-deleted
89 $this->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
90
91 $html = '';
92 $canDelete = $this->current->isLocal() &&
93 $this->getAuthority()->isAllowedAny( 'delete', 'deletedhistory' );
94
95 foreach ( [
96 '',
97 $canDelete ? '' : null,
98 'filehist-datetime',
99 $this->showThumb ? 'filehist-thumb' : null,
100 'filehist-dimensions',
101 'filehist-user',
102 'filehist-comment',
103 ] as $key ) {
104 if ( $key !== null ) {
105 $html .= Html::element( 'th', [], $key ? $this->msg( $key )->text() : '' );
106 }
107 }
108
109 return Html::element( 'h2', [ 'id' => 'filehistory' ], $this->msg( 'filehist' )->text() )
110 . "\n"
111 . Html::openElement( 'div', [ 'id' => 'mw-imagepage-section-filehistory' ] ) . "\n"
112 . $this->msg( 'filehist-help' )->parseAsBlock()
113 . $navLinks . "\n"
114 . Html::openElement( 'table', [ 'class' => 'wikitable filehistory' ] ) . "\n"
115 . Html::rawElement( 'tr', [], $html ) . "\n";
116 }
117
122 public function endImageHistoryList( $navLinks = '' ) {
123 return Html::closeElement( 'table' ) . "\n" .
124 $navLinks . "\n" .
125 Html::closeElement( 'div' ) . "\n";
126 }
127
135 public function imageHistoryLine( $iscur, $file, $formattedComment ) {
136 $user = $this->getUser();
137 $lang = $this->getLanguage();
138 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
139 $timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
140 // @phan-suppress-next-line PhanUndeclaredMethod
141 $img = $iscur ? $file->getName() : $file->getArchiveName();
142 $uploader = $file->getUploader( File::FOR_THIS_USER, $user );
143
144 $local = $this->current->isLocal();
145 $row = '';
146
147 // Deletion link
148 if ( $local && ( $this->getAuthority()->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
149 $row .= Html::openElement( 'td' );
150 # Link to remove from history
151 if ( $this->getAuthority()->isAllowed( 'delete' ) ) {
152 $row .= $linkRenderer->makeKnownLink(
153 $this->title,
154 $this->msg( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' )->text(),
155 [],
156 [ 'action' => 'delete', 'oldimage' => $iscur ? null : $img ]
157 );
158 }
159 # Link to hide content. Don't show useless link to people who cannot hide revisions.
160 $canHide = $this->getAuthority()->isAllowed( 'deleterevision' );
161 if ( $canHide || ( $this->getAuthority()->isAllowed( 'deletedhistory' )
162 && $file->getVisibility() ) ) {
163 if ( $this->getAuthority()->isAllowed( 'delete' ) ) {
164 $row .= Html::element( 'br' );
165 }
166 // If file is top revision or locked from this user, don't link
167 if ( $iscur || !$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
168 $row .= Linker::revDeleteLinkDisabled( $canHide );
169 } else {
170 $row .= Linker::revDeleteLink(
171 [
172 'type' => 'oldimage',
173 'target' => $this->title->getPrefixedText(),
174 'ids' => explode( '!', $img, 2 )[0],
175 ],
176 $file->isDeleted( File::DELETED_RESTRICTED ),
177 $canHide
178 );
179 }
180 }
181 $row .= Html::closeElement( 'td' );
182 }
183
184 // Reversion link/current indicator
185 $row .= Html::openElement( 'td' );
186 if ( $iscur ) {
187 $row .= $this->msg( 'filehist-current' )->escaped();
188 } elseif ( $local && $this->getAuthority()->probablyCan( 'edit', $this->title )
189 && $this->getAuthority()->probablyCan( 'upload', $this->title )
190 ) {
191 if ( $file->isDeleted( File::DELETED_FILE ) ) {
192 $row .= $this->msg( 'filehist-revert' )->escaped();
193 } else {
194 $row .= $linkRenderer->makeKnownLink(
195 $this->title,
196 $this->msg( 'filehist-revert' )->text(),
197 [],
198 [
199 'action' => 'revert',
200 'oldimage' => $img,
201 ]
202 );
203 }
204 }
205 $row .= Html::closeElement( 'td' );
206
207 // Date/time and image link
208 $selected = $file->getTimestamp() === $this->img->getTimestamp();
209 $row .= Html::openElement( 'td', [
210 'class' => $selected ? 'filehistory-selected' : null,
211 'style' => 'white-space: nowrap;'
212 ] );
213 if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
214 # Don't link to unviewable files
215 $row .= Html::element( 'span', [ 'class' => 'history-deleted' ],
216 $lang->userTimeAndDate( $timestamp, $user )
217 );
218 } elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
219 $timeAndDate = $lang->userTimeAndDate( $timestamp, $user );
220 if ( $local ) {
221 $this->setPreventClickjacking( true );
222 # Make a link to review the image
223 $url = $linkRenderer->makeKnownLink(
224 SpecialPage::getTitleFor( 'Revisiondelete' ),
225 $timeAndDate,
226 [],
227 [
228 'target' => $this->title->getPrefixedText(),
229 'file' => $img,
230 'token' => $user->getEditToken( $img )
231 ]
232 );
233 } else {
234 $url = htmlspecialchars( $timeAndDate );
235 }
236 $row .= Html::rawElement( 'span', [ 'class' => 'history-deleted' ], $url );
237 } elseif ( !$file->exists() ) {
238 $row .= Html::element( 'span', [ 'class' => 'mw-file-missing' ],
239 $lang->userTimeAndDate( $timestamp, $user )
240 );
241 } else {
242 $url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
243 $row .= Html::element( 'a', [ 'href' => $url ],
244 $lang->userTimeAndDate( $timestamp, $user )
245 );
246 }
247 $row .= Html::closeElement( 'td' );
248
249 // Thumbnail
250 if ( $this->showThumb ) {
251 $row .= Html::rawElement( 'td', [],
252 $this->getThumbForLine( $file, $iscur ) ?? $this->msg( 'filehist-nothumb' )->escaped()
253 );
254 }
255
256 // Image dimensions + size
257 $row .= Html::openElement( 'td' );
258 $row .= htmlspecialchars( $file->getDimensionsString() );
259 $row .= $this->msg( 'word-separator' )->escaped();
260 $row .= Html::element( 'span', [ 'style' => 'white-space: nowrap;' ],
261 $this->msg( 'parentheses' )->sizeParams( $file->getSize() )->text()
262 );
263 $row .= Html::closeElement( 'td' );
264
265 // Uploading user
266 $row .= Html::openElement( 'td' );
267 // Hide deleted usernames
268 if ( $uploader && $local ) {
269 $row .= Linker::userLink( $uploader->getId(), $uploader->getName() );
270 $row .= Html::rawElement( 'span', [ 'style' => 'white-space: nowrap;' ],
271 Linker::userToolLinks( $uploader->getId(), $uploader->getName() )
272 );
273 } elseif ( $uploader ) {
274 $row .= htmlspecialchars( $uploader->getName() );
275 } else {
276 $row .= Html::element( 'span', [ 'class' => 'history-deleted' ],
277 $this->msg( 'rev-deleted-user' )->text()
278 );
279 }
280 $row .= Html::closeElement( 'td' );
281
282 // Don't show deleted descriptions
283 if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
284 $row .= Html::rawElement( 'td', [],
285 Html::element( 'span', [ 'class' => 'history-deleted' ],
286 $this->msg( 'rev-deleted-comment' )->text()
287 )
288 );
289 } else {
290 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
291 $row .= Html::rawElement( 'td', [ 'dir' => $contLang->getDir() ], $formattedComment );
292 }
293
294 $rowClass = null;
295 $this->getHookRunner()->onImagePageFileHistoryLine( $this, $file, $row, $rowClass );
296
297 return Html::rawElement( 'tr', [ 'class' => $rowClass ], $row ) . "\n";
298 }
299
305 protected function getThumbForLine( $file, $iscur ) {
306 $user = $this->getUser();
307 if ( !$file->allowInlineDisplay() ||
308 $file->isDeleted( File::DELETED_FILE ) ||
309 !$file->userCan( File::DELETED_FILE, $user )
310 ) {
311 return null;
312 }
313
314 $thumbnail = $file->transform(
315 [
316 'width' => '120',
317 'height' => '120',
318 'isFilePageThumb' => $iscur // old revisions are already versioned
319 ]
320 );
321 if ( !$thumbnail ) {
322 return null;
323 }
324
325 $lang = $this->getLanguage();
326 $timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
327 $alt = $this->msg(
328 'filehist-thumbtext',
329 $lang->userTimeAndDate( $timestamp, $user ),
330 $lang->userDate( $timestamp, $user ),
331 $lang->userTime( $timestamp, $user )
332 )->text();
333 return $thumbnail->toHtml( [ 'alt' => $alt, 'file-link' => true ] );
334 }
335
340 protected function preventClickjacking( $enable = true ) {
341 $this->preventClickjacking = $enable;
342 }
343
348 protected function setPreventClickjacking( bool $enable ) {
349 $this->preventClickjacking = $enable;
350 }
351
355 public function getPreventClickjacking() {
356 return $this->preventClickjacking;
357 }
358}
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:1981
getTitle()
Get the title object of the article.
Definition Article.php:224
getPage()
Get the WikiPage object of this instance.
Definition Article.php:234
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()
IContextSource $context
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:331
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)
Class for viewing MediaWiki file description pages.
Definition ImagePage.php:33
getDisplayedFile()
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition Linker.php:1093
static revDeleteLinkDisabled( $delete=true)
Creates a dead (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2211
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:1138
static revDeleteLink( $query=[], $restricted=false, $delete=true)
Creates a (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2187
MediaWikiServices is the service locator for the application scope of MediaWiki.
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:47
getConfig()
Get the site configuration.
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