diff options
Diffstat (limited to 'includes/PageHistory.php')
-rw-r--r-- | includes/PageHistory.php | 258 |
1 files changed, 138 insertions, 120 deletions
diff --git a/includes/PageHistory.php b/includes/PageHistory.php index 0c44682e..870b57b7 100644 --- a/includes/PageHistory.php +++ b/includes/PageHistory.php @@ -3,6 +3,7 @@ * Page history * * Split off from Article.php and Skin.php, 2003-12-22 + * @file */ /** @@ -17,7 +18,7 @@ class PageHistory { const DIR_PREV = 0; const DIR_NEXT = 1; - + var $mArticle, $mTitle, $mSkin; var $lastdate; var $linesonpage; @@ -37,6 +38,28 @@ class PageHistory { $this->mTitle =& $article->mTitle; $this->mNotificationTimestamp = NULL; $this->mSkin = $wgUser->getSkin(); + $this->preCacheMessages(); + } + + function getArticle() { + return $this->mArticle; + } + + function getTitle() { + return $this->mTitle; + } + + /** + * As we use the same small set of messages in various methods and that + * they are called often, we call them once and save them in $this->message + */ + function preCacheMessages() { + // Precache various messages + if( !isset( $this->message ) ) { + foreach( explode(' ', 'cur last rev-delundel' ) as $msg ) { + $this->message[$msg] = wfMsgExt( $msg, array( 'escape') ); + } + } } /** @@ -51,12 +74,11 @@ class PageHistory { * Allow client caching. */ - if( $wgOut->checkLastModified( $this->mArticle->getTimestamp() ) ) + if( $wgOut->checkLastModified( $this->mArticle->getTouched() ) ) /* Client cache fresh and headers sent, nothing more to do. */ return; - $fname = 'PageHistory::history'; - wfProfileIn( $fname ); + wfProfileIn( __METHOD__ ); /* * Setup page variables. @@ -68,6 +90,7 @@ class PageHistory { $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->setSyndicated( true ); $wgOut->setFeedAppendQuery( 'action=history' ); + $wgOut->addScriptFile( 'history.js' ); $logPage = SpecialPage::getTitleFor( 'Log' ); $logLink = $this->mSkin->makeKnownLinkObj( $logPage, wfMsgHtml( 'viewpagelogs' ), 'page=' . $this->mTitle->getPrefixedUrl() ); @@ -75,7 +98,7 @@ class PageHistory { $feedType = $wgRequest->getVal( 'feed' ); if( $feedType ) { - wfProfileOut( $fname ); + wfProfileOut( __METHOD__ ); return $this->feed( $feedType ); } @@ -84,7 +107,7 @@ class PageHistory { */ if( !$this->mTitle->exists() ) { $wgOut->addWikiMsg( 'nohistory' ); - wfProfileOut( $fname ); + wfProfileOut( __METHOD__ ); return; } @@ -94,25 +117,29 @@ class PageHistory { */ if ( $wgRequest->getText("go") == 'first' ) { $limit = $wgRequest->getInt( 'limit', 50 ); + global $wgFeedLimit; + if( $limit > $wgFeedLimit ) { + $limit = $wgFeedLimit; + } $wgOut->redirect( $wgTitle->getLocalURL( "action=history&limit={$limit}&dir=prev" ) ); return; } wfRunHooks( 'PageHistoryBeforeList', array( &$this->mArticle ) ); - /** + /** * Do the list */ $pager = new PageHistoryPager( $this ); $this->linesonpage = $pager->getNumRows(); $wgOut->addHTML( - $pager->getNavigationBar() . - $this->beginHistoryList() . + $pager->getNavigationBar() . + $this->beginHistoryList() . $pager->getBody() . $this->endHistoryList() . $pager->getNavigationBar() ); - wfProfileOut( $fname ); + wfProfileOut( __METHOD__ ); } /** @@ -121,25 +148,11 @@ class PageHistory { * @return string HTML output */ function beginHistoryList() { - global $wgTitle; + global $wgTitle, $wgScript; $this->lastdate = ''; $s = wfMsgExt( 'histlegend', array( 'parse') ); - $s .= '<form action="' . $wgTitle->escapeLocalURL( '-' ) . '" method="get">'; - $prefixedkey = htmlspecialchars($wgTitle->getPrefixedDbKey()); - - // The following line is SUPPOSED to have double-quotes around the - // $prefixedkey variable, because htmlspecialchars() doesn't escape - // single-quotes. - // - // On at least two occasions people have changed it to single-quotes, - // which creates invalid HTML and incorrect display of the resulting - // link. - // - // Please do not break this a third time. Thank you for your kind - // consideration and cooperation. - // - $s .= "<input type='hidden' name='title' value=\"{$prefixedkey}\" />\n"; - + $s .= Xml::openElement( 'form', array( 'action' => $wgScript ) ); + $s .= Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() ); $s .= $this->submitButton(); $s .= '<ul id="pagehistory">' . "\n"; return $s; @@ -183,8 +196,8 @@ class PageHistory { * * @todo document some more, and maybe clean up the code (some params redundant?) * - * @param object $row The database row corresponding to the line (or is it the previous line?). - * @param object $next The database row corresponding to the next line (or is it this one?). + * @param Row $row The database row corresponding to the previous line. + * @param mixed $next The database row corresponding to the next line. * @param int $counter Apparently a counter of what row number we're at, counted from the top row = 1. * @param $notificationtimestamp * @param bool $latest Whether this row corresponds to the page's latest revision. @@ -196,71 +209,57 @@ class PageHistory { $rev = new Revision( $row ); $rev->setTitle( $this->mTitle ); - $s = '<li>'; + $s = ''; $curlink = $this->curLink( $rev, $latest ); $lastlink = $this->lastLink( $rev, $next, $counter ); $arbitrary = $this->diffButtons( $rev, $firstInList, $counter ); $link = $this->revLink( $rev ); - - $user = $this->mSkin->userLink( $rev->getUser(), $rev->getUserText() ) - . $this->mSkin->userToolLinks( $rev->getUser(), $rev->getUserText() ); - + $s .= "($curlink) ($lastlink) $arbitrary"; - + if( $wgUser->isAllowed( 'deleterevision' ) ) { $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); if( $firstInList ) { - // We don't currently handle well changing the top revision's settings - $del = wfMsgHtml( 'rev-delundel' ); + // We don't currently handle well changing the top revision's settings + $del = $this->message['rev-delundel']; } else if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) { // If revision was hidden from sysops - $del = wfMsgHtml( 'rev-delundel' ); + $del = $this->message['rev-delundel']; } else { $del = $this->mSkin->makeKnownLinkObj( $revdel, - wfMsg( 'rev-delundel' ), + $this->message['rev-delundel'], 'target=' . urlencode( $this->mTitle->getPrefixedDbkey() ) . '&oldid=' . urlencode( $rev->getId() ) ); + // Bolden oversighted content + if( $rev->isDeleted( Revision::DELETED_RESTRICTED ) ) + $del = "<strong>$del</strong>"; } - $s .= " (<small>$del</small>) "; + $s .= " <tt>(<small>$del</small>)</tt> "; } - + $s .= " $link"; - #getUser is safe, but this avoids making the invalid untargeted contribs links - if( $row->rev_deleted & Revision::DELETED_USER ) { - $user = '<span class="history-deleted">' . wfMsg('rev-deleted-user') . '</span>'; - } - $s .= " <span class='history-user'>$user</span>"; + $s .= " <span class='history-user'>" . $this->mSkin->revUserTools( $rev, true ) . "</span>"; if( $row->rev_minor_edit ) { - $s .= ' ' . wfElement( 'span', array( 'class' => 'minor' ), wfMsg( 'minoreditletter') ); + $s .= ' ' . Xml::element( 'span', array( 'class' => 'minor' ), wfMsg( 'minoreditletter') ); } - if ( !is_null( $size = $rev->getSize() ) ) { - if ( $size == 0 ) - $stxt = wfMsgHtml( 'historyempty' ); - else - $stxt = wfMsgExt( 'historysize', array( 'parsemag' ), $wgLang->formatNum( $size ) ); - $s .= " <span class=\"history-size\">$stxt</span>"; + if ( !is_null( $size = $rev->getSize() ) && $rev->userCan( Revision::DELETED_TEXT ) ) { + $s .= ' ' . $this->mSkin->formatRevisionSize( $size ); } - #getComment is safe, but this is better formatted - if( $rev->isDeleted( Revision::DELETED_COMMENT ) ) { - $s .= " <span class=\"history-deleted\"><span class=\"comment\">" . - wfMsgHtml( 'rev-deleted-comment' ) . "</span></span>"; - } else { - $s .= $this->mSkin->revComment( $rev ); - } - + $s .= $this->mSkin->revComment( $rev, false, true ); + if ($notificationtimestamp && ($row->rev_timestamp >= $notificationtimestamp)) { $s .= ' <span class="updatedmarker">' . wfMsgHtml( 'updatedmarker' ) . '</span>'; } #add blurb about text having been deleted - if( $row->rev_deleted & Revision::DELETED_TEXT ) { - $s .= ' ' . wfMsgHtml( 'deletedrev' ); + if( $rev->isDeleted( Revision::DELETED_TEXT ) ) { + $s .= ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>'; } - + $tools = array(); - + if ( !is_null( $next ) && is_object( $next ) ) { if( !$this->mTitle->getUserPermissionsErrors( 'rollback', $wgUser ) && !$this->mTitle->getUserPermissionsErrors( 'edit', $wgUser ) @@ -270,7 +269,9 @@ class PageHistory { . '</span>'; } - if( $this->mTitle->quickUserCan( 'edit' ) ) { + if( $this->mTitle->quickUserCan( 'edit' ) && + !$rev->isDeleted( Revision::DELETED_TEXT ) && + !$next->rev_deleted & Revision::DELETED_TEXT ) { $undolink = $this->mSkin->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'editundo' ), @@ -279,19 +280,21 @@ class PageHistory { $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>"; } } - + if( $tools ) { $s .= ' (' . implode( ' | ', $tools ) . ')'; } - - wfRunHooks( 'PageHistoryLineEnding', array( &$row , &$s ) ); - - $s .= "</li>\n"; - return $s; + wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row , &$s ) ); + + return "<li>$s</li>\n"; } - - /** @todo document */ + + /** + * Create a link to view this revision of the page + * @param Revision $rev + * @returns string + */ function revLink( $rev ) { global $wgLang; $date = $wgLang->timeanddate( wfTimestamp(TS_MW, $rev->getTimestamp()), true ); @@ -307,9 +310,14 @@ class PageHistory { return $link; } - /** @todo document */ + /** + * Create a diff-to-current link for this revision for this page + * @param Revision $rev + * @param Bool $latest, this is the latest revision of the page? + * @returns string + */ function curLink( $rev, $latest ) { - $cur = wfMsgExt( 'cur', array( 'escape') ); + $cur = $this->message['cur']; if( $latest || !$rev->userCan( Revision::DELETED_TEXT ) ) { return $cur; } else { @@ -320,25 +328,33 @@ class PageHistory { } } - /** @todo document */ - function lastLink( $rev, $next, $counter ) { - $last = wfMsgExt( 'last', array( 'escape' ) ); - if ( is_null( $next ) ) { + /** + * Create a diff-to-previous link for this revision for this page. + * @param Revision $prevRev, the previous revision + * @param mixed $next, the newer revision + * @param int $counter, what row on the history list this is + * @returns string + */ + function lastLink( $prevRev, $next, $counter ) { + $last = $this->message['last']; + # $next may either be a Row, null, or "unkown" + $nextRev = is_object($next) ? new Revision( $next ) : $next; + if( is_null($next) ) { # Probably no next row return $last; - } elseif ( $next === 'unknown' ) { + } elseif( $next === 'unknown' ) { # Next row probably exists but is unknown, use an oldid=prev link return $this->mSkin->makeKnownLinkObj( $this->mTitle, $last, - "diff=" . $rev->getId() . "&oldid=prev" ); - } elseif( !$rev->userCan( Revision::DELETED_TEXT ) ) { + "diff=" . $prevRev->getId() . "&oldid=prev" ); + } elseif( !$prevRev->userCan(Revision::DELETED_TEXT) || !$nextRev->userCan(Revision::DELETED_TEXT) ) { return $last; } else { return $this->mSkin->makeKnownLinkObj( $this->mTitle, $last, - "diff=" . $rev->getId() . "&oldid={$next->rev_id}" + "diff=" . $prevRev->getId() . "&oldid={$next->rev_id}" /*, '', '', @@ -399,23 +415,21 @@ class PageHistory { function getLatestId() { if( is_null( $this->mLatestId ) ) { $id = $this->mTitle->getArticleID(); - $db = wfGetDB(DB_SLAVE); + $db = wfGetDB( DB_SLAVE ); $this->mLatestId = $db->selectField( 'page', "page_latest", array( 'page_id' => $id ), - 'PageHistory::getLatestID' ); + __METHOD__ ); } return $this->mLatestId; } /** * Fetch an array of revisions, specified by a given limit, offset and - * direction. This is now only used by the feeds. It was previously + * direction. This is now only used by the feeds. It was previously * used by the main UI but that's now handled by the pager. */ function fetchRevisions($limit, $offset, $direction) { - $fname = 'PageHistory::fetchRevisions'; - $dbr = wfGetDB( DB_SLAVE ); if ($direction == PageHistory::DIR_PREV) @@ -434,7 +448,7 @@ class PageHistory { 'revision', Revision::selectFields(), array_merge(array("rev_page=$page_id"), $offsets), - $fname, + __METHOD__, array('ORDER BY' => "rev_timestamp $dirs", 'USE INDEX' => 'page_timestamp', 'LIMIT' => $limit) ); @@ -449,7 +463,6 @@ class PageHistory { /** @todo document */ function getNotificationTimestamp() { global $wgUser, $wgShowUpdatedMarker; - $fname = 'PageHistory::getNotficationTimestamp'; if ($this->mNotificationTimestamp !== NULL) return $this->mNotificationTimestamp; @@ -464,10 +477,10 @@ class PageHistory { 'wl_notificationtimestamp', array( 'wl_namespace' => $this->mTitle->getNamespace(), 'wl_title' => $this->mTitle->getDBkey(), - 'wl_user' => $wgUser->getID() + 'wl_user' => $wgUser->getId() ), - $fname); - + __METHOD__ ); + // Don't use the special value reserved for telling whether the field is filled if ( is_null( $this->mNotificationTimestamp ) ) { $this->mNotificationTimestamp = false; @@ -475,28 +488,31 @@ class PageHistory { return $this->mNotificationTimestamp; } - + /** * Output a subscription feed listing recent edits to this page. * @param string $type */ function feed( $type ) { - require_once 'SpecialRecentchanges.php'; - - global $wgFeedClasses; - if( !isset( $wgFeedClasses[$type] ) ) { - global $wgOut; - $wgOut->addWikiMsg( 'feed-invalid' ); + global $wgFeedClasses, $wgRequest, $wgFeedLimit; + if ( !FeedUtils::checkFeedOutput($type) ) { return; } - + $feed = new $wgFeedClasses[$type]( $this->mTitle->getPrefixedText() . ' - ' . wfMsgForContent( 'history-feed-title' ), wfMsgForContent( 'history-feed-description' ), $this->mTitle->getFullUrl( 'action=history' ) ); - $items = $this->fetchRevisions(10, 0, PageHistory::DIR_NEXT); + // Get a limit on number of feed entries. Provide a sane default + // of 10 if none is defined (but limit to $wgFeedLimit max) + $limit = $wgRequest->getInt( 'limit', 10 ); + if( $limit > $wgFeedLimit || $limit < 1 ) { + $limit = 10; + } + $items = $this->fetchRevisions($limit, 0, PageHistory::DIR_NEXT); + $feed->outHeader(); if( $items ) { foreach( $items as $row ) { @@ -507,7 +523,7 @@ class PageHistory { } $feed->outFooter(); } - + function feedEmpty() { global $wgOut; return new FeedItem( @@ -518,7 +534,7 @@ class PageHistory { '', $this->mTitle->getTalkPage()->getFullUrl() ); } - + /** * Generate a FeedItem object from a given revision table row * Borrows Recent Changes' feed generation functions for formatting; @@ -530,12 +546,12 @@ class PageHistory { function feedItem( $row ) { $rev = new Revision( $row ); $rev->setTitle( $this->mTitle ); - $text = rcFormatDiffRow( $this->mTitle, + $text = FeedUtils::formatDiffRow( $this->mTitle, $this->mTitle->getPreviousRevisionID( $rev->getId() ), $rev->getId(), $rev->getTimestamp(), $rev->getComment() ); - + if( $rev->getComment() == '' ) { global $wgContLang; $title = wfMsgForContent( 'history-feed-item-nocomment', @@ -553,7 +569,7 @@ class PageHistory { $rev->getUserText(), $this->mTitle->getTalkPage()->getFullUrl() ); } - + /** * Quickie hack... strip out wikilinks to more legible form from the comment. */ @@ -564,23 +580,25 @@ class PageHistory { /** - * @addtogroup Pager + * @ingroup Pager */ class PageHistoryPager extends ReverseChronologicalPager { public $mLastRow = false, $mPageHistory; - + function __construct( $pageHistory ) { parent::__construct(); $this->mPageHistory = $pageHistory; } function getQueryInfo() { - return array( - 'tables' => 'revision', - 'fields' => Revision::selectFields(), - 'conds' => array('rev_page' => $this->mPageHistory->mTitle->getArticleID() ), - 'options' => array( 'USE INDEX' => 'page_timestamp' ) + $queryInfo = array( + 'tables' => array('revision'), + 'fields' => Revision::selectFields(), + 'conds' => array('rev_page' => $this->mPageHistory->mTitle->getArticleID() ), + 'options' => array( 'USE INDEX' => array('revision' => 'page_timestamp') ) ); + wfRunHooks( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) ); + return $queryInfo; } function getIndexField() { @@ -589,9 +607,9 @@ class PageHistoryPager extends ReverseChronologicalPager { function formatRow( $row ) { if ( $this->mLastRow ) { - $latest = $this->mCounter == 1 && $this->mOffset == ''; + $latest = $this->mCounter == 1 && $this->mIsFirst; $firstInList = $this->mCounter == 1; - $s = $this->mPageHistory->historyLine( $this->mLastRow, $row, $this->mCounter++, + $s = $this->mPageHistory->historyLine( $this->mLastRow, $row, $this->mCounter++, $this->mPageHistory->getNotificationTimestamp(), $latest, $firstInList ); } else { $s = ''; @@ -599,7 +617,7 @@ class PageHistoryPager extends ReverseChronologicalPager { $this->mLastRow = $row; return $s; } - + function getStartBody() { $this->mLastRow = false; $this->mCounter = 1; @@ -608,7 +626,7 @@ class PageHistoryPager extends ReverseChronologicalPager { function getEndBody() { if ( $this->mLastRow ) { - $latest = $this->mCounter == 1 && $this->mOffset == 0; + $latest = $this->mCounter == 1 && $this->mIsFirst; $firstInList = $this->mCounter == 1; if ( $this->mIsBackwards ) { # Next row is unknown, but for UI reasons, probably exists if an offset has been specified @@ -621,7 +639,7 @@ class PageHistoryPager extends ReverseChronologicalPager { # The next row is the past-the-end row $next = $this->mPastTheEndRow; } - $s = $this->mPageHistory->historyLine( $this->mLastRow, $next, $this->mCounter++, + $s = $this->mPageHistory->historyLine( $this->mLastRow, $next, $this->mCounter++, $this->mPageHistory->getNotificationTimestamp(), $latest, $firstInList ); } else { $s = ''; |