Split ImagePage.php into separate classes
Change-Id: Id2ca94c50b75d24da4d02fe82747a7ce7edccd9f
This commit is contained in:
parent
314fa3e2eb
commit
2c2d6248f9
4 changed files with 534 additions and 496 deletions
|
|
@ -566,8 +566,8 @@ $wgAutoloadLocalClasses = array(
|
|||
'ImageGallery' => __DIR__ . '/includes/gallery/TraditionalImageGallery.php',
|
||||
'ImageGalleryBase' => __DIR__ . '/includes/gallery/ImageGalleryBase.php',
|
||||
'ImageHandler' => __DIR__ . '/includes/media/ImageHandler.php',
|
||||
'ImageHistoryList' => __DIR__ . '/includes/page/ImagePage.php',
|
||||
'ImageHistoryPseudoPager' => __DIR__ . '/includes/page/ImagePage.php',
|
||||
'ImageHistoryList' => __DIR__ . '/includes/page/ImageHistoryList.php',
|
||||
'ImageHistoryPseudoPager' => __DIR__ . '/includes/page/ImageHistoryPseudoPager.php',
|
||||
'ImageListPager' => __DIR__ . '/includes/specials/SpecialListfiles.php',
|
||||
'ImagePage' => __DIR__ . '/includes/page/ImagePage.php',
|
||||
'ImageQueryPage' => __DIR__ . '/includes/specialpage/ImageQueryPage.php',
|
||||
|
|
|
|||
327
includes/page/ImageHistoryList.php
Normal file
327
includes/page/ImageHistoryList.php
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Builds the image revision log shown on image pages
|
||||
*
|
||||
* @ingroup Media
|
||||
*/
|
||||
class ImageHistoryList extends ContextSource {
|
||||
|
||||
/**
|
||||
* @var Title
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $img;
|
||||
|
||||
/**
|
||||
* @var ImagePage
|
||||
*/
|
||||
protected $imagePage;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $current;
|
||||
|
||||
protected $repo, $showThumb;
|
||||
protected $preventClickjacking = false;
|
||||
|
||||
/**
|
||||
* @param ImagePage $imagePage
|
||||
*/
|
||||
public function __construct( $imagePage ) {
|
||||
global $wgShowArchiveThumbnails;
|
||||
$this->current = $imagePage->getFile();
|
||||
$this->img = $imagePage->getDisplayedFile();
|
||||
$this->title = $imagePage->getTitle();
|
||||
$this->imagePage = $imagePage;
|
||||
$this->showThumb = $wgShowArchiveThumbnails && $this->img->canRender();
|
||||
$this->setContext( $imagePage->getContext() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ImagePage
|
||||
*/
|
||||
public function getImagePage() {
|
||||
return $this->imagePage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return File
|
||||
*/
|
||||
public function getFile() {
|
||||
return $this->img;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $navLinks
|
||||
* @return string
|
||||
*/
|
||||
public function beginImageHistoryList( $navLinks = '' ) {
|
||||
return Xml::element( 'h2', array( 'id' => 'filehistory' ), $this->msg( 'filehist' )->text() )
|
||||
. "\n"
|
||||
. "<div id=\"mw-imagepage-section-filehistory\">\n"
|
||||
. $this->msg( 'filehist-help' )->parseAsBlock()
|
||||
. $navLinks . "\n"
|
||||
. Xml::openElement( 'table', array( 'class' => 'wikitable filehistory' ) ) . "\n"
|
||||
. '<tr><th></th>'
|
||||
. ( $this->current->isLocal()
|
||||
&& ( $this->getUser()->isAllowedAny( 'delete', 'deletedhistory' ) ) ? '<th></th>' : '' )
|
||||
. '<th>' . $this->msg( 'filehist-datetime' )->escaped() . '</th>'
|
||||
. ( $this->showThumb ? '<th>' . $this->msg( 'filehist-thumb' )->escaped() . '</th>' : '' )
|
||||
. '<th>' . $this->msg( 'filehist-dimensions' )->escaped() . '</th>'
|
||||
. '<th>' . $this->msg( 'filehist-user' )->escaped() . '</th>'
|
||||
. '<th>' . $this->msg( 'filehist-comment' )->escaped() . '</th>'
|
||||
. "</tr>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $navLinks
|
||||
* @return string
|
||||
*/
|
||||
public function endImageHistoryList( $navLinks = '' ) {
|
||||
return "</table>\n$navLinks\n</div>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $iscur
|
||||
* @param File $file
|
||||
* @return string
|
||||
*/
|
||||
public function imageHistoryLine( $iscur, $file ) {
|
||||
global $wgContLang;
|
||||
|
||||
$user = $this->getUser();
|
||||
$lang = $this->getLanguage();
|
||||
$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
|
||||
$img = $iscur ? $file->getName() : $file->getArchiveName();
|
||||
$userId = $file->getUser( 'id' );
|
||||
$userText = $file->getUser( 'text' );
|
||||
$description = $file->getDescription( File::FOR_THIS_USER, $user );
|
||||
|
||||
$local = $this->current->isLocal();
|
||||
$row = $selected = '';
|
||||
|
||||
// Deletion link
|
||||
if ( $local && ( $user->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
|
||||
$row .= '<td>';
|
||||
# Link to remove from history
|
||||
if ( $user->isAllowed( 'delete' ) ) {
|
||||
$q = array( 'action' => 'delete' );
|
||||
if ( !$iscur ) {
|
||||
$q['oldimage'] = $img;
|
||||
}
|
||||
$row .= Linker::linkKnown(
|
||||
$this->title,
|
||||
$this->msg( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' )->escaped(),
|
||||
array(), $q
|
||||
);
|
||||
}
|
||||
# Link to hide content. Don't show useless link to people who cannot hide revisions.
|
||||
$canHide = $user->isAllowed( 'deleterevision' );
|
||||
if ( $canHide || ( $user->isAllowed( 'deletedhistory' ) && $file->getVisibility() ) ) {
|
||||
if ( $user->isAllowed( 'delete' ) ) {
|
||||
$row .= '<br />';
|
||||
}
|
||||
// If file is top revision or locked from this user, don't link
|
||||
if ( $iscur || !$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
|
||||
$del = Linker::revDeleteLinkDisabled( $canHide );
|
||||
} else {
|
||||
list( $ts, ) = explode( '!', $img, 2 );
|
||||
$query = array(
|
||||
'type' => 'oldimage',
|
||||
'target' => $this->title->getPrefixedText(),
|
||||
'ids' => $ts,
|
||||
);
|
||||
$del = Linker::revDeleteLink( $query,
|
||||
$file->isDeleted( File::DELETED_RESTRICTED ), $canHide );
|
||||
}
|
||||
$row .= $del;
|
||||
}
|
||||
$row .= '</td>';
|
||||
}
|
||||
|
||||
// Reversion link/current indicator
|
||||
$row .= '<td>';
|
||||
if ( $iscur ) {
|
||||
$row .= $this->msg( 'filehist-current' )->escaped();
|
||||
} elseif ( $local && $this->title->quickUserCan( 'edit', $user )
|
||||
&& $this->title->quickUserCan( 'upload', $user )
|
||||
) {
|
||||
if ( $file->isDeleted( File::DELETED_FILE ) ) {
|
||||
$row .= $this->msg( 'filehist-revert' )->escaped();
|
||||
} else {
|
||||
$row .= Linker::linkKnown(
|
||||
$this->title,
|
||||
$this->msg( 'filehist-revert' )->escaped(),
|
||||
array(),
|
||||
array(
|
||||
'action' => 'revert',
|
||||
'oldimage' => $img,
|
||||
'wpEditToken' => $user->getEditToken( $img )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
$row .= '</td>';
|
||||
|
||||
// Date/time and image link
|
||||
if ( $file->getTimestamp() === $this->img->getTimestamp() ) {
|
||||
$selected = "class='filehistory-selected'";
|
||||
}
|
||||
$row .= "<td $selected style='white-space: nowrap;'>";
|
||||
if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
|
||||
# Don't link to unviewable files
|
||||
$row .= '<span class="history-deleted">'
|
||||
. $lang->userTimeAndDate( $timestamp, $user ) . '</span>';
|
||||
} elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
|
||||
if ( $local ) {
|
||||
$this->preventClickjacking();
|
||||
$revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
|
||||
# Make a link to review the image
|
||||
$url = Linker::linkKnown(
|
||||
$revdel,
|
||||
$lang->userTimeAndDate( $timestamp, $user ),
|
||||
array(),
|
||||
array(
|
||||
'target' => $this->title->getPrefixedText(),
|
||||
'file' => $img,
|
||||
'token' => $user->getEditToken( $img )
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$url = $lang->userTimeAndDate( $timestamp, $user );
|
||||
}
|
||||
$row .= '<span class="history-deleted">' . $url . '</span>';
|
||||
} elseif ( !$file->exists() ) {
|
||||
$row .= '<span class="mw-file-missing">'
|
||||
. $lang->userTimeAndDate( $timestamp, $user ) . '</span>';
|
||||
} else {
|
||||
$url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
|
||||
$row .= Xml::element(
|
||||
'a',
|
||||
array( 'href' => $url ),
|
||||
$lang->userTimeAndDate( $timestamp, $user )
|
||||
);
|
||||
}
|
||||
$row .= "</td>";
|
||||
|
||||
// Thumbnail
|
||||
if ( $this->showThumb ) {
|
||||
$row .= '<td>' . $this->getThumbForLine( $file ) . '</td>';
|
||||
}
|
||||
|
||||
// Image dimensions + size
|
||||
$row .= '<td>';
|
||||
$row .= htmlspecialchars( $file->getDimensionsString() );
|
||||
$row .= $this->msg( 'word-separator' )->escaped();
|
||||
$row .= '<span style="white-space: nowrap;">';
|
||||
$row .= $this->msg( 'parentheses' )->sizeParams( $file->getSize() )->escaped();
|
||||
$row .= '</span>';
|
||||
$row .= '</td>';
|
||||
|
||||
// Uploading user
|
||||
$row .= '<td>';
|
||||
// Hide deleted usernames
|
||||
if ( $file->isDeleted( File::DELETED_USER ) ) {
|
||||
$row .= '<span class="history-deleted">'
|
||||
. $this->msg( 'rev-deleted-user' )->escaped() . '</span>';
|
||||
} else {
|
||||
if ( $local ) {
|
||||
$row .= Linker::userLink( $userId, $userText );
|
||||
$row .= '<span style="white-space: nowrap;">';
|
||||
$row .= Linker::userToolLinks( $userId, $userText );
|
||||
$row .= '</span>';
|
||||
} else {
|
||||
$row .= htmlspecialchars( $userText );
|
||||
}
|
||||
}
|
||||
$row .= '</td>';
|
||||
|
||||
// Don't show deleted descriptions
|
||||
if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
|
||||
$row .= '<td><span class="history-deleted">' .
|
||||
$this->msg( 'rev-deleted-comment' )->escaped() . '</span></td>';
|
||||
} else {
|
||||
$row .= '<td dir="' . $wgContLang->getDir() . '">' .
|
||||
Linker::formatComment( $description, $this->title ) . '</td>';
|
||||
}
|
||||
|
||||
$rowClass = null;
|
||||
Hooks::run( 'ImagePageFileHistoryLine', array( $this, $file, &$row, &$rowClass ) );
|
||||
$classAttr = $rowClass ? " class='$rowClass'" : '';
|
||||
|
||||
return "<tr{$classAttr}>{$row}</tr>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param File $file
|
||||
* @return string
|
||||
*/
|
||||
protected function getThumbForLine( $file ) {
|
||||
$lang = $this->getLanguage();
|
||||
$user = $this->getUser();
|
||||
if ( $file->allowInlineDisplay() && $file->userCan( File::DELETED_FILE, $user )
|
||||
&& !$file->isDeleted( File::DELETED_FILE )
|
||||
) {
|
||||
$params = array(
|
||||
'width' => '120',
|
||||
'height' => '120',
|
||||
);
|
||||
$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
|
||||
|
||||
$thumbnail = $file->transform( $params );
|
||||
$options = array(
|
||||
'alt' => $this->msg( 'filehist-thumbtext',
|
||||
$lang->userTimeAndDate( $timestamp, $user ),
|
||||
$lang->userDate( $timestamp, $user ),
|
||||
$lang->userTime( $timestamp, $user ) )->text(),
|
||||
'file-link' => true,
|
||||
);
|
||||
|
||||
if ( !$thumbnail ) {
|
||||
return $this->msg( 'filehist-nothumb' )->escaped();
|
||||
}
|
||||
|
||||
return $thumbnail->toHtml( $options );
|
||||
} else {
|
||||
return $this->msg( 'filehist-nothumb' )->escaped();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $enable
|
||||
*/
|
||||
protected function preventClickjacking( $enable = true ) {
|
||||
$this->preventClickjacking = $enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getPreventClickjacking() {
|
||||
return $this->preventClickjacking;
|
||||
}
|
||||
}
|
||||
205
includes/page/ImageHistoryPseudoPager.php
Normal file
205
includes/page/ImageHistoryPseudoPager.php
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
class ImageHistoryPseudoPager extends ReverseChronologicalPager {
|
||||
protected $preventClickjacking = false;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $mImg;
|
||||
|
||||
/**
|
||||
* @var Title
|
||||
*/
|
||||
protected $mTitle;
|
||||
|
||||
/**
|
||||
* @param ImagePage $imagePage
|
||||
*/
|
||||
function __construct( $imagePage ) {
|
||||
parent::__construct( $imagePage->getContext() );
|
||||
$this->mImagePage = $imagePage;
|
||||
$this->mTitle = clone $imagePage->getTitle();
|
||||
$this->mTitle->setFragment( '#filehistory' );
|
||||
$this->mImg = null;
|
||||
$this->mHist = array();
|
||||
$this->mRange = array( 0, 0 ); // display range
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Title
|
||||
*/
|
||||
function getTitle() {
|
||||
return $this->mTitle;
|
||||
}
|
||||
|
||||
function getQueryInfo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function getIndexField() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $row
|
||||
* @return string
|
||||
*/
|
||||
function formatRow( $row ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function getBody() {
|
||||
$s = '';
|
||||
$this->doQuery();
|
||||
if ( count( $this->mHist ) ) {
|
||||
if ( $this->mImg->isLocal() ) {
|
||||
// Do a batch existence check for user pages and talkpages
|
||||
$linkBatch = new LinkBatch();
|
||||
for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
|
||||
$file = $this->mHist[$i];
|
||||
$user = $file->getUser( 'text' );
|
||||
$linkBatch->add( NS_USER, $user );
|
||||
$linkBatch->add( NS_USER_TALK, $user );
|
||||
}
|
||||
$linkBatch->execute();
|
||||
}
|
||||
|
||||
$list = new ImageHistoryList( $this->mImagePage );
|
||||
# Generate prev/next links
|
||||
$navLink = $this->getNavigationBar();
|
||||
$s = $list->beginImageHistoryList( $navLink );
|
||||
// Skip rows there just for paging links
|
||||
for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
|
||||
$file = $this->mHist[$i];
|
||||
$s .= $list->imageHistoryLine( !$file->isOld(), $file );
|
||||
}
|
||||
$s .= $list->endImageHistoryList( $navLink );
|
||||
|
||||
if ( $list->getPreventClickjacking() ) {
|
||||
$this->preventClickjacking();
|
||||
}
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
function doQuery() {
|
||||
if ( $this->mQueryDone ) {
|
||||
return;
|
||||
}
|
||||
$this->mImg = $this->mImagePage->getFile(); // ensure loading
|
||||
if ( !$this->mImg->exists() ) {
|
||||
return;
|
||||
}
|
||||
$queryLimit = $this->mLimit + 1; // limit plus extra row
|
||||
if ( $this->mIsBackwards ) {
|
||||
// Fetch the file history
|
||||
$this->mHist = $this->mImg->getHistory( $queryLimit, null, $this->mOffset, false );
|
||||
// The current rev may not meet the offset/limit
|
||||
$numRows = count( $this->mHist );
|
||||
if ( $numRows <= $this->mLimit && $this->mImg->getTimestamp() > $this->mOffset ) {
|
||||
$this->mHist = array_merge( array( $this->mImg ), $this->mHist );
|
||||
}
|
||||
} else {
|
||||
// The current rev may not meet the offset
|
||||
if ( !$this->mOffset || $this->mImg->getTimestamp() < $this->mOffset ) {
|
||||
$this->mHist[] = $this->mImg;
|
||||
}
|
||||
// Old image versions (fetch extra row for nav links)
|
||||
$oiLimit = count( $this->mHist ) ? $this->mLimit : $this->mLimit + 1;
|
||||
// Fetch the file history
|
||||
$this->mHist = array_merge( $this->mHist,
|
||||
$this->mImg->getHistory( $oiLimit, $this->mOffset, null, false ) );
|
||||
}
|
||||
$numRows = count( $this->mHist ); // Total number of query results
|
||||
if ( $numRows ) {
|
||||
# Index value of top item in the list
|
||||
$firstIndex = $this->mIsBackwards ?
|
||||
$this->mHist[$numRows - 1]->getTimestamp() : $this->mHist[0]->getTimestamp();
|
||||
# Discard the extra result row if there is one
|
||||
if ( $numRows > $this->mLimit && $numRows > 1 ) {
|
||||
if ( $this->mIsBackwards ) {
|
||||
# Index value of item past the index
|
||||
$this->mPastTheEndIndex = $this->mHist[0]->getTimestamp();
|
||||
# Index value of bottom item in the list
|
||||
$lastIndex = $this->mHist[1]->getTimestamp();
|
||||
# Display range
|
||||
$this->mRange = array( 1, $numRows - 1 );
|
||||
} else {
|
||||
# Index value of item past the index
|
||||
$this->mPastTheEndIndex = $this->mHist[$numRows - 1]->getTimestamp();
|
||||
# Index value of bottom item in the list
|
||||
$lastIndex = $this->mHist[$numRows - 2]->getTimestamp();
|
||||
# Display range
|
||||
$this->mRange = array( 0, $numRows - 2 );
|
||||
}
|
||||
} else {
|
||||
# Setting indexes to an empty string means that they will be
|
||||
# omitted if they would otherwise appear in URLs. It just so
|
||||
# happens that this is the right thing to do in the standard
|
||||
# UI, in all the relevant cases.
|
||||
$this->mPastTheEndIndex = '';
|
||||
# Index value of bottom item in the list
|
||||
$lastIndex = $this->mIsBackwards ?
|
||||
$this->mHist[0]->getTimestamp() : $this->mHist[$numRows - 1]->getTimestamp();
|
||||
# Display range
|
||||
$this->mRange = array( 0, $numRows - 1 );
|
||||
}
|
||||
} else {
|
||||
$firstIndex = '';
|
||||
$lastIndex = '';
|
||||
$this->mPastTheEndIndex = '';
|
||||
}
|
||||
if ( $this->mIsBackwards ) {
|
||||
$this->mIsFirst = ( $numRows < $queryLimit );
|
||||
$this->mIsLast = ( $this->mOffset == '' );
|
||||
$this->mLastShown = $firstIndex;
|
||||
$this->mFirstShown = $lastIndex;
|
||||
} else {
|
||||
$this->mIsFirst = ( $this->mOffset == '' );
|
||||
$this->mIsLast = ( $numRows < $queryLimit );
|
||||
$this->mLastShown = $lastIndex;
|
||||
$this->mFirstShown = $firstIndex;
|
||||
}
|
||||
$this->mQueryDone = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $enable
|
||||
*/
|
||||
protected function preventClickjacking( $enable = true ) {
|
||||
$this->preventClickjacking = $enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getPreventClickjacking() {
|
||||
return $this->preventClickjacking;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1242,497 +1242,3 @@ EOT
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the image revision log shown on image pages
|
||||
*
|
||||
* @ingroup Media
|
||||
*/
|
||||
class ImageHistoryList extends ContextSource {
|
||||
|
||||
/**
|
||||
* @var Title
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $img;
|
||||
|
||||
/**
|
||||
* @var ImagePage
|
||||
*/
|
||||
protected $imagePage;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $current;
|
||||
|
||||
protected $repo, $showThumb;
|
||||
protected $preventClickjacking = false;
|
||||
|
||||
/**
|
||||
* @param ImagePage $imagePage
|
||||
*/
|
||||
public function __construct( $imagePage ) {
|
||||
global $wgShowArchiveThumbnails;
|
||||
$this->current = $imagePage->getFile();
|
||||
$this->img = $imagePage->getDisplayedFile();
|
||||
$this->title = $imagePage->getTitle();
|
||||
$this->imagePage = $imagePage;
|
||||
$this->showThumb = $wgShowArchiveThumbnails && $this->img->canRender();
|
||||
$this->setContext( $imagePage->getContext() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ImagePage
|
||||
*/
|
||||
public function getImagePage() {
|
||||
return $this->imagePage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return File
|
||||
*/
|
||||
public function getFile() {
|
||||
return $this->img;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $navLinks
|
||||
* @return string
|
||||
*/
|
||||
public function beginImageHistoryList( $navLinks = '' ) {
|
||||
return Xml::element( 'h2', array( 'id' => 'filehistory' ), $this->msg( 'filehist' )->text() )
|
||||
. "\n"
|
||||
. "<div id=\"mw-imagepage-section-filehistory\">\n"
|
||||
. $this->msg( 'filehist-help' )->parseAsBlock()
|
||||
. $navLinks . "\n"
|
||||
. Xml::openElement( 'table', array( 'class' => 'wikitable filehistory' ) ) . "\n"
|
||||
. '<tr><th></th>'
|
||||
. ( $this->current->isLocal()
|
||||
&& ( $this->getUser()->isAllowedAny( 'delete', 'deletedhistory' ) ) ? '<th></th>' : '' )
|
||||
. '<th>' . $this->msg( 'filehist-datetime' )->escaped() . '</th>'
|
||||
. ( $this->showThumb ? '<th>' . $this->msg( 'filehist-thumb' )->escaped() . '</th>' : '' )
|
||||
. '<th>' . $this->msg( 'filehist-dimensions' )->escaped() . '</th>'
|
||||
. '<th>' . $this->msg( 'filehist-user' )->escaped() . '</th>'
|
||||
. '<th>' . $this->msg( 'filehist-comment' )->escaped() . '</th>'
|
||||
. "</tr>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $navLinks
|
||||
* @return string
|
||||
*/
|
||||
public function endImageHistoryList( $navLinks = '' ) {
|
||||
return "</table>\n$navLinks\n</div>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $iscur
|
||||
* @param File $file
|
||||
* @return string
|
||||
*/
|
||||
public function imageHistoryLine( $iscur, $file ) {
|
||||
global $wgContLang;
|
||||
|
||||
$user = $this->getUser();
|
||||
$lang = $this->getLanguage();
|
||||
$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
|
||||
$img = $iscur ? $file->getName() : $file->getArchiveName();
|
||||
$userId = $file->getUser( 'id' );
|
||||
$userText = $file->getUser( 'text' );
|
||||
$description = $file->getDescription( File::FOR_THIS_USER, $user );
|
||||
|
||||
$local = $this->current->isLocal();
|
||||
$row = $selected = '';
|
||||
|
||||
// Deletion link
|
||||
if ( $local && ( $user->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
|
||||
$row .= '<td>';
|
||||
# Link to remove from history
|
||||
if ( $user->isAllowed( 'delete' ) ) {
|
||||
$q = array( 'action' => 'delete' );
|
||||
if ( !$iscur ) {
|
||||
$q['oldimage'] = $img;
|
||||
}
|
||||
$row .= Linker::linkKnown(
|
||||
$this->title,
|
||||
$this->msg( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' )->escaped(),
|
||||
array(), $q
|
||||
);
|
||||
}
|
||||
# Link to hide content. Don't show useless link to people who cannot hide revisions.
|
||||
$canHide = $user->isAllowed( 'deleterevision' );
|
||||
if ( $canHide || ( $user->isAllowed( 'deletedhistory' ) && $file->getVisibility() ) ) {
|
||||
if ( $user->isAllowed( 'delete' ) ) {
|
||||
$row .= '<br />';
|
||||
}
|
||||
// If file is top revision or locked from this user, don't link
|
||||
if ( $iscur || !$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
|
||||
$del = Linker::revDeleteLinkDisabled( $canHide );
|
||||
} else {
|
||||
list( $ts, ) = explode( '!', $img, 2 );
|
||||
$query = array(
|
||||
'type' => 'oldimage',
|
||||
'target' => $this->title->getPrefixedText(),
|
||||
'ids' => $ts,
|
||||
);
|
||||
$del = Linker::revDeleteLink( $query,
|
||||
$file->isDeleted( File::DELETED_RESTRICTED ), $canHide );
|
||||
}
|
||||
$row .= $del;
|
||||
}
|
||||
$row .= '</td>';
|
||||
}
|
||||
|
||||
// Reversion link/current indicator
|
||||
$row .= '<td>';
|
||||
if ( $iscur ) {
|
||||
$row .= $this->msg( 'filehist-current' )->escaped();
|
||||
} elseif ( $local && $this->title->quickUserCan( 'edit', $user )
|
||||
&& $this->title->quickUserCan( 'upload', $user )
|
||||
) {
|
||||
if ( $file->isDeleted( File::DELETED_FILE ) ) {
|
||||
$row .= $this->msg( 'filehist-revert' )->escaped();
|
||||
} else {
|
||||
$row .= Linker::linkKnown(
|
||||
$this->title,
|
||||
$this->msg( 'filehist-revert' )->escaped(),
|
||||
array(),
|
||||
array(
|
||||
'action' => 'revert',
|
||||
'oldimage' => $img,
|
||||
'wpEditToken' => $user->getEditToken( $img )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
$row .= '</td>';
|
||||
|
||||
// Date/time and image link
|
||||
if ( $file->getTimestamp() === $this->img->getTimestamp() ) {
|
||||
$selected = "class='filehistory-selected'";
|
||||
}
|
||||
$row .= "<td $selected style='white-space: nowrap;'>";
|
||||
if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
|
||||
# Don't link to unviewable files
|
||||
$row .= '<span class="history-deleted">'
|
||||
. $lang->userTimeAndDate( $timestamp, $user ) . '</span>';
|
||||
} elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
|
||||
if ( $local ) {
|
||||
$this->preventClickjacking();
|
||||
$revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
|
||||
# Make a link to review the image
|
||||
$url = Linker::linkKnown(
|
||||
$revdel,
|
||||
$lang->userTimeAndDate( $timestamp, $user ),
|
||||
array(),
|
||||
array(
|
||||
'target' => $this->title->getPrefixedText(),
|
||||
'file' => $img,
|
||||
'token' => $user->getEditToken( $img )
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$url = $lang->userTimeAndDate( $timestamp, $user );
|
||||
}
|
||||
$row .= '<span class="history-deleted">' . $url . '</span>';
|
||||
} elseif ( !$file->exists() ) {
|
||||
$row .= '<span class="mw-file-missing">'
|
||||
. $lang->userTimeAndDate( $timestamp, $user ) . '</span>';
|
||||
} else {
|
||||
$url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
|
||||
$row .= Xml::element(
|
||||
'a',
|
||||
array( 'href' => $url ),
|
||||
$lang->userTimeAndDate( $timestamp, $user )
|
||||
);
|
||||
}
|
||||
$row .= "</td>";
|
||||
|
||||
// Thumbnail
|
||||
if ( $this->showThumb ) {
|
||||
$row .= '<td>' . $this->getThumbForLine( $file ) . '</td>';
|
||||
}
|
||||
|
||||
// Image dimensions + size
|
||||
$row .= '<td>';
|
||||
$row .= htmlspecialchars( $file->getDimensionsString() );
|
||||
$row .= $this->msg( 'word-separator' )->escaped();
|
||||
$row .= '<span style="white-space: nowrap;">';
|
||||
$row .= $this->msg( 'parentheses' )->sizeParams( $file->getSize() )->escaped();
|
||||
$row .= '</span>';
|
||||
$row .= '</td>';
|
||||
|
||||
// Uploading user
|
||||
$row .= '<td>';
|
||||
// Hide deleted usernames
|
||||
if ( $file->isDeleted( File::DELETED_USER ) ) {
|
||||
$row .= '<span class="history-deleted">'
|
||||
. $this->msg( 'rev-deleted-user' )->escaped() . '</span>';
|
||||
} else {
|
||||
if ( $local ) {
|
||||
$row .= Linker::userLink( $userId, $userText );
|
||||
$row .= '<span style="white-space: nowrap;">';
|
||||
$row .= Linker::userToolLinks( $userId, $userText );
|
||||
$row .= '</span>';
|
||||
} else {
|
||||
$row .= htmlspecialchars( $userText );
|
||||
}
|
||||
}
|
||||
$row .= '</td>';
|
||||
|
||||
// Don't show deleted descriptions
|
||||
if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
|
||||
$row .= '<td><span class="history-deleted">' .
|
||||
$this->msg( 'rev-deleted-comment' )->escaped() . '</span></td>';
|
||||
} else {
|
||||
$row .= '<td dir="' . $wgContLang->getDir() . '">' .
|
||||
Linker::formatComment( $description, $this->title ) . '</td>';
|
||||
}
|
||||
|
||||
$rowClass = null;
|
||||
Hooks::run( 'ImagePageFileHistoryLine', array( $this, $file, &$row, &$rowClass ) );
|
||||
$classAttr = $rowClass ? " class='$rowClass'" : '';
|
||||
|
||||
return "<tr{$classAttr}>{$row}</tr>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param File $file
|
||||
* @return string
|
||||
*/
|
||||
protected function getThumbForLine( $file ) {
|
||||
$lang = $this->getLanguage();
|
||||
$user = $this->getUser();
|
||||
if ( $file->allowInlineDisplay() && $file->userCan( File::DELETED_FILE, $user )
|
||||
&& !$file->isDeleted( File::DELETED_FILE )
|
||||
) {
|
||||
$params = array(
|
||||
'width' => '120',
|
||||
'height' => '120',
|
||||
);
|
||||
$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
|
||||
|
||||
$thumbnail = $file->transform( $params );
|
||||
$options = array(
|
||||
'alt' => $this->msg( 'filehist-thumbtext',
|
||||
$lang->userTimeAndDate( $timestamp, $user ),
|
||||
$lang->userDate( $timestamp, $user ),
|
||||
$lang->userTime( $timestamp, $user ) )->text(),
|
||||
'file-link' => true,
|
||||
);
|
||||
|
||||
if ( !$thumbnail ) {
|
||||
return $this->msg( 'filehist-nothumb' )->escaped();
|
||||
}
|
||||
|
||||
return $thumbnail->toHtml( $options );
|
||||
} else {
|
||||
return $this->msg( 'filehist-nothumb' )->escaped();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $enable
|
||||
*/
|
||||
protected function preventClickjacking( $enable = true ) {
|
||||
$this->preventClickjacking = $enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getPreventClickjacking() {
|
||||
return $this->preventClickjacking;
|
||||
}
|
||||
}
|
||||
|
||||
class ImageHistoryPseudoPager extends ReverseChronologicalPager {
|
||||
protected $preventClickjacking = false;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $mImg;
|
||||
|
||||
/**
|
||||
* @var Title
|
||||
*/
|
||||
protected $mTitle;
|
||||
|
||||
/**
|
||||
* @param ImagePage $imagePage
|
||||
*/
|
||||
function __construct( $imagePage ) {
|
||||
parent::__construct( $imagePage->getContext() );
|
||||
$this->mImagePage = $imagePage;
|
||||
$this->mTitle = clone $imagePage->getTitle();
|
||||
$this->mTitle->setFragment( '#filehistory' );
|
||||
$this->mImg = null;
|
||||
$this->mHist = array();
|
||||
$this->mRange = array( 0, 0 ); // display range
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Title
|
||||
*/
|
||||
function getTitle() {
|
||||
return $this->mTitle;
|
||||
}
|
||||
|
||||
function getQueryInfo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function getIndexField() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $row
|
||||
* @return string
|
||||
*/
|
||||
function formatRow( $row ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function getBody() {
|
||||
$s = '';
|
||||
$this->doQuery();
|
||||
if ( count( $this->mHist ) ) {
|
||||
if ( $this->mImg->isLocal() ) {
|
||||
// Do a batch existence check for user pages and talkpages
|
||||
$linkBatch = new LinkBatch();
|
||||
for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
|
||||
$file = $this->mHist[$i];
|
||||
$user = $file->getUser( 'text' );
|
||||
$linkBatch->add( NS_USER, $user );
|
||||
$linkBatch->add( NS_USER_TALK, $user );
|
||||
}
|
||||
$linkBatch->execute();
|
||||
}
|
||||
|
||||
$list = new ImageHistoryList( $this->mImagePage );
|
||||
# Generate prev/next links
|
||||
$navLink = $this->getNavigationBar();
|
||||
$s = $list->beginImageHistoryList( $navLink );
|
||||
// Skip rows there just for paging links
|
||||
for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
|
||||
$file = $this->mHist[$i];
|
||||
$s .= $list->imageHistoryLine( !$file->isOld(), $file );
|
||||
}
|
||||
$s .= $list->endImageHistoryList( $navLink );
|
||||
|
||||
if ( $list->getPreventClickjacking() ) {
|
||||
$this->preventClickjacking();
|
||||
}
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
function doQuery() {
|
||||
if ( $this->mQueryDone ) {
|
||||
return;
|
||||
}
|
||||
$this->mImg = $this->mImagePage->getFile(); // ensure loading
|
||||
if ( !$this->mImg->exists() ) {
|
||||
return;
|
||||
}
|
||||
$queryLimit = $this->mLimit + 1; // limit plus extra row
|
||||
if ( $this->mIsBackwards ) {
|
||||
// Fetch the file history
|
||||
$this->mHist = $this->mImg->getHistory( $queryLimit, null, $this->mOffset, false );
|
||||
// The current rev may not meet the offset/limit
|
||||
$numRows = count( $this->mHist );
|
||||
if ( $numRows <= $this->mLimit && $this->mImg->getTimestamp() > $this->mOffset ) {
|
||||
$this->mHist = array_merge( array( $this->mImg ), $this->mHist );
|
||||
}
|
||||
} else {
|
||||
// The current rev may not meet the offset
|
||||
if ( !$this->mOffset || $this->mImg->getTimestamp() < $this->mOffset ) {
|
||||
$this->mHist[] = $this->mImg;
|
||||
}
|
||||
// Old image versions (fetch extra row for nav links)
|
||||
$oiLimit = count( $this->mHist ) ? $this->mLimit : $this->mLimit + 1;
|
||||
// Fetch the file history
|
||||
$this->mHist = array_merge( $this->mHist,
|
||||
$this->mImg->getHistory( $oiLimit, $this->mOffset, null, false ) );
|
||||
}
|
||||
$numRows = count( $this->mHist ); // Total number of query results
|
||||
if ( $numRows ) {
|
||||
# Index value of top item in the list
|
||||
$firstIndex = $this->mIsBackwards ?
|
||||
$this->mHist[$numRows - 1]->getTimestamp() : $this->mHist[0]->getTimestamp();
|
||||
# Discard the extra result row if there is one
|
||||
if ( $numRows > $this->mLimit && $numRows > 1 ) {
|
||||
if ( $this->mIsBackwards ) {
|
||||
# Index value of item past the index
|
||||
$this->mPastTheEndIndex = $this->mHist[0]->getTimestamp();
|
||||
# Index value of bottom item in the list
|
||||
$lastIndex = $this->mHist[1]->getTimestamp();
|
||||
# Display range
|
||||
$this->mRange = array( 1, $numRows - 1 );
|
||||
} else {
|
||||
# Index value of item past the index
|
||||
$this->mPastTheEndIndex = $this->mHist[$numRows - 1]->getTimestamp();
|
||||
# Index value of bottom item in the list
|
||||
$lastIndex = $this->mHist[$numRows - 2]->getTimestamp();
|
||||
# Display range
|
||||
$this->mRange = array( 0, $numRows - 2 );
|
||||
}
|
||||
} else {
|
||||
# Setting indexes to an empty string means that they will be
|
||||
# omitted if they would otherwise appear in URLs. It just so
|
||||
# happens that this is the right thing to do in the standard
|
||||
# UI, in all the relevant cases.
|
||||
$this->mPastTheEndIndex = '';
|
||||
# Index value of bottom item in the list
|
||||
$lastIndex = $this->mIsBackwards ?
|
||||
$this->mHist[0]->getTimestamp() : $this->mHist[$numRows - 1]->getTimestamp();
|
||||
# Display range
|
||||
$this->mRange = array( 0, $numRows - 1 );
|
||||
}
|
||||
} else {
|
||||
$firstIndex = '';
|
||||
$lastIndex = '';
|
||||
$this->mPastTheEndIndex = '';
|
||||
}
|
||||
if ( $this->mIsBackwards ) {
|
||||
$this->mIsFirst = ( $numRows < $queryLimit );
|
||||
$this->mIsLast = ( $this->mOffset == '' );
|
||||
$this->mLastShown = $firstIndex;
|
||||
$this->mFirstShown = $lastIndex;
|
||||
} else {
|
||||
$this->mIsFirst = ( $this->mOffset == '' );
|
||||
$this->mIsLast = ( $numRows < $queryLimit );
|
||||
$this->mLastShown = $lastIndex;
|
||||
$this->mFirstShown = $firstIndex;
|
||||
}
|
||||
$this->mQueryDone = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $enable
|
||||
*/
|
||||
protected function preventClickjacking( $enable = true ) {
|
||||
$this->preventClickjacking = $enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getPreventClickjacking() {
|
||||
return $this->preventClickjacking;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue