MediaWiki  master
ImageHistoryList.php
Go to the documentation of this file.
1 <?php
21 use 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 ) ?? $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 
304  protected function getThumbForLine( $file ) {
305  $user = $this->getUser();
306  if ( !$file->allowInlineDisplay() ||
307  $file->isDeleted( File::DELETED_FILE ) ||
308  !$file->userCan( File::DELETED_FILE, $user )
309  ) {
310  return null;
311  }
312 
313  $thumbnail = $file->transform( [ 'width' => '120', 'height' => '120' ] );
314  if ( !$thumbnail ) {
315  return null;
316  }
317 
318  $lang = $this->getLanguage();
319  $timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
320  $alt = $this->msg(
321  'filehist-thumbtext',
322  $lang->userTimeAndDate( $timestamp, $user ),
323  $lang->userDate( $timestamp, $user ),
324  $lang->userTime( $timestamp, $user )
325  )->text();
326  return $thumbnail->toHtml( [ 'alt' => $alt, 'file-link' => true ] );
327  }
328 
333  protected function preventClickjacking( $enable = true ) {
334  $this->preventClickjacking = $enable;
335  }
336 
341  protected function setPreventClickjacking( bool $enable ) {
342  $this->preventClickjacking = $enable;
343  }
344 
348  public function getPreventClickjacking() {
350  }
351 }
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:39
ImageHistoryList\$img
File $img
Definition: ImageHistoryList.php:40
ImageHistoryList
Builds the image revision log shown on image pages.
Definition: ImageHistoryList.php:29
Linker\userLink
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition: Linker.php:1080
File\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: File.php:74
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:204
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
ImageHistoryList\$showThumb
$showThumb
Definition: ImageHistoryList.php:52
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1649
Linker\userToolLinks
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:1125
ImageHistoryList\__construct
__construct( $imagePage)
Definition: ImageHistoryList.php:58
ImageHistoryList\setPreventClickjacking
setPreventClickjacking(bool $enable)
Definition: ImageHistoryList.php:341
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
SpecialPage\getTitleFor
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,...
Definition: SpecialPage.php:131
ImagePage
Class for viewing MediaWiki file description pages.
Definition: ImagePage.php:34
ContextSource\getUser
getUser()
Definition: ContextSource.php:136
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:153
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:319
ImageHistoryList\getImagePage
getImagePage()
Definition: ImageHistoryList.php:72
File
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:67
File\DELETED_COMMENT
const DELETED_COMMENT
Definition: File.php:72
Article\getTitle
getTitle()
Get the title object of the article.
Definition: Article.php:224
ImageHistoryList\$repo
$repo
Definition: ImageHistoryList.php:52
ContextSource\getOutput
getOutput()
Definition: ContextSource.php:126
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:33
Article\getPage
getPage()
Get the WikiPage object of this instance.
Definition: Article.php:234
Article\getContext
getContext()
Gets the context this Article is executed in.
Definition: Article.php:1977
Linker\revDeleteLinkDisabled
static revDeleteLinkDisabled( $delete=true)
Creates a dead (show/hide) link for deleting revisions/log entries.
Definition: Linker.php:2206
File\FOR_THIS_USER
const FOR_THIS_USER
Definition: File.php:88
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:63
ImageHistoryList\preventClickjacking
preventClickjacking( $enable=true)
Definition: ImageHistoryList.php:333
ImageHistoryList\$imagePage
ImagePage $imagePage
Definition: ImageHistoryList.php:45
ImageHistoryList\imageHistoryLine
imageHistoryLine( $iscur, $file, $formattedComment)
Definition: ImageHistoryList.php:135
ImageHistoryList\getFile
getFile()
Definition: ImageHistoryList.php:79
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:197
ContextSource\getAuthority
getAuthority()
Definition: ContextSource.php:144
ImagePage\getDisplayedFile
getDisplayedFile()
Definition: ImagePage.php:230
Title
Represents a title within MediaWiki.
Definition: Title.php:47
ImageHistoryList\$title
Title $title
Definition: ImageHistoryList.php:35
ImageHistoryList\getThumbForLine
getThumbForLine( $file)
Definition: ImageHistoryList.php:304
IContextSource\getConfig
getConfig()
Get the site configuration.
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:255
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:213
Linker\revDeleteLink
static revDeleteLink( $query=[], $restricted=false, $delete=true)
Creates a (show/hide) link for deleting revisions/log entries.
Definition: Linker.php:2182
ImageHistoryList\beginImageHistoryList
beginImageHistoryList( $navLinks='')
Definition: ImageHistoryList.php:87
File\DELETED_FILE
const DELETED_FILE
Definition: File.php:71
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:235
ImageHistoryList\$preventClickjacking
$preventClickjacking
Definition: ImageHistoryList.php:53
ImageHistoryList\$current
File $current
Definition: ImageHistoryList.php:50
ImageHistoryList\getPreventClickjacking
getPreventClickjacking()
Definition: ImageHistoryList.php:348
ImageHistoryList\endImageHistoryList
endImageHistoryList( $navLinks='')
Definition: ImageHistoryList.php:122