MediaWiki
REL1_19
|
00001 <?php 00018 class HistoryAction extends FormlessAction { 00019 const DIR_PREV = 0; 00020 const DIR_NEXT = 1; 00021 00022 public function getName() { 00023 return 'history'; 00024 } 00025 00026 public function requiresWrite() { 00027 return false; 00028 } 00029 00030 public function requiresUnblock() { 00031 return false; 00032 } 00033 00034 protected function getPageTitle() { 00035 return $this->msg( 'history-title', $this->getTitle()->getPrefixedText() )->text(); 00036 } 00037 00038 protected function getDescription() { 00039 // Creation of a subtitle link pointing to [[Special:Log]] 00040 return Linker::linkKnown( 00041 SpecialPage::getTitleFor( 'Log' ), 00042 $this->msg( 'viewpagelogs' )->escaped(), 00043 array(), 00044 array( 'page' => $this->getTitle()->getPrefixedText() ) 00045 ); 00046 } 00047 00052 public function getArticle() { 00053 return $this->page; 00054 } 00055 00060 private function preCacheMessages() { 00061 // Precache various messages 00062 if ( !isset( $this->message ) ) { 00063 $msgs = array( 'cur', 'last', 'pipe-separator' ); 00064 foreach ( $msgs as $msg ) { 00065 $this->message[$msg] = $this->msg( $msg )->escaped(); 00066 } 00067 } 00068 } 00069 00074 function onView() { 00075 global $wgScript, $wgUseFileCache, $wgSquidMaxage; 00076 00077 $out = $this->getOutput(); 00078 $request = $this->getRequest(); 00079 00083 if ( $out->checkLastModified( $this->page->getTouched() ) ) { 00084 return; // Client cache fresh and headers sent, nothing more to do. 00085 } 00086 00087 wfProfileIn( __METHOD__ ); 00088 00089 if ( $request->getFullRequestURL() == $this->getTitle()->getInternalURL( 'action=history' ) ) { 00090 $out->setSquidMaxage( $wgSquidMaxage ); 00091 } 00092 00093 $this->preCacheMessages(); 00094 00095 # Fill in the file cache if not set already 00096 if ( $wgUseFileCache && HTMLFileCache::useFileCache( $this->getContext() ) ) { 00097 $cache = HTMLFileCache::newFromTitle( $this->getTitle(), 'history' ); 00098 if ( !$cache->isCacheGood( /* Assume up to date */ ) ) { 00099 ob_start( array( &$cache, 'saveToFileCache' ) ); 00100 } 00101 } 00102 00103 // Setup page variables. 00104 $out->setFeedAppendQuery( 'action=history' ); 00105 $out->addModules( array( 'mediawiki.legacy.history', 'mediawiki.action.history' ) ); 00106 00107 // Handle atom/RSS feeds. 00108 $feedType = $request->getVal( 'feed' ); 00109 if ( $feedType ) { 00110 wfProfileOut( __METHOD__ ); 00111 return $this->feed( $feedType ); 00112 } 00113 00114 // Fail nicely if article doesn't exist. 00115 if ( !$this->page->exists() ) { 00116 $out->addWikiMsg( 'nohistory' ); 00117 # show deletion/move log if there is an entry 00118 LogEventsList::showLogExtract( 00119 $out, 00120 array( 'delete', 'move' ), 00121 $this->getTitle(), 00122 '', 00123 array( 'lim' => 10, 00124 'conds' => array( "log_action != 'revision'" ), 00125 'showIfEmpty' => false, 00126 'msgKey' => array( 'moveddeleted-notice' ) 00127 ) 00128 ); 00129 wfProfileOut( __METHOD__ ); 00130 return; 00131 } 00132 00136 $year = $request->getInt( 'year' ); 00137 $month = $request->getInt( 'month' ); 00138 $tagFilter = $request->getVal( 'tagfilter' ); 00139 $tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter ); 00140 00144 if ( $request->getBool( 'deleted' ) ) { 00145 $conds = array( "rev_deleted != '0'" ); 00146 } else { 00147 $conds = array(); 00148 } 00149 $checkDeleted = Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(), 00150 'deleted', 'mw-show-deleted-only', $request->getBool( 'deleted' ) ) . "\n"; 00151 00152 // Add the general form 00153 $action = htmlspecialchars( $wgScript ); 00154 $out->addHTML( 00155 "<form action=\"$action\" method=\"get\" id=\"mw-history-searchform\">" . 00156 Xml::fieldset( 00157 $this->msg( 'history-fieldset-title' )->text(), 00158 false, 00159 array( 'id' => 'mw-history-search' ) 00160 ) . 00161 Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n" . 00162 Html::hidden( 'action', 'history' ) . "\n" . 00163 Xml::dateMenu( $year, $month ) . ' ' . 00164 ( $tagSelector ? ( implode( ' ', $tagSelector ) . ' ' ) : '' ) . 00165 $checkDeleted . 00166 Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . "\n" . 00167 '</fieldset></form>' 00168 ); 00169 00170 wfRunHooks( 'PageHistoryBeforeList', array( &$this->page ) ); 00171 00172 // Create and output the list. 00173 $pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds ); 00174 $out->addHTML( 00175 $pager->getNavigationBar() . 00176 $pager->getBody() . 00177 $pager->getNavigationBar() 00178 ); 00179 $out->preventClickjacking( $pager->getPreventClickjacking() ); 00180 00181 wfProfileOut( __METHOD__ ); 00182 } 00183 00194 function fetchRevisions( $limit, $offset, $direction ) { 00195 $dbr = wfGetDB( DB_SLAVE ); 00196 00197 if ( $direction == HistoryPage::DIR_PREV ) { 00198 list( $dirs, $oper ) = array( "ASC", ">=" ); 00199 } else { /* $direction == HistoryPage::DIR_NEXT */ 00200 list( $dirs, $oper ) = array( "DESC", "<=" ); 00201 } 00202 00203 if ( $offset ) { 00204 $offsets = array( "rev_timestamp $oper '$offset'" ); 00205 } else { 00206 $offsets = array(); 00207 } 00208 00209 $page_id = $this->page->getId(); 00210 00211 return $dbr->select( 'revision', 00212 Revision::selectFields(), 00213 array_merge( array( "rev_page=$page_id" ), $offsets ), 00214 __METHOD__, 00215 array( 'ORDER BY' => "rev_timestamp $dirs", 00216 'USE INDEX' => 'page_timestamp', 'LIMIT' => $limit ) 00217 ); 00218 } 00219 00225 function feed( $type ) { 00226 global $wgFeedClasses, $wgFeedLimit; 00227 if ( !FeedUtils::checkFeedOutput( $type ) ) { 00228 return; 00229 } 00230 $request = $this->getRequest(); 00231 00232 $feed = new $wgFeedClasses[$type]( 00233 $this->getTitle()->getPrefixedText() . ' - ' . 00234 wfMsgForContent( 'history-feed-title' ), 00235 wfMsgForContent( 'history-feed-description' ), 00236 $this->getTitle()->getFullUrl( 'action=history' ) 00237 ); 00238 00239 // Get a limit on number of feed entries. Provide a sane default 00240 // of 10 if none is defined (but limit to $wgFeedLimit max) 00241 $limit = $request->getInt( 'limit', 10 ); 00242 if ( $limit > $wgFeedLimit || $limit < 1 ) { 00243 $limit = 10; 00244 } 00245 $items = $this->fetchRevisions( $limit, 0, HistoryPage::DIR_NEXT ); 00246 00247 // Generate feed elements enclosed between header and footer. 00248 $feed->outHeader(); 00249 if ( $items->numRows() ) { 00250 foreach ( $items as $row ) { 00251 $feed->outItem( $this->feedItem( $row ) ); 00252 } 00253 } else { 00254 $feed->outItem( $this->feedEmpty() ); 00255 } 00256 $feed->outFooter(); 00257 } 00258 00259 function feedEmpty() { 00260 return new FeedItem( 00261 wfMsgForContent( 'nohistory' ), 00262 $this->getOutput()->parse( wfMsgForContent( 'history-feed-empty' ) ), 00263 $this->getTitle()->getFullUrl(), 00264 wfTimestamp( TS_MW ), 00265 '', 00266 $this->getTitle()->getTalkPage()->getFullUrl() 00267 ); 00268 } 00269 00278 function feedItem( $row ) { 00279 $rev = new Revision( $row ); 00280 $rev->setTitle( $this->getTitle() ); 00281 $text = FeedUtils::formatDiffRow( 00282 $this->getTitle(), 00283 $this->getTitle()->getPreviousRevisionID( $rev->getId() ), 00284 $rev->getId(), 00285 $rev->getTimestamp(), 00286 $rev->getComment() 00287 ); 00288 if ( $rev->getComment() == '' ) { 00289 global $wgContLang; 00290 $title = wfMsgForContent( 'history-feed-item-nocomment', 00291 $rev->getUserText(), 00292 $wgContLang->timeanddate( $rev->getTimestamp() ), 00293 $wgContLang->date( $rev->getTimestamp() ), 00294 $wgContLang->time( $rev->getTimestamp() ) 00295 ); 00296 } else { 00297 $title = $rev->getUserText() . 00298 wfMsgForContent( 'colon-separator' ) . 00299 FeedItem::stripComment( $rev->getComment() ); 00300 } 00301 return new FeedItem( 00302 $title, 00303 $text, 00304 $this->getTitle()->getFullUrl( 'diff=' . $rev->getId() . '&oldid=prev' ), 00305 $rev->getTimestamp(), 00306 $rev->getUserText(), 00307 $this->getTitle()->getTalkPage()->getFullUrl() 00308 ); 00309 } 00310 } 00311 00315 class HistoryPager extends ReverseChronologicalPager { 00316 public $lastRow = false, $counter, $historyPage, $buttons, $conds; 00317 protected $oldIdChecked; 00318 protected $preventClickjacking = false; 00319 00320 function __construct( $historyPage, $year = '', $month = '', $tagFilter = '', $conds = array() ) { 00321 parent::__construct( $historyPage->getContext() ); 00322 $this->historyPage = $historyPage; 00323 $this->tagFilter = $tagFilter; 00324 $this->getDateCond( $year, $month ); 00325 $this->conds = $conds; 00326 } 00327 00328 // For hook compatibility... 00329 function getArticle() { 00330 return $this->historyPage->getArticle(); 00331 } 00332 00333 function getSqlComment() { 00334 if ( $this->conds ) { 00335 return 'history page filtered'; // potentially slow, see CR r58153 00336 } else { 00337 return 'history page unfiltered'; 00338 } 00339 } 00340 00341 function getQueryInfo() { 00342 $queryInfo = array( 00343 'tables' => array( 'revision', 'user' ), 00344 'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ), 00345 'conds' => array_merge( 00346 array( 'rev_page' => $this->getWikiPage()->getId() ), 00347 $this->conds ), 00348 'options' => array( 'USE INDEX' => array( 'revision' => 'page_timestamp' ) ), 00349 'join_conds' => array( 00350 'user' => Revision::userJoinCond(), 00351 'tag_summary' => array( 'LEFT JOIN', 'ts_rev_id=rev_id' ) ), 00352 ); 00353 ChangeTags::modifyDisplayQuery( 00354 $queryInfo['tables'], 00355 $queryInfo['fields'], 00356 $queryInfo['conds'], 00357 $queryInfo['join_conds'], 00358 $queryInfo['options'], 00359 $this->tagFilter 00360 ); 00361 wfRunHooks( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) ); 00362 return $queryInfo; 00363 } 00364 00365 function getIndexField() { 00366 return 'rev_timestamp'; 00367 } 00368 00369 function formatRow( $row ) { 00370 if ( $this->lastRow ) { 00371 $latest = ( $this->counter == 1 && $this->mIsFirst ); 00372 $firstInList = $this->counter == 1; 00373 $this->counter++; 00374 $s = $this->historyLine( $this->lastRow, $row, 00375 $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); 00376 } else { 00377 $s = ''; 00378 } 00379 $this->lastRow = $row; 00380 return $s; 00381 } 00382 00383 function doBatchLookups() { 00384 # Do a link batch query 00385 $this->mResult->seek( 0 ); 00386 $batch = new LinkBatch(); 00387 foreach ( $this->mResult as $row ) { 00388 if( !is_null( $row->user_name ) ) { 00389 $batch->add( NS_USER, $row->user_name ); 00390 $batch->add( NS_USER_TALK, $row->user_name ); 00391 } else { # for anons or usernames of imported revisions 00392 $batch->add( NS_USER, $row->rev_user_text ); 00393 $batch->add( NS_USER_TALK, $row->rev_user_text ); 00394 } 00395 } 00396 $batch->execute(); 00397 $this->mResult->seek( 0 ); 00398 } 00399 00405 function getStartBody() { 00406 global $wgScript; 00407 $this->lastRow = false; 00408 $this->counter = 1; 00409 $this->oldIdChecked = 0; 00410 00411 $this->getOutput()->wrapWikiMsg( "<div class='mw-history-legend'>\n$1\n</div>", 'histlegend' ); 00412 $s = Html::openElement( 'form', array( 'action' => $wgScript, 00413 'id' => 'mw-history-compare' ) ) . "\n"; 00414 $s .= Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) . "\n"; 00415 $s .= Html::hidden( 'action', 'historysubmit' ) . "\n"; 00416 00417 // Button container stored in $this->buttons for re-use in getEndBody() 00418 $this->buttons = '<div>'; 00419 $this->buttons .= $this->submitButton( $this->msg( 'compareselectedversions' )->text(), 00420 array( 'class' => 'historysubmit mw-history-compareselectedversions-button' ) 00421 + Linker::tooltipAndAccesskeyAttribs( 'compareselectedversions' ) 00422 ) . "\n"; 00423 00424 if ( $this->getUser()->isAllowed( 'deleterevision' ) ) { 00425 $this->buttons .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' ); 00426 } 00427 $this->buttons .= '</div>'; 00428 00429 $s .= $this->buttons; 00430 $s .= '<ul id="pagehistory">' . "\n"; 00431 return $s; 00432 } 00433 00434 private function getRevisionButton( $name, $msg ) { 00435 $this->preventClickjacking(); 00436 # Note bug #20966, <button> is non-standard in IE<8 00437 $element = Html::element( 'button', 00438 array( 00439 'type' => 'submit', 00440 'name' => $name, 00441 'value' => '1', 00442 'class' => "historysubmit mw-history-$name-button", 00443 ), 00444 $this->msg( $msg )->text() 00445 ) . "\n"; 00446 return $element; 00447 } 00448 00449 function getEndBody() { 00450 if ( $this->lastRow ) { 00451 $latest = $this->counter == 1 && $this->mIsFirst; 00452 $firstInList = $this->counter == 1; 00453 if ( $this->mIsBackwards ) { 00454 # Next row is unknown, but for UI reasons, probably exists if an offset has been specified 00455 if ( $this->mOffset == '' ) { 00456 $next = null; 00457 } else { 00458 $next = 'unknown'; 00459 } 00460 } else { 00461 # The next row is the past-the-end row 00462 $next = $this->mPastTheEndRow; 00463 } 00464 $this->counter++; 00465 $s = $this->historyLine( $this->lastRow, $next, 00466 $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); 00467 } else { 00468 $s = ''; 00469 } 00470 $s .= "</ul>\n"; 00471 # Add second buttons only if there is more than one rev 00472 if ( $this->getNumRows() > 2 ) { 00473 $s .= $this->buttons; 00474 } 00475 $s .= '</form>'; 00476 return $s; 00477 } 00478 00486 function submitButton( $message, $attributes = array() ) { 00487 # Disable submit button if history has 1 revision only 00488 if ( $this->getNumRows() > 1 ) { 00489 return Xml::submitButton( $message , $attributes ); 00490 } else { 00491 return ''; 00492 } 00493 } 00494 00507 function historyLine( $row, $next, $notificationtimestamp = false, 00508 $latest = false, $firstInList = false ) 00509 { 00510 $rev = new Revision( $row ); 00511 $rev->setTitle( $this->getTitle() ); 00512 00513 if ( is_object( $next ) ) { 00514 $prevRev = new Revision( $next ); 00515 $prevRev->setTitle( $this->getTitle() ); 00516 } else { 00517 $prevRev = null; 00518 } 00519 00520 $curlink = $this->curLink( $rev, $latest ); 00521 $lastlink = $this->lastLink( $rev, $next ); 00522 $diffButtons = $this->diffButtons( $rev, $firstInList ); 00523 $histLinks = Html::rawElement( 00524 'span', 00525 array( 'class' => 'mw-history-histlinks' ), 00526 '(' . $curlink . $this->historyPage->message['pipe-separator'] . $lastlink . ') ' 00527 ); 00528 $s = $histLinks . $diffButtons; 00529 00530 $link = $this->revLink( $rev ); 00531 $classes = array(); 00532 00533 $del = ''; 00534 $user = $this->getUser(); 00535 // Show checkboxes for each revision 00536 if ( $user->isAllowed( 'deleterevision' ) ) { 00537 $this->preventClickjacking(); 00538 // If revision was hidden from sysops, disable the checkbox 00539 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { 00540 $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) ); 00541 // Otherwise, enable the checkbox... 00542 } else { 00543 $del = Xml::check( 'showhiderevisions', false, 00544 array( 'name' => 'ids[' . $rev->getId() . ']' ) ); 00545 } 00546 // User can only view deleted revisions... 00547 } elseif ( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) { 00548 // If revision was hidden from sysops, disable the link 00549 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { 00550 $cdel = Linker::revDeleteLinkDisabled( false ); 00551 // Otherwise, show the link... 00552 } else { 00553 $query = array( 'type' => 'revision', 00554 'target' => $this->getTitle()->getPrefixedDbkey(), 'ids' => $rev->getId() ); 00555 $del .= Linker::revDeleteLink( $query, 00556 $rev->isDeleted( Revision::DELETED_RESTRICTED ), false ); 00557 } 00558 } 00559 if ( $del ) { 00560 $s .= " $del "; 00561 } 00562 00563 $lang = $this->getLanguage(); 00564 $dirmark = $lang->getDirMark(); 00565 00566 $s .= " $link"; 00567 $s .= $dirmark; 00568 $s .= " <span class='history-user'>" . 00569 Linker::revUserTools( $rev, true ) . "</span>"; 00570 $s .= $dirmark; 00571 00572 if ( $rev->isMinor() ) { 00573 $s .= ' ' . ChangesList::flag( 'minor' ); 00574 } 00575 00576 # Size is always public data 00577 $prevSize = $prevRev ? $prevRev->getSize() : 0; 00578 $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() ); 00579 $s .= ' . . ' . $sDiff . ' . . '; 00580 00581 $s .= Linker::revComment( $rev, false, true ); 00582 00583 if ( $notificationtimestamp && ( $row->rev_timestamp >= $notificationtimestamp ) ) { 00584 $s .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>'; 00585 } 00586 00587 $tools = array(); 00588 00589 # Rollback and undo links 00590 if ( $prevRev && 00591 !count( $this->getTitle()->getUserPermissionsErrors( 'edit', $this->getUser() ) ) ) 00592 { 00593 if ( $latest && !count( $this->getTitle()->getUserPermissionsErrors( 'rollback', $this->getUser() ) ) ) { 00594 $this->preventClickjacking(); 00595 $tools[] = '<span class="mw-rollback-link">' . 00596 Linker::buildRollbackLink( $rev ) . '</span>'; 00597 } 00598 00599 if ( !$rev->isDeleted( Revision::DELETED_TEXT ) 00600 && !$prevRev->isDeleted( Revision::DELETED_TEXT ) ) 00601 { 00602 # Create undo tooltip for the first (=latest) line only 00603 $undoTooltip = $latest 00604 ? array( 'title' => $this->msg( 'tooltip-undo' )->text() ) 00605 : array(); 00606 $undolink = Linker::linkKnown( 00607 $this->getTitle(), 00608 $this->msg( 'editundo' )->escaped(), 00609 $undoTooltip, 00610 array( 00611 'action' => 'edit', 00612 'undoafter' => $prevRev->getId(), 00613 'undo' => $rev->getId() 00614 ) 00615 ); 00616 $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>"; 00617 } 00618 } 00619 00620 if ( $tools ) { 00621 $s .= ' (' . $lang->pipeList( $tools ) . ')'; 00622 } 00623 00624 # Tags 00625 list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'history' ); 00626 $classes = array_merge( $classes, $newClasses ); 00627 $s .= " $tagSummary"; 00628 00629 wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row , &$s, &$classes ) ); 00630 00631 $attribs = array(); 00632 if ( $classes ) { 00633 $attribs['class'] = implode( ' ', $classes ); 00634 } 00635 00636 return Xml::tags( 'li', $attribs, $s ) . "\n"; 00637 } 00638 00645 function revLink( $rev ) { 00646 $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $this->getUser() ); 00647 $date = htmlspecialchars( $date ); 00648 if ( $rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00649 $link = Linker::linkKnown( 00650 $this->getTitle(), 00651 $date, 00652 array(), 00653 array( 'oldid' => $rev->getId() ) 00654 ); 00655 } else { 00656 $link = $date; 00657 } 00658 if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { 00659 $link = "<span class=\"history-deleted\">$link</span>"; 00660 } 00661 return $link; 00662 } 00663 00671 function curLink( $rev, $latest ) { 00672 $cur = $this->historyPage->message['cur']; 00673 if ( $latest || !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00674 return $cur; 00675 } else { 00676 return Linker::linkKnown( 00677 $this->getTitle(), 00678 $cur, 00679 array(), 00680 array( 00681 'diff' => $this->getWikiPage()->getLatest(), 00682 'oldid' => $rev->getId() 00683 ) 00684 ); 00685 } 00686 } 00687 00695 function lastLink( $prevRev, $next ) { 00696 $last = $this->historyPage->message['last']; 00697 # $next may either be a Row, null, or "unkown" 00698 $nextRev = is_object( $next ) ? new Revision( $next ) : $next; 00699 if ( is_null( $next ) ) { 00700 # Probably no next row 00701 return $last; 00702 } elseif ( $next === 'unknown' ) { 00703 # Next row probably exists but is unknown, use an oldid=prev link 00704 return Linker::linkKnown( 00705 $this->getTitle(), 00706 $last, 00707 array(), 00708 array( 00709 'diff' => $prevRev->getId(), 00710 'oldid' => 'prev' 00711 ) 00712 ); 00713 } elseif ( !$prevRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) 00714 || !$nextRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) 00715 { 00716 return $last; 00717 } else { 00718 return Linker::linkKnown( 00719 $this->getTitle(), 00720 $last, 00721 array(), 00722 array( 00723 'diff' => $prevRev->getId(), 00724 'oldid' => $next->rev_id 00725 ) 00726 ); 00727 } 00728 } 00729 00738 function diffButtons( $rev, $firstInList ) { 00739 if ( $this->getNumRows() > 1 ) { 00740 $id = $rev->getId(); 00741 $radio = array( 'type' => 'radio', 'value' => $id ); 00743 if ( $firstInList ) { 00744 $first = Xml::element( 'input', 00745 array_merge( $radio, array( 00746 'style' => 'visibility:hidden', 00747 'name' => 'oldid', 00748 'id' => 'mw-oldid-null' ) ) 00749 ); 00750 $checkmark = array( 'checked' => 'checked' ); 00751 } else { 00752 # Check visibility of old revisions 00753 if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { 00754 $radio['disabled'] = 'disabled'; 00755 $checkmark = array(); // We will check the next possible one 00756 } elseif ( !$this->oldIdChecked ) { 00757 $checkmark = array( 'checked' => 'checked' ); 00758 $this->oldIdChecked = $id; 00759 } else { 00760 $checkmark = array(); 00761 } 00762 $first = Xml::element( 'input', 00763 array_merge( $radio, $checkmark, array( 00764 'name' => 'oldid', 00765 'id' => "mw-oldid-$id" ) ) ); 00766 $checkmark = array(); 00767 } 00768 $second = Xml::element( 'input', 00769 array_merge( $radio, $checkmark, array( 00770 'name' => 'diff', 00771 'id' => "mw-diff-$id" ) ) ); 00772 return $first . $second; 00773 } else { 00774 return ''; 00775 } 00776 } 00777 00781 function preventClickjacking( $enable = true ) { 00782 $this->preventClickjacking = $enable; 00783 } 00784 00788 function getPreventClickjacking() { 00789 return $this->preventClickjacking; 00790 } 00791 } 00792 00796 class HistoryPage extends HistoryAction { 00797 public function __construct( Page $article ) { # Just to make it public 00798 parent::__construct( $article ); 00799 } 00800 00801 public function history() { 00802 $this->onView(); 00803 } 00804 }