* Page history
*
* Split off from Article.php and Skin.php, 2003-12-22
+ *
+ * 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
*/
return 'history';
}
- public function getRestriction() {
- return 'read';
- }
-
public function requiresWrite() {
return false;
}
/**
* Print the history page for an article.
- * @return nothing
*/
function onView() {
- global $wgScript, $wgUseFileCache, $wgSquidMaxage;
+ global $wgScript, $wgUseFileCache;
$out = $this->getOutput();
$request = $this->getRequest();
wfProfileIn( __METHOD__ );
- if ( $request->getFullRequestURL() == $this->getTitle()->getInternalURL( 'action=history' ) ) {
- $out->setSquidMaxage( $wgSquidMaxage );
- }
-
$this->preCacheMessages();
# Fill in the file cache if not set already
// Handle atom/RSS feeds.
$feedType = $request->getVal( 'feed' );
if ( $feedType ) {
+ $this->feed( $feedType );
wfProfileOut( __METHOD__ );
- return $this->feed( $feedType );
+ return;
}
// Fail nicely if article doesn't exist.
- if ( !$this->getTitle()->exists() ) {
+ if ( !$this->page->exists() ) {
$out->addWikiMsg( 'nohistory' );
# show deletion/move log if there is an entry
LogEventsList::showLogExtract(
'</fieldset></form>'
);
- wfRunHooks( 'PageHistoryBeforeList', array( &$this->article ) );
+ wfRunHooks( 'PageHistoryBeforeList', array( &$this->page ) );
// Create and output the list.
$pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds );
$offsets = array();
}
- $page_id = $this->getTitle()->getArticleID();
+ $page_id = $this->page->getId();
return $dbr->select( 'revision',
Revision::selectFields(),
public $lastRow = false, $counter, $historyPage, $buttons, $conds;
protected $oldIdChecked;
protected $preventClickjacking = false;
+ /**
+ * @var array
+ */
+ protected $parentLens;
function __construct( $historyPage, $year = '', $month = '', $tagFilter = '', $conds = array() ) {
parent::__construct( $historyPage->getContext() );
'tables' => array( 'revision', 'user' ),
'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ),
'conds' => array_merge(
- array( 'rev_page' => $this->getTitle()->getArticleID() ),
+ array( 'rev_page' => $this->getWikiPage()->getId() ),
$this->conds ),
'options' => array( 'USE INDEX' => array( 'revision' => 'page_timestamp' ) ),
'join_conds' => array(
- 'user' => array( 'LEFT JOIN', 'rev_user != 0 AND user_id = rev_user' ),
+ 'user' => Revision::userJoinCond(),
'tag_summary' => array( 'LEFT JOIN', 'ts_rev_id=rev_id' ) ),
);
ChangeTags::modifyDisplayQuery(
# Do a link batch query
$this->mResult->seek( 0 );
$batch = new LinkBatch();
- # Give some pointers to make (last) links
+ $revIds = array();
foreach ( $this->mResult as $row ) {
- $batch->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
- $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->user_name ) );
+ if( $row->rev_parent_id ) {
+ $revIds[] = $row->rev_parent_id;
+ }
+ if( !is_null( $row->user_name ) ) {
+ $batch->add( NS_USER, $row->user_name );
+ $batch->add( NS_USER_TALK, $row->user_name );
+ } else { # for anons or usernames of imported revisions
+ $batch->add( NS_USER, $row->rev_user_text );
+ $batch->add( NS_USER_TALK, $row->rev_user_text );
+ }
}
+ $this->parentLens = $this->getParentLengths( $revIds );
$batch->execute();
$this->mResult->seek( 0 );
}
+ /**
+ * Do a batched query to get the parent revision lengths
+ * @param $revIds array
+ * @return array
+ * @TODO: stolen from Contributions, refactor
+ */
+ private function getParentLengths( array $revIds ) {
+ $revLens = array();
+ if ( !$revIds ) {
+ return $revLens; // empty
+ }
+ wfProfileIn( __METHOD__ );
+ $res = $this->mDb->select( 'revision',
+ array( 'rev_id', 'rev_len' ),
+ array( 'rev_id' => $revIds ),
+ __METHOD__ );
+ foreach ( $res as $row ) {
+ $revLens[$row->rev_id] = $row->rev_len;
+ }
+ wfProfileOut( __METHOD__ );
+ return $revLens;
+ }
+
/**
* Creates begin of history list with a submit button
*
$s .= Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) . "\n";
$s .= Html::hidden( 'action', 'historysubmit' ) . "\n";
- $s .= '<div>' . $this->submitButton( $this->msg( 'compareselectedversions' )->text(),
- array( 'class' => 'historysubmit' ) ) . "\n";
-
+ // Button container stored in $this->buttons for re-use in getEndBody()
$this->buttons = '<div>';
$this->buttons .= $this->submitButton( $this->msg( 'compareselectedversions' )->text(),
- array( 'class' => 'historysubmit' )
+ array( 'class' => 'historysubmit mw-history-compareselectedversions-button' )
+ Linker::tooltipAndAccesskeyAttribs( 'compareselectedversions' )
) . "\n";
if ( $this->getUser()->isAllowed( 'deleterevision' ) ) {
- $s .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' );
+ $this->buttons .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' );
}
$this->buttons .= '</div>';
- $s .= '</div><ul id="pagehistory">' . "\n";
+
+ $s .= $this->buttons;
+ $s .= '<ul id="pagehistory">' . "\n";
return $s;
}
'type' => 'submit',
'name' => $name,
'value' => '1',
- 'class' => "mw-history-$name-button",
+ 'class' => "historysubmit mw-history-$name-button",
),
$this->msg( $msg )->text()
) . "\n";
- $this->buttons .= $element;
return $element;
}
* @todo document some more, and maybe clean up the code (some params redundant?)
*
* @param $row Object: the database row corresponding to the previous line.
- * @param $next Mixed: the database row corresponding to the next line.
+ * @param $next Mixed: the database row corresponding to the next line. (chronologically previous)
* @param $notificationtimestamp
* @param $latest Boolean: whether this row corresponds to the page's latest revision.
* @param $firstInList Boolean: whether this row corresponds to the first displayed on this history page.
$rev = new Revision( $row );
$rev->setTitle( $this->getTitle() );
+ if ( is_object( $next ) ) {
+ $prevRev = new Revision( $next );
+ $prevRev->setTitle( $this->getTitle() );
+ } else {
+ $prevRev = null;
+ }
+
$curlink = $this->curLink( $rev, $latest );
$lastlink = $this->lastLink( $rev, $next );
$diffButtons = $this->diffButtons( $rev, $firstInList );
$histLinks = Html::rawElement(
'span',
array( 'class' => 'mw-history-histlinks' ),
- '(' . $curlink . $this->historyPage->message['pipe-separator'] . $lastlink . ') '
+ $this->msg( 'parentheses' )->rawParams( $curlink . $this->historyPage->message['pipe-separator'] . $lastlink )->escaped()
);
$s = $histLinks . $diffButtons;
$s .= " $del ";
}
- $lang = $this->getLang();
+ $lang = $this->getLanguage();
$dirmark = $lang->getDirMark();
$s .= " $link";
$s .= ' ' . ChangesList::flag( 'minor' );
}
- if ( !is_null( $size = $rev->getSize() ) && !$rev->isDeleted( Revision::DELETED_TEXT ) ) {
- $s .= ' ' . Linker::formatRevisionSize( $size );
- }
+ # Size is always public data
+ $prevSize = isset( $this->parentLens[$row->rev_parent_id] )
+ ? $this->parentLens[$row->rev_parent_id]
+ : 0;
+ $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() );
+ $fSize = Linker::formatRevisionSize($rev->getSize());
+ $s .= " . . $fSize $sDiff";
- $s .= Linker::revComment( $rev, false, true );
+ # Text following the character difference is added just before running hooks
+ $s2 = Linker::revComment( $rev, false, true );
if ( $notificationtimestamp && ( $row->rev_timestamp >= $notificationtimestamp ) ) {
- $s .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>';
+ $s2 .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>';
}
$tools = array();
# Rollback and undo links
- if ( !is_null( $next ) && is_object( $next ) &&
+ if ( $prevRev &&
!count( $this->getTitle()->getUserPermissionsErrors( 'edit', $this->getUser() ) ) )
{
if ( $latest && !count( $this->getTitle()->getUserPermissionsErrors( 'rollback', $this->getUser() ) ) ) {
}
if ( !$rev->isDeleted( Revision::DELETED_TEXT )
- && !$next->rev_deleted & Revision::DELETED_TEXT )
+ && !$prevRev->isDeleted( Revision::DELETED_TEXT ) )
{
# Create undo tooltip for the first (=latest) line only
$undoTooltip = $latest
$this->msg( 'editundo' )->escaped(),
$undoTooltip,
array(
- 'action' => 'edit',
- 'undoafter' => $next->rev_id,
- 'undo' => $rev->getId()
+ 'action' => 'edit',
+ 'undoafter' => $prevRev->getId(),
+ 'undo' => $rev->getId()
)
);
$tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>";
}
if ( $tools ) {
- $s .= ' (' . $lang->pipeList( $tools ) . ')';
+ $s2 .= ' '. $this->msg( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped();
}
# Tags
list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'history' );
$classes = array_merge( $classes, $newClasses );
- $s .= " $tagSummary";
+ if ( $tagSummary !== '' ) {
+ $s2 .= " $tagSummary";
+ }
+
+ # Include separator between character difference and following text
+ if ( $s2 !== '' ) {
+ $s .= " . . $s2";
+ }
wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row , &$s, &$classes ) );
* @return String
*/
function revLink( $rev ) {
- $date = $this->getLang()->userTimeAndDate( $rev->getTimestamp(), $this->getUser() );
+ $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $this->getUser() );
$date = htmlspecialchars( $date );
if ( $rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
$link = Linker::linkKnown(
$cur,
array(),
array(
- 'diff' => $this->getTitle()->getLatestRevID(),
+ 'diff' => $this->getWikiPage()->getLatest(),
'oldid' => $rev->getId()
)
);
/**
* Get the "prevent clickjacking" flag
+ * @return bool
*/
function getPreventClickjacking() {
return $this->preventClickjacking;