wiki.techinc.nl/includes/page/ImageHistoryList.php
Umherirrender ca8b1eb476 Add missing documentation to class properties (frontend-related)
Add doc-typehints to class properties found by the PropertyDocumentation
sniff to improve the documentation.

Once the sniff is enabled it avoids that new code is missing type
declarations. This is focused on documentation and does not change code.

Change-Id: Id75cb2e5fbee0fe7600f92473d876f23730d46b7
2024-09-05 21:41:19 +02:00

340 lines
10 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
use MediaWiki\Context\ContextSource;
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Html\Html;
use MediaWiki\Linker\Linker;
use MediaWiki\MainConfigNames;
use MediaWiki\MediaWikiServices;
use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\Title\Title;
/**
* Builds the image revision log shown on image pages
*
* @ingroup Media
*/
class ImageHistoryList extends ContextSource {
use ProtectedHookAccessorTrait;
protected Title $title;
protected File $img;
protected ImagePage $imagePage;
protected File $current;
protected bool $showThumb;
/** @var bool */
protected $preventClickjacking = false;
/**
* @param ImagePage $imagePage
*/
public function __construct( $imagePage ) {
$context = $imagePage->getContext();
$this->current = $imagePage->getPage()->getFile();
$this->img = $imagePage->getDisplayedFile();
$this->title = $imagePage->getTitle();
$this->imagePage = $imagePage;
$this->showThumb = $context->getConfig()->get( MainConfigNames::ShowArchiveThumbnails ) &&
$this->img->canRender();
$this->setContext( $context );
}
/**
* @return ImagePage
*/
public function getImagePage() {
return $this->imagePage;
}
/**
* @return File
*/
public function getFile() {
return $this->img;
}
/**
* @return string
*/
public function beginImageHistoryList() {
// Styles for class=history-deleted
$this->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
$html = '';
$canDelete = $this->current->isLocal() &&
$this->getAuthority()->isAllowedAny( 'delete', 'deletedhistory' );
foreach ( [
'',
$canDelete ? '' : null,
'filehist-datetime',
$this->showThumb ? 'filehist-thumb' : null,
'filehist-dimensions',
'filehist-user',
'filehist-comment',
] as $key ) {
if ( $key !== null ) {
$html .= Html::element( 'th', [], $key ? $this->msg( $key )->text() : '' );
}
}
return Html::openElement( 'table', [ 'class' => 'wikitable filehistory' ] ) . "\n"
. Html::rawElement( 'tr', [], $html ) . "\n";
}
/**
* @return string
*/
public function endImageHistoryList() {
return Html::closeElement( 'table' ) . "\n";
}
/**
* @internal
* @param bool $iscur
* @param File $file
* @param string $formattedComment
* @return string
*/
public function imageHistoryLine( $iscur, $file, $formattedComment ) {
$user = $this->getUser();
$lang = $this->getLanguage();
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
// @phan-suppress-next-line PhanUndeclaredMethod
$img = $iscur ? $file->getName() : $file->getArchiveName();
$uploader = $file->getUploader( File::FOR_THIS_USER, $user );
$local = $this->current->isLocal();
$row = '';
// Deletion link
if ( $local && ( $this->getAuthority()->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
$row .= Html::openElement( 'td' );
# Link to hide content. Don't show useless link to people who cannot hide revisions.
if ( !$iscur && $this->getAuthority()->isAllowed( 'deleterevision' ) ) {
// If file is top revision, is missing or locked from this user, don't link
if ( !$file->userCan( File::DELETED_RESTRICTED, $user ) || !$file->exists() ) {
$row .= Html::check( 'deleterevisions', false, [ 'disabled' => 'disabled' ] );
} else {
$row .= Html::check( 'ids[' . explode( '!', $img, 2 )[0] . ']', false );
}
if ( $this->getAuthority()->isAllowed( 'delete' ) ) {
$row .= ' ';
}
}
# Link to remove from history
if ( $this->getAuthority()->isAllowed( 'delete' ) ) {
if ( $file->exists() ) {
$row .= $linkRenderer->makeKnownLink(
$this->title,
$this->msg( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' )->text(),
[],
[ 'action' => 'delete', 'oldimage' => $iscur ? null : $img ]
);
} else {
// T244567: Non-existing file can not be deleted.
$row .= $this->msg( 'filehist-missing' )->escaped();
}
}
$row .= Html::closeElement( 'td' );
}
// Reversion link/current indicator
$row .= Html::openElement( 'td' );
if ( $iscur ) {
$row .= $this->msg( 'filehist-current' )->escaped();
} elseif ( $local && $this->getAuthority()->probablyCan( 'edit', $this->title )
&& $this->getAuthority()->probablyCan( 'upload', $this->title )
) {
if ( $file->isDeleted( File::DELETED_FILE ) ) {
$row .= $this->msg( 'filehist-revert' )->escaped();
} elseif ( !$file->exists() ) {
// T328112: Lost file, in this case there's no version to revert back to.
$row .= $this->msg( 'filehist-missing' )->escaped();
} else {
$row .= $linkRenderer->makeKnownLink(
$this->title,
$this->msg( 'filehist-revert' )->text(),
[],
[
'action' => 'revert',
'oldimage' => $img,
]
);
}
}
$row .= Html::closeElement( 'td' );
// Date/time and image link
$selected = $file->getTimestamp() === $this->img->getTimestamp();
$row .= Html::openElement( 'td', [
'class' => $selected ? 'filehistory-selected' : null,
'style' => 'white-space: nowrap;'
] );
if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
# Don't link to unviewable files
$row .= Html::element( 'span', [ 'class' => 'history-deleted' ],
$lang->userTimeAndDate( $timestamp, $user )
);
} elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
$timeAndDate = $lang->userTimeAndDate( $timestamp, $user );
if ( $local ) {
$this->setPreventClickjacking( true );
# Make a link to review the image
$url = $linkRenderer->makeKnownLink(
SpecialPage::getTitleFor( 'Revisiondelete' ),
$timeAndDate,
[],
[
'target' => $this->title->getPrefixedText(),
'file' => $img,
'token' => $user->getEditToken( $img )
]
);
} else {
$url = htmlspecialchars( $timeAndDate );
}
$row .= Html::rawElement( 'span', [ 'class' => 'history-deleted' ], $url );
} elseif ( !$file->exists() ) {
$row .= Html::element( 'span', [ 'class' => 'mw-file-missing' ],
$lang->userTimeAndDate( $timestamp, $user )
);
} else {
$url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
$row .= Html::element( 'a', [ 'href' => $url ],
$lang->userTimeAndDate( $timestamp, $user )
);
}
$row .= Html::closeElement( 'td' );
// Thumbnail
if ( $this->showThumb ) {
$row .= Html::rawElement( 'td', [],
$this->getThumbForLine( $file, $iscur ) ?? $this->msg( 'filehist-nothumb' )->escaped()
);
}
// Image dimensions + size
$row .= Html::openElement( 'td' );
$row .= htmlspecialchars( $file->getDimensionsString() );
$row .= $this->msg( 'word-separator' )->escaped();
$row .= Html::element( 'span', [ 'style' => 'white-space: nowrap;' ],
$this->msg( 'parentheses' )->sizeParams( $file->getSize() )->text()
);
$row .= Html::closeElement( 'td' );
// Uploading user
$row .= Html::openElement( 'td' );
// Hide deleted usernames
if ( $uploader ) {
$row .= Linker::userLink( $uploader->getId(), $uploader->getName() );
if ( $local ) {
$row .= Html::rawElement( 'span', [ 'style' => 'white-space: nowrap;' ],
Linker::userToolLinks( $uploader->getId(), $uploader->getName() )
);
}
} else {
$row .= Html::element( 'span', [ 'class' => 'history-deleted' ],
$this->msg( 'rev-deleted-user' )->text()
);
}
$row .= Html::closeElement( 'td' );
// Don't show deleted descriptions
if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
$row .= Html::rawElement( 'td', [],
Html::element( 'span', [ 'class' => 'history-deleted' ],
$this->msg( 'rev-deleted-comment' )->text()
)
);
} else {
$contLang = MediaWikiServices::getInstance()->getContentLanguage();
$row .= Html::rawElement( 'td', [ 'dir' => $contLang->getDir() ], $formattedComment );
}
$rowClass = null;
$this->getHookRunner()->onImagePageFileHistoryLine( $this, $file, $row, $rowClass );
return Html::rawElement( 'tr', [ 'class' => $rowClass ], $row ) . "\n";
}
/**
* @param File $file
* @param bool $iscur
* @return string|null
*/
protected function getThumbForLine( $file, $iscur ) {
$user = $this->getUser();
if ( !$file->allowInlineDisplay() ||
$file->isDeleted( File::DELETED_FILE ) ||
!$file->userCan( File::DELETED_FILE, $user )
) {
return null;
}
$thumbnail = $file->transform(
[
'width' => '120',
'height' => '120',
'isFilePageThumb' => $iscur // old revisions are already versioned
]
);
if ( !$thumbnail ) {
return null;
}
$lang = $this->getLanguage();
$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
$alt = $this->msg(
'filehist-thumbtext',
$lang->userTimeAndDate( $timestamp, $user ),
$lang->userDate( $timestamp, $user ),
$lang->userTime( $timestamp, $user )
)->text();
return $thumbnail->toHtml( [ 'alt' => $alt, 'file-link' => true, 'loading' => 'lazy' ] );
}
/**
* @param bool $enable
* @deprecated since 1.38, use ::setPreventClickjacking() instead
*/
protected function preventClickjacking( $enable = true ) {
$this->preventClickjacking = $enable;
}
/**
* @param bool $enable
* @since 1.38
*/
protected function setPreventClickjacking( bool $enable ) {
$this->preventClickjacking = $enable;
}
/**
* @return bool
*/
public function getPreventClickjacking() {
return $this->preventClickjacking;
}
}