MediaWiki
REL1_24
|
00001 <?php 00036 class HistoryAction extends FormlessAction { 00037 const DIR_PREV = 0; 00038 const DIR_NEXT = 1; 00039 00041 public $message; 00042 00043 public function getName() { 00044 return 'history'; 00045 } 00046 00047 public function requiresWrite() { 00048 return false; 00049 } 00050 00051 public function requiresUnblock() { 00052 return false; 00053 } 00054 00055 protected function getPageTitle() { 00056 return $this->msg( 'history-title', $this->getTitle()->getPrefixedText() )->text(); 00057 } 00058 00059 protected function getDescription() { 00060 // Creation of a subtitle link pointing to [[Special:Log]] 00061 return Linker::linkKnown( 00062 SpecialPage::getTitleFor( 'Log' ), 00063 $this->msg( 'viewpagelogs' )->escaped(), 00064 array(), 00065 array( 'page' => $this->getTitle()->getPrefixedText() ) 00066 ); 00067 } 00068 00073 public function getArticle() { 00074 return $this->page; 00075 } 00076 00081 private function preCacheMessages() { 00082 // Precache various messages 00083 if ( !isset( $this->message ) ) { 00084 $msgs = array( 'cur', 'last', 'pipe-separator' ); 00085 foreach ( $msgs as $msg ) { 00086 $this->message[$msg] = $this->msg( $msg )->escaped(); 00087 } 00088 } 00089 } 00090 00094 function onView() { 00095 $out = $this->getOutput(); 00096 $request = $this->getRequest(); 00097 00101 if ( $out->checkLastModified( $this->page->getTouched() ) ) { 00102 return; // Client cache fresh and headers sent, nothing more to do. 00103 } 00104 00105 wfProfileIn( __METHOD__ ); 00106 00107 $this->preCacheMessages(); 00108 $config = $this->context->getConfig(); 00109 00110 # Fill in the file cache if not set already 00111 $useFileCache = $config->get( 'UseFileCache' ); 00112 if ( $useFileCache && HTMLFileCache::useFileCache( $this->getContext() ) ) { 00113 $cache = new HTMLFileCache( $this->getTitle(), 'history' ); 00114 if ( !$cache->isCacheGood( /* Assume up to date */ ) ) { 00115 ob_start( array( &$cache, 'saveToFileCache' ) ); 00116 } 00117 } 00118 00119 // Setup page variables. 00120 $out->setFeedAppendQuery( 'action=history' ); 00121 $out->addModules( 'mediawiki.action.history' ); 00122 if ( $config->get( 'UseMediaWikiUIEverywhere' ) ) { 00123 $out = $this->getOutput(); 00124 $out->addModuleStyles( array( 00125 'mediawiki.ui.input', 00126 'mediawiki.ui.checkbox', 00127 ) ); 00128 } 00129 00130 // Handle atom/RSS feeds. 00131 $feedType = $request->getVal( 'feed' ); 00132 if ( $feedType ) { 00133 $this->feed( $feedType ); 00134 wfProfileOut( __METHOD__ ); 00135 00136 return; 00137 } 00138 00139 // Fail nicely if article doesn't exist. 00140 if ( !$this->page->exists() ) { 00141 $out->addWikiMsg( 'nohistory' ); 00142 # show deletion/move log if there is an entry 00143 LogEventsList::showLogExtract( 00144 $out, 00145 array( 'delete', 'move' ), 00146 $this->getTitle(), 00147 '', 00148 array( 'lim' => 10, 00149 'conds' => array( "log_action != 'revision'" ), 00150 'showIfEmpty' => false, 00151 'msgKey' => array( 'moveddeleted-notice' ) 00152 ) 00153 ); 00154 wfProfileOut( __METHOD__ ); 00155 00156 return; 00157 } 00158 00162 $year = $request->getInt( 'year' ); 00163 $month = $request->getInt( 'month' ); 00164 $tagFilter = $request->getVal( 'tagfilter' ); 00165 $tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter ); 00166 00170 if ( $request->getBool( 'deleted' ) ) { 00171 $conds = array( 'rev_deleted != 0' ); 00172 } else { 00173 $conds = array(); 00174 } 00175 if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) { 00176 $checkDeleted = Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(), 00177 'deleted', 'mw-show-deleted-only', $request->getBool( 'deleted' ) ) . "\n"; 00178 } else { 00179 $checkDeleted = ''; 00180 } 00181 00182 // Add the general form 00183 $action = htmlspecialchars( wfScript() ); 00184 $out->addHTML( 00185 "<form action=\"$action\" method=\"get\" id=\"mw-history-searchform\">" . 00186 Xml::fieldset( 00187 $this->msg( 'history-fieldset-title' )->text(), 00188 false, 00189 array( 'id' => 'mw-history-search' ) 00190 ) . 00191 Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n" . 00192 Html::hidden( 'action', 'history' ) . "\n" . 00193 Xml::dateMenu( 00194 ( $year == null ? MWTimestamp::getLocalInstance()->format( 'Y' ) : $year ), 00195 $month 00196 ) . ' ' . 00197 ( $tagSelector ? ( implode( ' ', $tagSelector ) . ' ' ) : '' ) . 00198 $checkDeleted . 00199 Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . "\n" . 00200 '</fieldset></form>' 00201 ); 00202 00203 wfRunHooks( 'PageHistoryBeforeList', array( &$this->page, $this->getContext() ) ); 00204 00205 // Create and output the list. 00206 $pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds ); 00207 $out->addHTML( 00208 $pager->getNavigationBar() . 00209 $pager->getBody() . 00210 $pager->getNavigationBar() 00211 ); 00212 $out->preventClickjacking( $pager->getPreventClickjacking() ); 00213 00214 wfProfileOut( __METHOD__ ); 00215 } 00216 00227 function fetchRevisions( $limit, $offset, $direction ) { 00228 // Fail if article doesn't exist. 00229 if ( !$this->getTitle()->exists() ) { 00230 return new FakeResultWrapper( array() ); 00231 } 00232 00233 $dbr = wfGetDB( DB_SLAVE ); 00234 00235 if ( $direction === self::DIR_PREV ) { 00236 list( $dirs, $oper ) = array( "ASC", ">=" ); 00237 } else { /* $direction === self::DIR_NEXT */ 00238 list( $dirs, $oper ) = array( "DESC", "<=" ); 00239 } 00240 00241 if ( $offset ) { 00242 $offsets = array( "rev_timestamp $oper " . $dbr->addQuotes( $dbr->timestamp( $offset ) ) ); 00243 } else { 00244 $offsets = array(); 00245 } 00246 00247 $page_id = $this->page->getId(); 00248 00249 return $dbr->select( 'revision', 00250 Revision::selectFields(), 00251 array_merge( array( 'rev_page' => $page_id ), $offsets ), 00252 __METHOD__, 00253 array( 'ORDER BY' => "rev_timestamp $dirs", 00254 'USE INDEX' => 'page_timestamp', 'LIMIT' => $limit ) 00255 ); 00256 } 00257 00263 function feed( $type ) { 00264 if ( !FeedUtils::checkFeedOutput( $type ) ) { 00265 return; 00266 } 00267 $request = $this->getRequest(); 00268 00269 $feedClasses = $this->context->getConfig()->get( 'FeedClasses' ); 00271 $feed = new $feedClasses[$type]( 00272 $this->getTitle()->getPrefixedText() . ' - ' . 00273 $this->msg( 'history-feed-title' )->inContentLanguage()->text(), 00274 $this->msg( 'history-feed-description' )->inContentLanguage()->text(), 00275 $this->getTitle()->getFullURL( 'action=history' ) 00276 ); 00277 00278 // Get a limit on number of feed entries. Provide a sane default 00279 // of 10 if none is defined (but limit to $wgFeedLimit max) 00280 $limit = $request->getInt( 'limit', 10 ); 00281 $limit = min( 00282 max( $limit, 1 ), 00283 $this->context->getConfig()->get( 'FeedLimit' ) 00284 ); 00285 00286 $items = $this->fetchRevisions( $limit, 0, self::DIR_NEXT ); 00287 00288 // Generate feed elements enclosed between header and footer. 00289 $feed->outHeader(); 00290 if ( $items->numRows() ) { 00291 foreach ( $items as $row ) { 00292 $feed->outItem( $this->feedItem( $row ) ); 00293 } 00294 } else { 00295 $feed->outItem( $this->feedEmpty() ); 00296 } 00297 $feed->outFooter(); 00298 } 00299 00300 function feedEmpty() { 00301 return new FeedItem( 00302 $this->msg( 'nohistory' )->inContentLanguage()->text(), 00303 $this->msg( 'history-feed-empty' )->inContentLanguage()->parseAsBlock(), 00304 $this->getTitle()->getFullURL(), 00305 wfTimestamp( TS_MW ), 00306 '', 00307 $this->getTitle()->getTalkPage()->getFullURL() 00308 ); 00309 } 00310 00319 function feedItem( $row ) { 00320 $rev = new Revision( $row ); 00321 $rev->setTitle( $this->getTitle() ); 00322 $text = FeedUtils::formatDiffRow( 00323 $this->getTitle(), 00324 $this->getTitle()->getPreviousRevisionID( $rev->getId() ), 00325 $rev->getId(), 00326 $rev->getTimestamp(), 00327 $rev->getComment() 00328 ); 00329 if ( $rev->getComment() == '' ) { 00330 global $wgContLang; 00331 $title = $this->msg( 'history-feed-item-nocomment', 00332 $rev->getUserText(), 00333 $wgContLang->timeanddate( $rev->getTimestamp() ), 00334 $wgContLang->date( $rev->getTimestamp() ), 00335 $wgContLang->time( $rev->getTimestamp() ) )->inContentLanguage()->text(); 00336 } else { 00337 $title = $rev->getUserText() . 00338 $this->msg( 'colon-separator' )->inContentLanguage()->text() . 00339 FeedItem::stripComment( $rev->getComment() ); 00340 } 00341 00342 return new FeedItem( 00343 $title, 00344 $text, 00345 $this->getTitle()->getFullURL( 'diff=' . $rev->getId() . '&oldid=prev' ), 00346 $rev->getTimestamp(), 00347 $rev->getUserText(), 00348 $this->getTitle()->getTalkPage()->getFullURL() 00349 ); 00350 } 00351 } 00352 00357 class HistoryPager extends ReverseChronologicalPager { 00361 public $lastRow = false; 00362 00363 public $counter, $historyPage, $buttons, $conds; 00364 00365 protected $oldIdChecked; 00366 00367 protected $preventClickjacking = false; 00371 protected $parentLens; 00372 00380 function __construct( $historyPage, $year = '', $month = '', $tagFilter = '', $conds = array() ) { 00381 parent::__construct( $historyPage->getContext() ); 00382 $this->historyPage = $historyPage; 00383 $this->tagFilter = $tagFilter; 00384 $this->getDateCond( $year, $month ); 00385 $this->conds = $conds; 00386 } 00387 00388 // For hook compatibility... 00389 function getArticle() { 00390 return $this->historyPage->getArticle(); 00391 } 00392 00393 function getSqlComment() { 00394 if ( $this->conds ) { 00395 return 'history page filtered'; // potentially slow, see CR r58153 00396 } else { 00397 return 'history page unfiltered'; 00398 } 00399 } 00400 00401 function getQueryInfo() { 00402 $queryInfo = array( 00403 'tables' => array( 'revision', 'user' ), 00404 'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ), 00405 'conds' => array_merge( 00406 array( 'rev_page' => $this->getWikiPage()->getId() ), 00407 $this->conds ), 00408 'options' => array( 'USE INDEX' => array( 'revision' => 'page_timestamp' ) ), 00409 'join_conds' => array( 'user' => Revision::userJoinCond() ), 00410 ); 00411 ChangeTags::modifyDisplayQuery( 00412 $queryInfo['tables'], 00413 $queryInfo['fields'], 00414 $queryInfo['conds'], 00415 $queryInfo['join_conds'], 00416 $queryInfo['options'], 00417 $this->tagFilter 00418 ); 00419 wfRunHooks( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) ); 00420 00421 return $queryInfo; 00422 } 00423 00424 function getIndexField() { 00425 return 'rev_timestamp'; 00426 } 00427 00432 function formatRow( $row ) { 00433 if ( $this->lastRow ) { 00434 $latest = ( $this->counter == 1 && $this->mIsFirst ); 00435 $firstInList = $this->counter == 1; 00436 $this->counter++; 00437 $s = $this->historyLine( $this->lastRow, $row, 00438 $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); 00439 } else { 00440 $s = ''; 00441 } 00442 $this->lastRow = $row; 00443 00444 return $s; 00445 } 00446 00447 function doBatchLookups() { 00448 # Do a link batch query 00449 $this->mResult->seek( 0 ); 00450 $batch = new LinkBatch(); 00451 $revIds = array(); 00452 foreach ( $this->mResult as $row ) { 00453 if ( $row->rev_parent_id ) { 00454 $revIds[] = $row->rev_parent_id; 00455 } 00456 if ( !is_null( $row->user_name ) ) { 00457 $batch->add( NS_USER, $row->user_name ); 00458 $batch->add( NS_USER_TALK, $row->user_name ); 00459 } else { # for anons or usernames of imported revisions 00460 $batch->add( NS_USER, $row->rev_user_text ); 00461 $batch->add( NS_USER_TALK, $row->rev_user_text ); 00462 } 00463 } 00464 $this->parentLens = Revision::getParentLengths( $this->mDb, $revIds ); 00465 $batch->execute(); 00466 $this->mResult->seek( 0 ); 00467 } 00468 00474 function getStartBody() { 00475 $this->lastRow = false; 00476 $this->counter = 1; 00477 $this->oldIdChecked = 0; 00478 00479 $this->getOutput()->wrapWikiMsg( "<div class='mw-history-legend'>\n$1\n</div>", 'histlegend' ); 00480 $s = Html::openElement( 'form', array( 'action' => wfScript(), 00481 'id' => 'mw-history-compare' ) ) . "\n"; 00482 $s .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n"; 00483 $s .= Html::hidden( 'action', 'historysubmit' ) . "\n"; 00484 00485 // Button container stored in $this->buttons for re-use in getEndBody() 00486 $this->buttons = '<div>'; 00487 $className = 'historysubmit mw-history-compareselectedversions-button'; 00488 if ( $this->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) { 00489 $className .= ' mw-ui-button mw-ui-constructive'; 00490 } 00491 $this->buttons .= $this->submitButton( $this->msg( 'compareselectedversions' )->text(), 00492 array( 'class' => $className ) 00493 + Linker::tooltipAndAccesskeyAttribs( 'compareselectedversions' ) 00494 ) . "\n"; 00495 00496 if ( $this->getUser()->isAllowed( 'deleterevision' ) ) { 00497 $this->buttons .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' ); 00498 } 00499 $this->buttons .= '</div>'; 00500 00501 $s .= $this->buttons; 00502 $s .= '<ul id="pagehistory">' . "\n"; 00503 00504 return $s; 00505 } 00506 00507 private function getRevisionButton( $name, $msg ) { 00508 $this->preventClickjacking(); 00509 # Note bug #20966, <button> is non-standard in IE<8 00510 $element = Html::element( 00511 'button', 00512 array( 00513 'type' => 'submit', 00514 'name' => $name, 00515 'value' => '1', 00516 'class' => "historysubmit mw-history-$name-button", 00517 ), 00518 $this->msg( $msg )->text() 00519 ) . "\n"; 00520 return $element; 00521 } 00522 00523 function getEndBody() { 00524 if ( $this->lastRow ) { 00525 $latest = $this->counter == 1 && $this->mIsFirst; 00526 $firstInList = $this->counter == 1; 00527 if ( $this->mIsBackwards ) { 00528 # Next row is unknown, but for UI reasons, probably exists if an offset has been specified 00529 if ( $this->mOffset == '' ) { 00530 $next = null; 00531 } else { 00532 $next = 'unknown'; 00533 } 00534 } else { 00535 # The next row is the past-the-end row 00536 $next = $this->mPastTheEndRow; 00537 } 00538 $this->counter++; 00539 $s = $this->historyLine( $this->lastRow, $next, 00540 $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); 00541 } else { 00542 $s = ''; 00543 } 00544 $s .= "</ul>\n"; 00545 # Add second buttons only if there is more than one rev 00546 if ( $this->getNumRows() > 2 ) { 00547 $s .= $this->buttons; 00548 } 00549 $s .= '</form>'; 00550 00551 return $s; 00552 } 00553 00561 function submitButton( $message, $attributes = array() ) { 00562 # Disable submit button if history has 1 revision only 00563 if ( $this->getNumRows() > 1 ) { 00564 return Xml::submitButton( $message, $attributes ); 00565 } else { 00566 return ''; 00567 } 00568 } 00569 00584 function historyLine( $row, $next, $notificationtimestamp = false, 00585 $latest = false, $firstInList = false ) { 00586 $rev = new Revision( $row ); 00587 $rev->setTitle( $this->getTitle() ); 00588 00589 if ( is_object( $next ) ) { 00590 $prevRev = new Revision( $next ); 00591 $prevRev->setTitle( $this->getTitle() ); 00592 } else { 00593 $prevRev = null; 00594 } 00595 00596 $curlink = $this->curLink( $rev, $latest ); 00597 $lastlink = $this->lastLink( $rev, $next ); 00598 $curLastlinks = $curlink . $this->historyPage->message['pipe-separator'] . $lastlink; 00599 $histLinks = Html::rawElement( 00600 'span', 00601 array( 'class' => 'mw-history-histlinks' ), 00602 $this->msg( 'parentheses' )->rawParams( $curLastlinks )->escaped() 00603 ); 00604 00605 $diffButtons = $this->diffButtons( $rev, $firstInList ); 00606 $s = $histLinks . $diffButtons; 00607 00608 $link = $this->revLink( $rev ); 00609 $classes = array(); 00610 00611 $del = ''; 00612 $user = $this->getUser(); 00613 // Show checkboxes for each revision 00614 if ( $user->isAllowed( 'deleterevision' ) ) { 00615 $this->preventClickjacking(); 00616 // If revision was hidden from sysops, disable the checkbox 00617 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { 00618 $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) ); 00619 // Otherwise, enable the checkbox... 00620 } else { 00621 $del = Xml::check( 'showhiderevisions', false, 00622 array( 'name' => 'ids[' . $rev->getId() . ']' ) ); 00623 } 00624 // User can only view deleted revisions... 00625 } elseif ( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) { 00626 // If revision was hidden from sysops, disable the link 00627 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { 00628 $del = Linker::revDeleteLinkDisabled( false ); 00629 // Otherwise, show the link... 00630 } else { 00631 $query = array( 'type' => 'revision', 00632 'target' => $this->getTitle()->getPrefixedDBkey(), 'ids' => $rev->getId() ); 00633 $del .= Linker::revDeleteLink( $query, 00634 $rev->isDeleted( Revision::DELETED_RESTRICTED ), false ); 00635 } 00636 } 00637 if ( $del ) { 00638 $s .= " $del "; 00639 } 00640 00641 $lang = $this->getLanguage(); 00642 $dirmark = $lang->getDirMark(); 00643 00644 $s .= " $link"; 00645 $s .= $dirmark; 00646 $s .= " <span class='history-user'>" . 00647 Linker::revUserTools( $rev, true ) . "</span>"; 00648 $s .= $dirmark; 00649 00650 if ( $rev->isMinor() ) { 00651 $s .= ' ' . ChangesList::flag( 'minor' ); 00652 } 00653 00654 # Sometimes rev_len isn't populated 00655 if ( $rev->getSize() !== null ) { 00656 # Size is always public data 00657 $prevSize = isset( $this->parentLens[$row->rev_parent_id] ) 00658 ? $this->parentLens[$row->rev_parent_id] 00659 : 0; 00660 $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() ); 00661 $fSize = Linker::formatRevisionSize( $rev->getSize() ); 00662 $s .= ' <span class="mw-changeslist-separator">. .</span> ' . "$fSize $sDiff"; 00663 } 00664 00665 # Text following the character difference is added just before running hooks 00666 $s2 = Linker::revComment( $rev, false, true ); 00667 00668 if ( $notificationtimestamp && ( $row->rev_timestamp >= $notificationtimestamp ) ) { 00669 $s2 .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>'; 00670 $classes[] = 'mw-history-line-updated'; 00671 } 00672 00673 $tools = array(); 00674 00675 # Rollback and undo links 00676 if ( $prevRev && $this->getTitle()->quickUserCan( 'edit', $user ) ) { 00677 if ( $latest && $this->getTitle()->quickUserCan( 'rollback', $user ) ) { 00678 // Get a rollback link without the brackets 00679 $rollbackLink = Linker::generateRollback( 00680 $rev, 00681 $this->getContext(), 00682 array( 'verify', 'noBrackets' ) 00683 ); 00684 if ( $rollbackLink ) { 00685 $this->preventClickjacking(); 00686 $tools[] = $rollbackLink; 00687 } 00688 } 00689 00690 if ( !$rev->isDeleted( Revision::DELETED_TEXT ) 00691 && !$prevRev->isDeleted( Revision::DELETED_TEXT ) 00692 ) { 00693 # Create undo tooltip for the first (=latest) line only 00694 $undoTooltip = $latest 00695 ? array( 'title' => $this->msg( 'tooltip-undo' )->text() ) 00696 : array(); 00697 $undolink = Linker::linkKnown( 00698 $this->getTitle(), 00699 $this->msg( 'editundo' )->escaped(), 00700 $undoTooltip, 00701 array( 00702 'action' => 'edit', 00703 'undoafter' => $prevRev->getId(), 00704 'undo' => $rev->getId() 00705 ) 00706 ); 00707 $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>"; 00708 } 00709 } 00710 // Allow extension to add their own links here 00711 wfRunHooks( 'HistoryRevisionTools', array( $rev, &$tools ) ); 00712 00713 if ( $tools ) { 00714 $s2 .= ' ' . $this->msg( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped(); 00715 } 00716 00717 # Tags 00718 list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'history' ); 00719 $classes = array_merge( $classes, $newClasses ); 00720 if ( $tagSummary !== '' ) { 00721 $s2 .= " $tagSummary"; 00722 } 00723 00724 # Include separator between character difference and following text 00725 if ( $s2 !== '' ) { 00726 $s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2; 00727 } 00728 00729 wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row, &$s, &$classes ) ); 00730 00731 $attribs = array(); 00732 if ( $classes ) { 00733 $attribs['class'] = implode( ' ', $classes ); 00734 } 00735 00736 return Xml::tags( 'li', $attribs, $s ) . "\n"; 00737 } 00738 00745 function revLink( $rev ) { 00746 $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $this->getUser() ); 00747 $date = htmlspecialchars( $date ); 00748 if ( $rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00749 $link = Linker::linkKnown( 00750 $this->getTitle(), 00751 $date, 00752 array( 'class' => 'mw-changeslist-date' ), 00753 array( 'oldid' => $rev->getId() ) 00754 ); 00755 } else { 00756 $link = $date; 00757 } 00758 if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { 00759 $link = "<span class=\"history-deleted\">$link</span>"; 00760 } 00761 00762 return $link; 00763 } 00764 00772 function curLink( $rev, $latest ) { 00773 $cur = $this->historyPage->message['cur']; 00774 if ( $latest || !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00775 return $cur; 00776 } else { 00777 return Linker::linkKnown( 00778 $this->getTitle(), 00779 $cur, 00780 array(), 00781 array( 00782 'diff' => $this->getWikiPage()->getLatest(), 00783 'oldid' => $rev->getId() 00784 ) 00785 ); 00786 } 00787 } 00788 00798 function lastLink( $prevRev, $next ) { 00799 $last = $this->historyPage->message['last']; 00800 00801 if ( $next === null ) { 00802 # Probably no next row 00803 return $last; 00804 } 00805 00806 if ( $next === 'unknown' ) { 00807 # Next row probably exists but is unknown, use an oldid=prev link 00808 return Linker::linkKnown( 00809 $this->getTitle(), 00810 $last, 00811 array(), 00812 array( 00813 'diff' => $prevRev->getId(), 00814 'oldid' => 'prev' 00815 ) 00816 ); 00817 } 00818 00819 $nextRev = new Revision( $next ); 00820 00821 if ( !$prevRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) 00822 || !$nextRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) 00823 ) { 00824 return $last; 00825 } 00826 00827 return Linker::linkKnown( 00828 $this->getTitle(), 00829 $last, 00830 array(), 00831 array( 00832 'diff' => $prevRev->getId(), 00833 'oldid' => $next->rev_id 00834 ) 00835 ); 00836 } 00837 00846 function diffButtons( $rev, $firstInList ) { 00847 if ( $this->getNumRows() > 1 ) { 00848 $id = $rev->getId(); 00849 $radio = array( 'type' => 'radio', 'value' => $id ); 00851 if ( $firstInList ) { 00852 $first = Xml::element( 'input', 00853 array_merge( $radio, array( 00854 'style' => 'visibility:hidden', 00855 'name' => 'oldid', 00856 'id' => 'mw-oldid-null' ) ) 00857 ); 00858 $checkmark = array( 'checked' => 'checked' ); 00859 } else { 00860 # Check visibility of old revisions 00861 if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00862 $radio['disabled'] = 'disabled'; 00863 $checkmark = array(); // We will check the next possible one 00864 } elseif ( !$this->oldIdChecked ) { 00865 $checkmark = array( 'checked' => 'checked' ); 00866 $this->oldIdChecked = $id; 00867 } else { 00868 $checkmark = array(); 00869 } 00870 $first = Xml::element( 'input', 00871 array_merge( $radio, $checkmark, array( 00872 'name' => 'oldid', 00873 'id' => "mw-oldid-$id" ) ) ); 00874 $checkmark = array(); 00875 } 00876 $second = Xml::element( 'input', 00877 array_merge( $radio, $checkmark, array( 00878 'name' => 'diff', 00879 'id' => "mw-diff-$id" ) ) ); 00880 00881 return $first . $second; 00882 } else { 00883 return ''; 00884 } 00885 } 00886 00891 function preventClickjacking( $enable = true ) { 00892 $this->preventClickjacking = $enable; 00893 } 00894 00899 function getPreventClickjacking() { 00900 return $this->preventClickjacking; 00901 } 00902 }