MediaWiki
REL1_20
|
00001 <?php 00034 class HistoryAction extends FormlessAction { 00035 const DIR_PREV = 0; 00036 const DIR_NEXT = 1; 00037 00038 public function getName() { 00039 return 'history'; 00040 } 00041 00042 public function requiresWrite() { 00043 return false; 00044 } 00045 00046 public function requiresUnblock() { 00047 return false; 00048 } 00049 00050 protected function getPageTitle() { 00051 return $this->msg( 'history-title', $this->getTitle()->getPrefixedText() )->text(); 00052 } 00053 00054 protected function getDescription() { 00055 // Creation of a subtitle link pointing to [[Special:Log]] 00056 return Linker::linkKnown( 00057 SpecialPage::getTitleFor( 'Log' ), 00058 $this->msg( 'viewpagelogs' )->escaped(), 00059 array(), 00060 array( 'page' => $this->getTitle()->getPrefixedText() ) 00061 ); 00062 } 00063 00068 public function getArticle() { 00069 return $this->page; 00070 } 00071 00076 private function preCacheMessages() { 00077 // Precache various messages 00078 if ( !isset( $this->message ) ) { 00079 $msgs = array( 'cur', 'last', 'pipe-separator' ); 00080 foreach ( $msgs as $msg ) { 00081 $this->message[$msg] = $this->msg( $msg )->escaped(); 00082 } 00083 } 00084 } 00085 00089 function onView() { 00090 global $wgScript, $wgUseFileCache; 00091 00092 $out = $this->getOutput(); 00093 $request = $this->getRequest(); 00094 00098 if ( $out->checkLastModified( $this->page->getTouched() ) ) { 00099 return; // Client cache fresh and headers sent, nothing more to do. 00100 } 00101 00102 wfProfileIn( __METHOD__ ); 00103 00104 $this->preCacheMessages(); 00105 00106 # Fill in the file cache if not set already 00107 if ( $wgUseFileCache && HTMLFileCache::useFileCache( $this->getContext() ) ) { 00108 $cache = HTMLFileCache::newFromTitle( $this->getTitle(), 'history' ); 00109 if ( !$cache->isCacheGood( /* Assume up to date */ ) ) { 00110 ob_start( array( &$cache, 'saveToFileCache' ) ); 00111 } 00112 } 00113 00114 // Setup page variables. 00115 $out->setFeedAppendQuery( 'action=history' ); 00116 $out->addModules( array( 'mediawiki.legacy.history', 'mediawiki.action.history' ) ); 00117 00118 // Handle atom/RSS feeds. 00119 $feedType = $request->getVal( 'feed' ); 00120 if ( $feedType ) { 00121 $this->feed( $feedType ); 00122 wfProfileOut( __METHOD__ ); 00123 return; 00124 } 00125 00126 // Fail nicely if article doesn't exist. 00127 if ( !$this->page->exists() ) { 00128 $out->addWikiMsg( 'nohistory' ); 00129 # show deletion/move log if there is an entry 00130 LogEventsList::showLogExtract( 00131 $out, 00132 array( 'delete', 'move' ), 00133 $this->getTitle(), 00134 '', 00135 array( 'lim' => 10, 00136 'conds' => array( "log_action != 'revision'" ), 00137 'showIfEmpty' => false, 00138 'msgKey' => array( 'moveddeleted-notice' ) 00139 ) 00140 ); 00141 wfProfileOut( __METHOD__ ); 00142 return; 00143 } 00144 00148 $year = $request->getInt( 'year' ); 00149 $month = $request->getInt( 'month' ); 00150 $tagFilter = $request->getVal( 'tagfilter' ); 00151 $tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter ); 00152 00156 if ( $request->getBool( 'deleted' ) ) { 00157 $conds = array( "rev_deleted != '0'" ); 00158 } else { 00159 $conds = array(); 00160 } 00161 $checkDeleted = Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(), 00162 'deleted', 'mw-show-deleted-only', $request->getBool( 'deleted' ) ) . "\n"; 00163 00164 // Add the general form 00165 $action = htmlspecialchars( $wgScript ); 00166 $out->addHTML( 00167 "<form action=\"$action\" method=\"get\" id=\"mw-history-searchform\">" . 00168 Xml::fieldset( 00169 $this->msg( 'history-fieldset-title' )->text(), 00170 false, 00171 array( 'id' => 'mw-history-search' ) 00172 ) . 00173 Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n" . 00174 Html::hidden( 'action', 'history' ) . "\n" . 00175 Xml::dateMenu( $year, $month ) . ' ' . 00176 ( $tagSelector ? ( implode( ' ', $tagSelector ) . ' ' ) : '' ) . 00177 $checkDeleted . 00178 Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . "\n" . 00179 '</fieldset></form>' 00180 ); 00181 00182 wfRunHooks( 'PageHistoryBeforeList', array( &$this->page ) ); 00183 00184 // Create and output the list. 00185 $pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds ); 00186 $out->addHTML( 00187 $pager->getNavigationBar() . 00188 $pager->getBody() . 00189 $pager->getNavigationBar() 00190 ); 00191 $out->preventClickjacking( $pager->getPreventClickjacking() ); 00192 00193 wfProfileOut( __METHOD__ ); 00194 } 00195 00206 function fetchRevisions( $limit, $offset, $direction ) { 00207 // Fail if article doesn't exist. 00208 if( !$this->getTitle()->exists() ) { 00209 return new FakeResultWrapper( array() ); 00210 } 00211 00212 $dbr = wfGetDB( DB_SLAVE ); 00213 00214 if ( $direction == HistoryPage::DIR_PREV ) { 00215 list( $dirs, $oper ) = array( "ASC", ">=" ); 00216 } else { /* $direction == HistoryPage::DIR_NEXT */ 00217 list( $dirs, $oper ) = array( "DESC", "<=" ); 00218 } 00219 00220 if ( $offset ) { 00221 $offsets = array( "rev_timestamp $oper '$offset'" ); 00222 } else { 00223 $offsets = array(); 00224 } 00225 00226 $page_id = $this->page->getId(); 00227 00228 return $dbr->select( 'revision', 00229 Revision::selectFields(), 00230 array_merge( array( "rev_page=$page_id" ), $offsets ), 00231 __METHOD__, 00232 array( 'ORDER BY' => "rev_timestamp $dirs", 00233 'USE INDEX' => 'page_timestamp', 'LIMIT' => $limit ) 00234 ); 00235 } 00236 00242 function feed( $type ) { 00243 global $wgFeedClasses, $wgFeedLimit; 00244 if ( !FeedUtils::checkFeedOutput( $type ) ) { 00245 return; 00246 } 00247 $request = $this->getRequest(); 00248 00249 $feed = new $wgFeedClasses[$type]( 00250 $this->getTitle()->getPrefixedText() . ' - ' . 00251 $this->msg( 'history-feed-title' )->inContentLanguage()->text(), 00252 $this->msg( 'history-feed-description' )->inContentLanguage()->text(), 00253 $this->getTitle()->getFullUrl( 'action=history' ) 00254 ); 00255 00256 // Get a limit on number of feed entries. Provide a sane default 00257 // of 10 if none is defined (but limit to $wgFeedLimit max) 00258 $limit = $request->getInt( 'limit', 10 ); 00259 if ( $limit > $wgFeedLimit || $limit < 1 ) { 00260 $limit = 10; 00261 } 00262 $items = $this->fetchRevisions( $limit, 0, HistoryPage::DIR_NEXT ); 00263 00264 // Generate feed elements enclosed between header and footer. 00265 $feed->outHeader(); 00266 if ( $items->numRows() ) { 00267 foreach ( $items as $row ) { 00268 $feed->outItem( $this->feedItem( $row ) ); 00269 } 00270 } else { 00271 $feed->outItem( $this->feedEmpty() ); 00272 } 00273 $feed->outFooter(); 00274 } 00275 00276 function feedEmpty() { 00277 return new FeedItem( 00278 $this->msg( 'nohistory' )->inContentLanguage()->text(), 00279 $this->msg( 'history-feed-empty' )->inContentLanguage()->parseAsBlock(), 00280 $this->getTitle()->getFullUrl(), 00281 wfTimestamp( TS_MW ), 00282 '', 00283 $this->getTitle()->getTalkPage()->getFullUrl() 00284 ); 00285 } 00286 00295 function feedItem( $row ) { 00296 $rev = new Revision( $row ); 00297 $rev->setTitle( $this->getTitle() ); 00298 $text = FeedUtils::formatDiffRow( 00299 $this->getTitle(), 00300 $this->getTitle()->getPreviousRevisionID( $rev->getId() ), 00301 $rev->getId(), 00302 $rev->getTimestamp(), 00303 $rev->getComment() 00304 ); 00305 if ( $rev->getComment() == '' ) { 00306 global $wgContLang; 00307 $title = $this->msg( 'history-feed-item-nocomment', 00308 $rev->getUserText(), 00309 $wgContLang->timeanddate( $rev->getTimestamp() ), 00310 $wgContLang->date( $rev->getTimestamp() ), 00311 $wgContLang->time( $rev->getTimestamp() ) )->inContentLanguage()->text(); 00312 } else { 00313 $title = $rev->getUserText() . 00314 $this->msg( 'colon-separator' )->inContentLanguage()->text() . 00315 FeedItem::stripComment( $rev->getComment() ); 00316 } 00317 return new FeedItem( 00318 $title, 00319 $text, 00320 $this->getTitle()->getFullUrl( 'diff=' . $rev->getId() . '&oldid=prev' ), 00321 $rev->getTimestamp(), 00322 $rev->getUserText(), 00323 $this->getTitle()->getTalkPage()->getFullUrl() 00324 ); 00325 } 00326 } 00327 00331 class HistoryPager extends ReverseChronologicalPager { 00332 public $lastRow = false, $counter, $historyPage, $buttons, $conds; 00333 protected $oldIdChecked; 00334 protected $preventClickjacking = false; 00338 protected $parentLens; 00339 00340 function __construct( $historyPage, $year = '', $month = '', $tagFilter = '', $conds = array() ) { 00341 parent::__construct( $historyPage->getContext() ); 00342 $this->historyPage = $historyPage; 00343 $this->tagFilter = $tagFilter; 00344 $this->getDateCond( $year, $month ); 00345 $this->conds = $conds; 00346 } 00347 00348 // For hook compatibility... 00349 function getArticle() { 00350 return $this->historyPage->getArticle(); 00351 } 00352 00353 function getSqlComment() { 00354 if ( $this->conds ) { 00355 return 'history page filtered'; // potentially slow, see CR r58153 00356 } else { 00357 return 'history page unfiltered'; 00358 } 00359 } 00360 00361 function getQueryInfo() { 00362 $queryInfo = array( 00363 'tables' => array( 'revision', 'user' ), 00364 'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ), 00365 'conds' => array_merge( 00366 array( 'rev_page' => $this->getWikiPage()->getId() ), 00367 $this->conds ), 00368 'options' => array( 'USE INDEX' => array( 'revision' => 'page_timestamp' ) ), 00369 'join_conds' => array( 00370 'user' => Revision::userJoinCond(), 00371 'tag_summary' => array( 'LEFT JOIN', 'ts_rev_id=rev_id' ) ), 00372 ); 00373 ChangeTags::modifyDisplayQuery( 00374 $queryInfo['tables'], 00375 $queryInfo['fields'], 00376 $queryInfo['conds'], 00377 $queryInfo['join_conds'], 00378 $queryInfo['options'], 00379 $this->tagFilter 00380 ); 00381 wfRunHooks( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) ); 00382 return $queryInfo; 00383 } 00384 00385 function getIndexField() { 00386 return 'rev_timestamp'; 00387 } 00388 00389 function formatRow( $row ) { 00390 if ( $this->lastRow ) { 00391 $latest = ( $this->counter == 1 && $this->mIsFirst ); 00392 $firstInList = $this->counter == 1; 00393 $this->counter++; 00394 $s = $this->historyLine( $this->lastRow, $row, 00395 $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); 00396 } else { 00397 $s = ''; 00398 } 00399 $this->lastRow = $row; 00400 return $s; 00401 } 00402 00403 function doBatchLookups() { 00404 # Do a link batch query 00405 $this->mResult->seek( 0 ); 00406 $batch = new LinkBatch(); 00407 $revIds = array(); 00408 foreach ( $this->mResult as $row ) { 00409 if( $row->rev_parent_id ) { 00410 $revIds[] = $row->rev_parent_id; 00411 } 00412 if( !is_null( $row->user_name ) ) { 00413 $batch->add( NS_USER, $row->user_name ); 00414 $batch->add( NS_USER_TALK, $row->user_name ); 00415 } else { # for anons or usernames of imported revisions 00416 $batch->add( NS_USER, $row->rev_user_text ); 00417 $batch->add( NS_USER_TALK, $row->rev_user_text ); 00418 } 00419 } 00420 $this->parentLens = Revision::getParentLengths( $this->mDb, $revIds ); 00421 $batch->execute(); 00422 $this->mResult->seek( 0 ); 00423 } 00424 00430 function getStartBody() { 00431 global $wgScript; 00432 $this->lastRow = false; 00433 $this->counter = 1; 00434 $this->oldIdChecked = 0; 00435 00436 $this->getOutput()->wrapWikiMsg( "<div class='mw-history-legend'>\n$1\n</div>", 'histlegend' ); 00437 $s = Html::openElement( 'form', array( 'action' => $wgScript, 00438 'id' => 'mw-history-compare' ) ) . "\n"; 00439 $s .= Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) . "\n"; 00440 $s .= Html::hidden( 'action', 'historysubmit' ) . "\n"; 00441 00442 // Button container stored in $this->buttons for re-use in getEndBody() 00443 $this->buttons = '<div>'; 00444 $this->buttons .= $this->submitButton( $this->msg( 'compareselectedversions' )->text(), 00445 array( 'class' => 'historysubmit mw-history-compareselectedversions-button' ) 00446 + Linker::tooltipAndAccesskeyAttribs( 'compareselectedversions' ) 00447 ) . "\n"; 00448 00449 if ( $this->getUser()->isAllowed( 'deleterevision' ) ) { 00450 $this->buttons .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' ); 00451 } 00452 $this->buttons .= '</div>'; 00453 00454 $s .= $this->buttons; 00455 $s .= '<ul id="pagehistory">' . "\n"; 00456 return $s; 00457 } 00458 00459 private function getRevisionButton( $name, $msg ) { 00460 $this->preventClickjacking(); 00461 # Note bug #20966, <button> is non-standard in IE<8 00462 $element = Html::element( 'button', 00463 array( 00464 'type' => 'submit', 00465 'name' => $name, 00466 'value' => '1', 00467 'class' => "historysubmit mw-history-$name-button", 00468 ), 00469 $this->msg( $msg )->text() 00470 ) . "\n"; 00471 return $element; 00472 } 00473 00474 function getEndBody() { 00475 if ( $this->lastRow ) { 00476 $latest = $this->counter == 1 && $this->mIsFirst; 00477 $firstInList = $this->counter == 1; 00478 if ( $this->mIsBackwards ) { 00479 # Next row is unknown, but for UI reasons, probably exists if an offset has been specified 00480 if ( $this->mOffset == '' ) { 00481 $next = null; 00482 } else { 00483 $next = 'unknown'; 00484 } 00485 } else { 00486 # The next row is the past-the-end row 00487 $next = $this->mPastTheEndRow; 00488 } 00489 $this->counter++; 00490 $s = $this->historyLine( $this->lastRow, $next, 00491 $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); 00492 } else { 00493 $s = ''; 00494 } 00495 $s .= "</ul>\n"; 00496 # Add second buttons only if there is more than one rev 00497 if ( $this->getNumRows() > 2 ) { 00498 $s .= $this->buttons; 00499 } 00500 $s .= '</form>'; 00501 return $s; 00502 } 00503 00511 function submitButton( $message, $attributes = array() ) { 00512 # Disable submit button if history has 1 revision only 00513 if ( $this->getNumRows() > 1 ) { 00514 return Xml::submitButton( $message , $attributes ); 00515 } else { 00516 return ''; 00517 } 00518 } 00519 00532 function historyLine( $row, $next, $notificationtimestamp = false, 00533 $latest = false, $firstInList = false ) 00534 { 00535 $rev = new Revision( $row ); 00536 $rev->setTitle( $this->getTitle() ); 00537 00538 if ( is_object( $next ) ) { 00539 $prevRev = new Revision( $next ); 00540 $prevRev->setTitle( $this->getTitle() ); 00541 } else { 00542 $prevRev = null; 00543 } 00544 00545 $curlink = $this->curLink( $rev, $latest ); 00546 $lastlink = $this->lastLink( $rev, $next ); 00547 $diffButtons = $this->diffButtons( $rev, $firstInList ); 00548 $histLinks = Html::rawElement( 00549 'span', 00550 array( 'class' => 'mw-history-histlinks' ), 00551 $this->msg( 'parentheses' )->rawParams( $curlink . $this->historyPage->message['pipe-separator'] . $lastlink )->escaped() 00552 ); 00553 $s = $histLinks . $diffButtons; 00554 00555 $link = $this->revLink( $rev ); 00556 $classes = array(); 00557 00558 $del = ''; 00559 $user = $this->getUser(); 00560 // Show checkboxes for each revision 00561 if ( $user->isAllowed( 'deleterevision' ) ) { 00562 $this->preventClickjacking(); 00563 // If revision was hidden from sysops, disable the checkbox 00564 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { 00565 $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) ); 00566 // Otherwise, enable the checkbox... 00567 } else { 00568 $del = Xml::check( 'showhiderevisions', false, 00569 array( 'name' => 'ids[' . $rev->getId() . ']' ) ); 00570 } 00571 // User can only view deleted revisions... 00572 } elseif ( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) { 00573 // If revision was hidden from sysops, disable the link 00574 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { 00575 $cdel = Linker::revDeleteLinkDisabled( false ); 00576 // Otherwise, show the link... 00577 } else { 00578 $query = array( 'type' => 'revision', 00579 'target' => $this->getTitle()->getPrefixedDbkey(), 'ids' => $rev->getId() ); 00580 $del .= Linker::revDeleteLink( $query, 00581 $rev->isDeleted( Revision::DELETED_RESTRICTED ), false ); 00582 } 00583 } 00584 if ( $del ) { 00585 $s .= " $del "; 00586 } 00587 00588 $lang = $this->getLanguage(); 00589 $dirmark = $lang->getDirMark(); 00590 00591 $s .= " $link"; 00592 $s .= $dirmark; 00593 $s .= " <span class='history-user'>" . 00594 Linker::revUserTools( $rev, true ) . "</span>"; 00595 $s .= $dirmark; 00596 00597 if ( $rev->isMinor() ) { 00598 $s .= ' ' . ChangesList::flag( 'minor' ); 00599 } 00600 00601 # Size is always public data 00602 $prevSize = isset( $this->parentLens[$row->rev_parent_id] ) 00603 ? $this->parentLens[$row->rev_parent_id] 00604 : 0; 00605 $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() ); 00606 $fSize = Linker::formatRevisionSize($rev->getSize()); 00607 $s .= ' <span class="mw-changeslist-separator">. .</span> ' . "$fSize $sDiff"; 00608 00609 # Text following the character difference is added just before running hooks 00610 $s2 = Linker::revComment( $rev, false, true ); 00611 00612 if ( $notificationtimestamp && ( $row->rev_timestamp >= $notificationtimestamp ) ) { 00613 $s2 .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>'; 00614 $classes[] = 'mw-history-line-updated'; 00615 } 00616 00617 $tools = array(); 00618 00619 # Rollback and undo links 00620 if ( $prevRev && $this->getTitle()->quickUserCan( 'edit', $user ) ) { 00621 if ( $latest && $this->getTitle()->quickUserCan( 'rollback', $user ) ) { 00622 $this->preventClickjacking(); 00623 $tools[] = '<span class="mw-rollback-link">' . 00624 Linker::buildRollbackLink( $rev, $this->getContext() ) . '</span>'; 00625 } 00626 00627 if ( !$rev->isDeleted( Revision::DELETED_TEXT ) 00628 && !$prevRev->isDeleted( Revision::DELETED_TEXT ) ) 00629 { 00630 # Create undo tooltip for the first (=latest) line only 00631 $undoTooltip = $latest 00632 ? array( 'title' => $this->msg( 'tooltip-undo' )->text() ) 00633 : array(); 00634 $undolink = Linker::linkKnown( 00635 $this->getTitle(), 00636 $this->msg( 'editundo' )->escaped(), 00637 $undoTooltip, 00638 array( 00639 'action' => 'edit', 00640 'undoafter' => $prevRev->getId(), 00641 'undo' => $rev->getId() 00642 ) 00643 ); 00644 $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>"; 00645 } 00646 } 00647 00648 if ( $tools ) { 00649 $s2 .= ' '. $this->msg( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped(); 00650 } 00651 00652 # Tags 00653 list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'history' ); 00654 $classes = array_merge( $classes, $newClasses ); 00655 if ( $tagSummary !== '' ) { 00656 $s2 .= " $tagSummary"; 00657 } 00658 00659 # Include separator between character difference and following text 00660 if ( $s2 !== '' ) { 00661 $s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2; 00662 } 00663 00664 wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row , &$s, &$classes ) ); 00665 00666 $attribs = array(); 00667 if ( $classes ) { 00668 $attribs['class'] = implode( ' ', $classes ); 00669 } 00670 00671 return Xml::tags( 'li', $attribs, $s ) . "\n"; 00672 } 00673 00680 function revLink( $rev ) { 00681 $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $this->getUser() ); 00682 $date = htmlspecialchars( $date ); 00683 if ( $rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00684 $link = Linker::linkKnown( 00685 $this->getTitle(), 00686 $date, 00687 array( 'class' => 'mw-changeslist-date' ), 00688 array( 'oldid' => $rev->getId() ) 00689 ); 00690 } else { 00691 $link = $date; 00692 } 00693 if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { 00694 $link = "<span class=\"history-deleted\">$link</span>"; 00695 } 00696 return $link; 00697 } 00698 00706 function curLink( $rev, $latest ) { 00707 $cur = $this->historyPage->message['cur']; 00708 if ( $latest || !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00709 return $cur; 00710 } else { 00711 return Linker::linkKnown( 00712 $this->getTitle(), 00713 $cur, 00714 array(), 00715 array( 00716 'diff' => $this->getWikiPage()->getLatest(), 00717 'oldid' => $rev->getId() 00718 ) 00719 ); 00720 } 00721 } 00722 00730 function lastLink( $prevRev, $next ) { 00731 $last = $this->historyPage->message['last']; 00732 # $next may either be a Row, null, or "unkown" 00733 $nextRev = is_object( $next ) ? new Revision( $next ) : $next; 00734 if ( is_null( $next ) ) { 00735 # Probably no next row 00736 return $last; 00737 } elseif ( $next === 'unknown' ) { 00738 # Next row probably exists but is unknown, use an oldid=prev link 00739 return Linker::linkKnown( 00740 $this->getTitle(), 00741 $last, 00742 array(), 00743 array( 00744 'diff' => $prevRev->getId(), 00745 'oldid' => 'prev' 00746 ) 00747 ); 00748 } elseif ( !$prevRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) 00749 || !$nextRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) 00750 { 00751 return $last; 00752 } else { 00753 return Linker::linkKnown( 00754 $this->getTitle(), 00755 $last, 00756 array(), 00757 array( 00758 'diff' => $prevRev->getId(), 00759 'oldid' => $next->rev_id 00760 ) 00761 ); 00762 } 00763 } 00764 00773 function diffButtons( $rev, $firstInList ) { 00774 if ( $this->getNumRows() > 1 ) { 00775 $id = $rev->getId(); 00776 $radio = array( 'type' => 'radio', 'value' => $id ); 00778 if ( $firstInList ) { 00779 $first = Xml::element( 'input', 00780 array_merge( $radio, array( 00781 'style' => 'visibility:hidden', 00782 'name' => 'oldid', 00783 'id' => 'mw-oldid-null' ) ) 00784 ); 00785 $checkmark = array( 'checked' => 'checked' ); 00786 } else { 00787 # Check visibility of old revisions 00788 if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00789 $radio['disabled'] = 'disabled'; 00790 $checkmark = array(); // We will check the next possible one 00791 } elseif ( !$this->oldIdChecked ) { 00792 $checkmark = array( 'checked' => 'checked' ); 00793 $this->oldIdChecked = $id; 00794 } else { 00795 $checkmark = array(); 00796 } 00797 $first = Xml::element( 'input', 00798 array_merge( $radio, $checkmark, array( 00799 'name' => 'oldid', 00800 'id' => "mw-oldid-$id" ) ) ); 00801 $checkmark = array(); 00802 } 00803 $second = Xml::element( 'input', 00804 array_merge( $radio, $checkmark, array( 00805 'name' => 'diff', 00806 'id' => "mw-diff-$id" ) ) ); 00807 return $first . $second; 00808 } else { 00809 return ''; 00810 } 00811 } 00812 00816 function preventClickjacking( $enable = true ) { 00817 $this->preventClickjacking = $enable; 00818 } 00819 00824 function getPreventClickjacking() { 00825 return $this->preventClickjacking; 00826 } 00827 } 00828 00832 class HistoryPage extends HistoryAction { 00833 public function __construct( Page $article ) { # Just to make it public 00834 parent::__construct( $article ); 00835 } 00836 00837 public function history() { 00838 $this->onView(); 00839 } 00840 }