From 761b880e9815b7e0264e990613819d9758cfd14c Mon Sep 17 00:00:00 2001 From: aude Date: Thu, 17 Oct 2013 00:51:49 +0000 Subject: [PATCH] Split changes list classes into separate files Having them separate improves readability of the code and makes it easier to work with this code. Change-Id: Ic6aaf1ace3640f66ad41c2d85b4f7d740b259e0c --- includes/AutoLoader.php | 12 +- includes/changes/ChangesList.php | 552 ++++++++++++++ .../EnhancedChangesList.php} | 674 +----------------- includes/changes/OldChangesList.php | 130 ++++ includes/changes/RCCacheEntry.php | 35 + includes/{ => changes}/RecentChange.php | 0 6 files changed, 725 insertions(+), 678 deletions(-) create mode 100644 includes/changes/ChangesList.php rename includes/{ChangesList.php => changes/EnhancedChangesList.php} (51%) create mode 100644 includes/changes/OldChangesList.php create mode 100644 includes/changes/RCCacheEntry.php rename includes/{ => changes}/RecentChange.php (100%) diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 8d571ad023..8a5032673f 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -55,7 +55,6 @@ $wgAutoloadLocalClasses = array( 'CdbWriter_DBA' => 'includes/Cdb.php', 'CdbWriter_PHP' => 'includes/Cdb_PHP.php', 'ChangesFeed' => 'includes/ChangesFeed.php', - 'ChangesList' => 'includes/ChangesList.php', 'ChangeTags' => 'includes/ChangeTags.php', 'ChannelFeed' => 'includes/Feed.php', 'Collation' => 'includes/Collation.php', @@ -87,7 +86,6 @@ $wgAutoloadLocalClasses = array( 'DumpPipeOutput' => 'includes/Export.php', 'EditPage' => 'includes/EditPage.php', 'EmailNotification' => 'includes/UserMailer.php', - 'EnhancedChangesList' => 'includes/ChangesList.php', 'ErrorPageError' => 'includes/Exception.php', 'ExplodeIterator' => 'includes/StringUtils.php', 'FakeTitle' => 'includes/FakeTitle.php', @@ -178,7 +176,6 @@ $wgAutoloadLocalClasses = array( 'MWHttpRequest' => 'includes/HttpFunctions.php', 'MWInit' => 'includes/Init.php', 'MWNamespace' => 'includes/Namespace.php', - 'OldChangesList' => 'includes/ChangesList.php', 'OutputPage' => 'includes/OutputPage.php', 'Page' => 'includes/WikiPage.php', 'PageQueryPage' => 'includes/PageQueryPage.php', @@ -200,10 +197,8 @@ $wgAutoloadLocalClasses = array( 'QueryPage' => 'includes/QueryPage.php', 'QuickTemplate' => 'includes/SkinTemplate.php', 'RawMessage' => 'includes/Message.php', - 'RCCacheEntry' => 'includes/ChangesList.php', 'RdfMetaData' => 'includes/Metadata.php', 'ReadOnlyError' => 'includes/Exception.php', - 'RecentChange' => 'includes/RecentChange.php', 'RedirectSpecialArticle' => 'includes/SpecialPage.php', 'RedirectSpecialPage' => 'includes/SpecialPage.php', 'RegexlikeReplacer' => 'includes/StringUtils.php', @@ -457,6 +452,13 @@ $wgAutoloadLocalClasses = array( 'TitleDependency' => 'includes/cache/CacheDependency.php', 'TitleListDependency' => 'includes/cache/CacheDependency.php', + # includes/changes + 'ChangesList' => 'includes/changes/ChangesList.php', + 'EnhancedChangesList' => 'includes/changes/EnhancedChangesList.php', + 'OldChangesList' => 'includes/changes/OldChangesList.php', + 'RCCacheEntry' => 'includes/changes/RCCacheEntry.php', + 'RecentChange' => 'includes/changes/RecentChange.php', + # includes/clientpool 'RedisConnectionPool' => 'includes/clientpool/RedisConnectionPool.php', 'RedisConnRef' => 'includes/clientpool/RedisConnectionPool.php', diff --git a/includes/changes/ChangesList.php b/includes/changes/ChangesList.php new file mode 100644 index 0000000000..bf800c4645 --- /dev/null +++ b/includes/changes/ChangesList.php @@ -0,0 +1,552 @@ +setContext( $obj ); + $this->skin = $obj->getSkin(); + } else { + $this->setContext( $obj->getContext() ); + $this->skin = $obj; + } + $this->preCacheMessages(); + } + + /** + * Fetch an appropriate changes list class for the main context + * This first argument used to be an User object. + * + * @deprecated in 1.18; use newFromContext() instead + * @param string|User $unused Unused + * @return ChangesList|EnhancedChangesList|OldChangesList derivative + */ + public static function newFromUser( $unused ) { + wfDeprecated( __METHOD__, '1.18' ); + return self::newFromContext( RequestContext::getMain() ); + } + + /** + * Fetch an appropriate changes list class for the specified context + * Some users might want to use an enhanced list format, for instance + * + * @param $context IContextSource to use + * @return ChangesList|EnhancedChangesList|OldChangesList derivative + */ + public static function newFromContext( IContextSource $context ) { + $user = $context->getUser(); + $sk = $context->getSkin(); + $list = null; + if ( wfRunHooks( 'FetchChangesList', array( $user, &$sk, &$list ) ) ) { + $new = $context->getRequest()->getBool( 'enhanced', $user->getOption( 'usenewrc' ) ); + return $new ? new EnhancedChangesList( $context ) : new OldChangesList( $context ); + } else { + return $list; + } + } + + /** + * Sets the list to use a "
  • " tag + * @param $value Boolean + */ + public function setWatchlistDivs( $value = true ) { + $this->watchlist = $value; + } + + /** + * 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 + */ + private function preCacheMessages() { + if ( !isset( $this->message ) ) { + foreach ( array( + 'cur', 'diff', 'hist', 'enhancedrc-history', 'last', 'blocklink', 'history', + 'semicolon-separator', 'pipe-separator' ) as $msg + ) { + $this->message[$msg] = $this->msg( $msg )->escaped(); + } + } + } + + /** + * Returns the appropriate flags for new page, minor change and patrolling + * @param array $flags Associative array of 'flag' => Bool + * @param string $nothing to use for empty space + * @return String + */ + public function recentChangesFlags( $flags, $nothing = ' ' ) { + global $wgRecentChangesFlags; + $f = ''; + foreach ( array_keys( $wgRecentChangesFlags ) as $flag ) { + $f .= isset( $flags[$flag] ) && $flags[$flag] + ? self::flag( $flag ) + : $nothing; + } + return $f; + } + + /** + * Provide the "" element appropriate to a given abbreviated flag, + * namely the flag indicating a new page, a minor edit, a bot edit, or an + * unpatrolled edit. By default in English it will contain "N", "m", "b", + * "!" respectively, plus it will have an appropriate title and class. + * + * @param string $flag One key of $wgRecentChangesFlags + * @return String: Raw HTML + */ + public static function flag( $flag ) { + static $flagInfos = null; + if ( is_null( $flagInfos ) ) { + global $wgRecentChangesFlags; + $flagInfos = array(); + foreach ( $wgRecentChangesFlags as $key => $value ) { + $flagInfos[$key]['letter'] = wfMessage( $value['letter'] )->escaped(); + $flagInfos[$key]['title'] = wfMessage( $value['title'] )->escaped(); + // Allow customized class name, fall back to flag name + $flagInfos[$key]['class'] = Sanitizer::escapeClass( + isset( $value['class'] ) ? $value['class'] : $key ); + } + } + + // Inconsistent naming, bleh, kepted for b/c + $map = array( + 'minoredit' => 'minor', + 'botedit' => 'bot', + ); + if ( isset( $map[$flag] ) ) { + $flag = $map[$flag]; + } + + return "" . + $flagInfos[$flag]['letter'] . + ''; + } + + /** + * Returns text for the start of the tabular part of RC + * @return String + */ + public function beginRecentChangesList() { + $this->rc_cache = array(); + $this->rcMoveIndex = 0; + $this->rcCacheIndex = 0; + $this->lastdate = ''; + $this->rclistOpen = false; + $this->getOutput()->addModuleStyles( 'mediawiki.special.changeslist' ); + return ''; + } + + /** + * Show formatted char difference + * @param $old Integer: bytes + * @param $new Integer: bytes + * @param $context IContextSource context to use + * @return String + */ + public static function showCharacterDifference( $old, $new, IContextSource $context = null ) { + global $wgRCChangedSizeThreshold, $wgMiserMode; + + if ( !$context ) { + $context = RequestContext::getMain(); + } + + $new = (int)$new; + $old = (int)$old; + $szdiff = $new - $old; + + $lang = $context->getLanguage(); + $code = $lang->getCode(); + static $fastCharDiff = array(); + if ( !isset( $fastCharDiff[$code] ) ) { + $fastCharDiff[$code] = $wgMiserMode || $context->msg( 'rc-change-size' )->plain() === '$1'; + } + + $formattedSize = $lang->formatNum( $szdiff ); + + if ( !$fastCharDiff[$code] ) { + $formattedSize = $context->msg( 'rc-change-size', $formattedSize )->text(); + } + + if ( abs( $szdiff ) > abs( $wgRCChangedSizeThreshold ) ) { + $tag = 'strong'; + } else { + $tag = 'span'; + } + + if ( $szdiff === 0 ) { + $formattedSizeClass = 'mw-plusminus-null'; + } + if ( $szdiff > 0 ) { + $formattedSize = '+' . $formattedSize; + $formattedSizeClass = 'mw-plusminus-pos'; + } + if ( $szdiff < 0 ) { + $formattedSizeClass = 'mw-plusminus-neg'; + } + + $formattedTotalSize = $context->msg( 'rc-change-size-new' )->numParams( $new )->text(); + + return Html::element( $tag, + array( 'dir' => 'ltr', 'class' => $formattedSizeClass, 'title' => $formattedTotalSize ), + $context->msg( 'parentheses', $formattedSize )->plain() ) . $lang->getDirMark(); + } + + /** + * Format the character difference of one or several changes. + * + * @param $old RecentChange + * @param $new RecentChange last change to use, if not provided, $old will be used + * @return string HTML fragment + */ + public function formatCharacterDifference( RecentChange $old, RecentChange $new = null ) { + $oldlen = $old->mAttribs['rc_old_len']; + + if ( $new ) { + $newlen = $new->mAttribs['rc_new_len']; + } else { + $newlen = $old->mAttribs['rc_new_len']; + } + + if ( $oldlen === null || $newlen === null ) { + return ''; + } + + return self::showCharacterDifference( $oldlen, $newlen, $this->getContext() ); + } + + /** + * Returns text for the end of RC + * @return String + */ + public function endRecentChangesList() { + if ( $this->rclistOpen ) { + return "\n"; + } else { + return ''; + } + } + + /** + * @param string $s HTML to update + * @param $rc_timestamp mixed + */ + public function insertDateHeader( &$s, $rc_timestamp ) { + # Make date header if necessary + $date = $this->getLanguage()->userDate( $rc_timestamp, $this->getUser() ); + if ( $date != $this->lastdate ) { + if ( $this->lastdate != '' ) { + $s .= "\n"; + } + $s .= Xml::element( 'h4', null, $date ) . "\n
      "; + $this->lastdate = $date; + $this->rclistOpen = true; + } + } + + /** + * @param string $s HTML to update + * @param $title Title + * @param $logtype string + */ + public function insertLog( &$s, $title, $logtype ) { + $page = new LogPage( $logtype ); + $logname = $page->getName()->escaped(); + $s .= $this->msg( 'parentheses' )->rawParams( Linker::linkKnown( $title, $logname ) )->escaped(); + } + + /** + * @param string $s HTML to update + * @param $rc RecentChange + * @param $unpatrolled + */ + public function insertDiffHist( &$s, &$rc, $unpatrolled ) { + # Diff link + if ( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) { + $diffLink = $this->message['diff']; + } elseif ( !self::userCan( $rc, Revision::DELETED_TEXT, $this->getUser() ) ) { + $diffLink = $this->message['diff']; + } else { + $query = array( + 'curid' => $rc->mAttribs['rc_cur_id'], + 'diff' => $rc->mAttribs['rc_this_oldid'], + 'oldid' => $rc->mAttribs['rc_last_oldid'] + ); + + $diffLink = Linker::linkKnown( + $rc->getTitle(), + $this->message['diff'], + array( 'tabindex' => $rc->counter ), + $query + ); + } + $diffhist = $diffLink . $this->message['pipe-separator']; + # History link + $diffhist .= Linker::linkKnown( + $rc->getTitle(), + $this->message['hist'], + array(), + array( + 'curid' => $rc->mAttribs['rc_cur_id'], + 'action' => 'history' + ) + ); + $s .= $this->msg( 'parentheses' )->rawParams( $diffhist )->escaped() . ' . . '; + } + + /** + * @param string $s HTML to update + * @param $rc RecentChange + * @param $unpatrolled + * @param $watched + */ + public function insertArticleLink( &$s, &$rc, $unpatrolled, $watched ) { + $params = array(); + + $articlelink = Linker::linkKnown( + $rc->getTitle(), + null, + array( 'class' => 'mw-changeslist-title' ), + $params + ); + if ( $this->isDeleted( $rc, Revision::DELETED_TEXT ) ) { + $articlelink = '' . $articlelink . ''; + } + # To allow for boldening pages watched by this user + $articlelink = "{$articlelink}"; + # RTL/LTR marker + $articlelink .= $this->getLanguage()->getDirMark(); + + wfRunHooks( 'ChangesListInsertArticleLink', + array( &$this, &$articlelink, &$s, &$rc, $unpatrolled, $watched ) ); + + $s .= " $articlelink"; + } + + /** + * Get the timestamp from $rc formatted with current user's settings + * and a separator + * + * @param $rc RecentChange + * @return string HTML fragment + */ + public function getTimestamp( $rc ) { + return $this->message['semicolon-separator'] . '' . + $this->getLanguage()->userTime( $rc->mAttribs['rc_timestamp'], $this->getUser() ) . ' . . '; + } + + /** + * Insert time timestamp string from $rc into $s + * + * @param string $s HTML to update + * @param $rc RecentChange + */ + public function insertTimestamp( &$s, $rc ) { + $s .= $this->getTimestamp( $rc ); + } + + /** + * Insert links to user page, user talk page and eventually a blocking link + * + * @param &$s String HTML to update + * @param &$rc RecentChange + */ + public function insertUserRelatedLinks( &$s, &$rc ) { + if ( $this->isDeleted( $rc, Revision::DELETED_USER ) ) { + $s .= ' ' . $this->msg( 'rev-deleted-user' )->escaped() . ''; + } else { + $s .= $this->getLanguage()->getDirMark() . Linker::userLink( $rc->mAttribs['rc_user'], + $rc->mAttribs['rc_user_text'] ); + $s .= Linker::userToolLinks( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); + } + } + + /** + * Insert a formatted action + * + * @param $rc RecentChange + * @return string + */ + public function insertLogEntry( $rc ) { + $formatter = LogFormatter::newFromRow( $rc->mAttribs ); + $formatter->setContext( $this->getContext() ); + $formatter->setShowUserToolLinks( true ); + $mark = $this->getLanguage()->getDirMark(); + return $formatter->getActionText() . " $mark" . $formatter->getComment(); + } + + /** + * Insert a formatted comment + * @param $rc RecentChange + * @return string + */ + public function insertComment( $rc ) { + if ( $rc->mAttribs['rc_type'] != RC_MOVE && $rc->mAttribs['rc_type'] != RC_MOVE_OVER_REDIRECT ) { + if ( $this->isDeleted( $rc, Revision::DELETED_COMMENT ) ) { + return ' ' . $this->msg( 'rev-deleted-comment' )->escaped() . ''; + } else { + return Linker::commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() ); + } + } + return ''; + } + + /** + * Check whether to enable recent changes patrol features + * + * @deprecated since 1.22 + * @return Boolean + */ + public static function usePatrol() { + global $wgUser; + + wfDeprecated( __METHOD__, '1.22' ); + + return $wgUser->useRCPatrol(); + } + + /** + * Returns the string which indicates the number of watching users + * @return string + */ + protected function numberofWatchingusers( $count ) { + static $cache = array(); + if ( $count > 0 ) { + if ( !isset( $cache[$count] ) ) { + $cache[$count] = $this->msg( 'number_of_watching_users_RCview' )->numParams( $count )->escaped(); + } + return $cache[$count]; + } else { + return ''; + } + } + + /** + * Determine if said field of a revision is hidden + * @param $rc RCCacheEntry + * @param $field Integer: one of DELETED_* bitfield constants + * @return Boolean + */ + public static function isDeleted( $rc, $field ) { + return ( $rc->mAttribs['rc_deleted'] & $field ) == $field; + } + + /** + * Determine if the current user is allowed to view a particular + * field of this revision, if it's marked as deleted. + * @param $rc RCCacheEntry + * @param $field Integer + * @param $user User object to check, or null to use $wgUser + * @return Boolean + */ + public static function userCan( $rc, $field, User $user = null ) { + if ( $rc->mAttribs['rc_type'] == RC_LOG ) { + return LogEventsList::userCanBitfield( $rc->mAttribs['rc_deleted'], $field, $user ); + } else { + return Revision::userCanBitfield( $rc->mAttribs['rc_deleted'], $field, $user ); + } + } + + /** + * @param $link string + * @param $watched bool + * @return string + */ + protected function maybeWatchedLink( $link, $watched = false ) { + if ( $watched ) { + return '' . $link . ''; + } else { + return '' . $link . ''; + } + } + + /** Inserts a rollback link + * + * @param $s string + * @param $rc RecentChange + */ + public function insertRollback( &$s, &$rc ) { + if ( $rc->mAttribs['rc_type'] == RC_EDIT && $rc->mAttribs['rc_this_oldid'] && $rc->mAttribs['rc_cur_id'] ) { + $page = $rc->getTitle(); + /** Check for rollback and edit permissions, disallow special pages, and only + * show a link on the top-most revision */ + if ( $this->getUser()->isAllowed( 'rollback' ) && $rc->mAttribs['page_latest'] == $rc->mAttribs['rc_this_oldid'] ) + { + $rev = new Revision( array( + 'title' => $page, + 'id' => $rc->mAttribs['rc_this_oldid'], + 'user' => $rc->mAttribs['rc_user'], + 'user_text' => $rc->mAttribs['rc_user_text'], + 'deleted' => $rc->mAttribs['rc_deleted'] + ) ); + $s .= ' ' . Linker::generateRollback( $rev, $this->getContext() ); + } + } + } + + /** + * @param $s string + * @param $rc RecentChange + * @param $classes + */ + public function insertTags( &$s, &$rc, &$classes ) { + if ( empty( $rc->mAttribs['ts_tags'] ) ) { + return; + } + + list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $rc->mAttribs['ts_tags'], 'changeslist' ); + $classes = array_merge( $classes, $newClasses ); + $s .= ' ' . $tagSummary; + } + + public function insertExtra( &$s, &$rc, &$classes ) { + // Empty, used for subclasses to add anything special. + } + + protected function showAsUnpatrolled( RecentChange $rc ) { + $unpatrolled = false; + if ( !$rc->mAttribs['rc_patrolled'] ) { + if ( $this->getUser()->useRCPatrol() ) { + $unpatrolled = true; + } elseif ( $this->getUser()->useNPPatrol() && $rc->mAttribs['rc_type'] == RC_NEW ) { + $unpatrolled = true; + } + } + return $unpatrolled; + } +} diff --git a/includes/ChangesList.php b/includes/changes/EnhancedChangesList.php similarity index 51% rename from includes/ChangesList.php rename to includes/changes/EnhancedChangesList.php index 9c441afaaf..433adb375c 100644 --- a/includes/ChangesList.php +++ b/includes/changes/EnhancedChangesList.php @@ -1,11 +1,6 @@ mAttribs = $rc->mAttribs; - $rc2->mExtra = $rc->mExtra; - return $rc2; - } -} - -/** - * Base class for all changes lists - */ -class ChangesList extends ContextSource { - - /** - * @var Skin - */ - public $skin; - - protected $watchlist = false; - - protected $message; - - /** - * Changeslist constructor - * - * @param $obj Skin or IContextSource - */ - public function __construct( $obj ) { - if ( $obj instanceof IContextSource ) { - $this->setContext( $obj ); - $this->skin = $obj->getSkin(); - } else { - $this->setContext( $obj->getContext() ); - $this->skin = $obj; - } - $this->preCacheMessages(); - } - - /** - * Fetch an appropriate changes list class for the main context - * This first argument used to be an User object. - * - * @deprecated in 1.18; use newFromContext() instead - * @param string|User $unused Unused - * @return ChangesList|EnhancedChangesList|OldChangesList derivative - */ - public static function newFromUser( $unused ) { - wfDeprecated( __METHOD__, '1.18' ); - return self::newFromContext( RequestContext::getMain() ); - } - - /** - * Fetch an appropriate changes list class for the specified context - * Some users might want to use an enhanced list format, for instance - * - * @param $context IContextSource to use - * @return ChangesList|EnhancedChangesList|OldChangesList derivative - */ - public static function newFromContext( IContextSource $context ) { - $user = $context->getUser(); - $sk = $context->getSkin(); - $list = null; - if ( wfRunHooks( 'FetchChangesList', array( $user, &$sk, &$list ) ) ) { - $new = $context->getRequest()->getBool( 'enhanced', $user->getOption( 'usenewrc' ) ); - return $new ? new EnhancedChangesList( $context ) : new OldChangesList( $context ); - } else { - return $list; - } - } - - /** - * Sets the list to use a "
    • " tag - * @param $value Boolean - */ - public function setWatchlistDivs( $value = true ) { - $this->watchlist = $value; - } - - /** - * 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 - */ - private function preCacheMessages() { - if ( !isset( $this->message ) ) { - foreach ( array( - 'cur', 'diff', 'hist', 'enhancedrc-history', 'last', 'blocklink', 'history', - 'semicolon-separator', 'pipe-separator' ) as $msg - ) { - $this->message[$msg] = $this->msg( $msg )->escaped(); - } - } - } - - /** - * Returns the appropriate flags for new page, minor change and patrolling - * @param array $flags Associative array of 'flag' => Bool - * @param string $nothing to use for empty space - * @return String - */ - public function recentChangesFlags( $flags, $nothing = ' ' ) { - global $wgRecentChangesFlags; - $f = ''; - foreach ( array_keys( $wgRecentChangesFlags ) as $flag ) { - $f .= isset( $flags[$flag] ) && $flags[$flag] - ? self::flag( $flag ) - : $nothing; - } - return $f; - } - - /** - * Provide the "" element appropriate to a given abbreviated flag, - * namely the flag indicating a new page, a minor edit, a bot edit, or an - * unpatrolled edit. By default in English it will contain "N", "m", "b", - * "!" respectively, plus it will have an appropriate title and class. - * - * @param string $flag One key of $wgRecentChangesFlags - * @return String: Raw HTML - */ - public static function flag( $flag ) { - static $flagInfos = null; - if ( is_null( $flagInfos ) ) { - global $wgRecentChangesFlags; - $flagInfos = array(); - foreach ( $wgRecentChangesFlags as $key => $value ) { - $flagInfos[$key]['letter'] = wfMessage( $value['letter'] )->escaped(); - $flagInfos[$key]['title'] = wfMessage( $value['title'] )->escaped(); - // Allow customized class name, fall back to flag name - $flagInfos[$key]['class'] = Sanitizer::escapeClass( - isset( $value['class'] ) ? $value['class'] : $key ); - } - } - - // Inconsistent naming, bleh, kepted for b/c - $map = array( - 'minoredit' => 'minor', - 'botedit' => 'bot', - ); - if ( isset( $map[$flag] ) ) { - $flag = $map[$flag]; - } - - return "" . - $flagInfos[$flag]['letter'] . - ''; - } - - /** - * Returns text for the start of the tabular part of RC - * @return String - */ - public function beginRecentChangesList() { - $this->rc_cache = array(); - $this->rcMoveIndex = 0; - $this->rcCacheIndex = 0; - $this->lastdate = ''; - $this->rclistOpen = false; - $this->getOutput()->addModuleStyles( 'mediawiki.special.changeslist' ); - return ''; - } - - /** - * Show formatted char difference - * @param $old Integer: bytes - * @param $new Integer: bytes - * @param $context IContextSource context to use - * @return String - */ - public static function showCharacterDifference( $old, $new, IContextSource $context = null ) { - global $wgRCChangedSizeThreshold, $wgMiserMode; - - if ( !$context ) { - $context = RequestContext::getMain(); - } - - $new = (int)$new; - $old = (int)$old; - $szdiff = $new - $old; - - $lang = $context->getLanguage(); - $code = $lang->getCode(); - static $fastCharDiff = array(); - if ( !isset( $fastCharDiff[$code] ) ) { - $fastCharDiff[$code] = $wgMiserMode || $context->msg( 'rc-change-size' )->plain() === '$1'; - } - - $formattedSize = $lang->formatNum( $szdiff ); - - if ( !$fastCharDiff[$code] ) { - $formattedSize = $context->msg( 'rc-change-size', $formattedSize )->text(); - } - - if ( abs( $szdiff ) > abs( $wgRCChangedSizeThreshold ) ) { - $tag = 'strong'; - } else { - $tag = 'span'; - } - - if ( $szdiff === 0 ) { - $formattedSizeClass = 'mw-plusminus-null'; - } - if ( $szdiff > 0 ) { - $formattedSize = '+' . $formattedSize; - $formattedSizeClass = 'mw-plusminus-pos'; - } - if ( $szdiff < 0 ) { - $formattedSizeClass = 'mw-plusminus-neg'; - } - - $formattedTotalSize = $context->msg( 'rc-change-size-new' )->numParams( $new )->text(); - - return Html::element( $tag, - array( 'dir' => 'ltr', 'class' => $formattedSizeClass, 'title' => $formattedTotalSize ), - $context->msg( 'parentheses', $formattedSize )->plain() ) . $lang->getDirMark(); - } - - /** - * Format the character difference of one or several changes. - * - * @param $old RecentChange - * @param $new RecentChange last change to use, if not provided, $old will be used - * @return string HTML fragment - */ - public function formatCharacterDifference( RecentChange $old, RecentChange $new = null ) { - $oldlen = $old->mAttribs['rc_old_len']; - - if ( $new ) { - $newlen = $new->mAttribs['rc_new_len']; - } else { - $newlen = $old->mAttribs['rc_new_len']; - } - - if ( $oldlen === null || $newlen === null ) { - return ''; - } - - return self::showCharacterDifference( $oldlen, $newlen, $this->getContext() ); - } - - /** - * Returns text for the end of RC - * @return String - */ - public function endRecentChangesList() { - if ( $this->rclistOpen ) { - return "
    \n"; - } else { - return ''; - } - } - - /** - * @param string $s HTML to update - * @param $rc_timestamp mixed - */ - public function insertDateHeader( &$s, $rc_timestamp ) { - # Make date header if necessary - $date = $this->getLanguage()->userDate( $rc_timestamp, $this->getUser() ); - if ( $date != $this->lastdate ) { - if ( $this->lastdate != '' ) { - $s .= "\n"; - } - $s .= Xml::element( 'h4', null, $date ) . "\n
      "; - $this->lastdate = $date; - $this->rclistOpen = true; - } - } - - /** - * @param string $s HTML to update - * @param $title Title - * @param $logtype string - */ - public function insertLog( &$s, $title, $logtype ) { - $page = new LogPage( $logtype ); - $logname = $page->getName()->escaped(); - $s .= $this->msg( 'parentheses' )->rawParams( Linker::linkKnown( $title, $logname ) )->escaped(); - } - - /** - * @param string $s HTML to update - * @param $rc RecentChange - * @param $unpatrolled - */ - public function insertDiffHist( &$s, &$rc, $unpatrolled ) { - # Diff link - if ( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) { - $diffLink = $this->message['diff']; - } elseif ( !self::userCan( $rc, Revision::DELETED_TEXT, $this->getUser() ) ) { - $diffLink = $this->message['diff']; - } else { - $query = array( - 'curid' => $rc->mAttribs['rc_cur_id'], - 'diff' => $rc->mAttribs['rc_this_oldid'], - 'oldid' => $rc->mAttribs['rc_last_oldid'] - ); - - $diffLink = Linker::linkKnown( - $rc->getTitle(), - $this->message['diff'], - array( 'tabindex' => $rc->counter ), - $query - ); - } - $diffhist = $diffLink . $this->message['pipe-separator']; - # History link - $diffhist .= Linker::linkKnown( - $rc->getTitle(), - $this->message['hist'], - array(), - array( - 'curid' => $rc->mAttribs['rc_cur_id'], - 'action' => 'history' - ) - ); - $s .= $this->msg( 'parentheses' )->rawParams( $diffhist )->escaped() . ' . . '; - } - - /** - * @param string $s HTML to update - * @param $rc RecentChange - * @param $unpatrolled - * @param $watched - */ - public function insertArticleLink( &$s, &$rc, $unpatrolled, $watched ) { - $params = array(); - - $articlelink = Linker::linkKnown( - $rc->getTitle(), - null, - array( 'class' => 'mw-changeslist-title' ), - $params - ); - if ( $this->isDeleted( $rc, Revision::DELETED_TEXT ) ) { - $articlelink = '' . $articlelink . ''; - } - # To allow for boldening pages watched by this user - $articlelink = "{$articlelink}"; - # RTL/LTR marker - $articlelink .= $this->getLanguage()->getDirMark(); - - wfRunHooks( 'ChangesListInsertArticleLink', - array( &$this, &$articlelink, &$s, &$rc, $unpatrolled, $watched ) ); - - $s .= " $articlelink"; - } - - /** - * Get the timestamp from $rc formatted with current user's settings - * and a separator - * - * @param $rc RecentChange - * @return string HTML fragment - */ - public function getTimestamp( $rc ) { - return $this->message['semicolon-separator'] . '' . - $this->getLanguage()->userTime( $rc->mAttribs['rc_timestamp'], $this->getUser() ) . ' . . '; - } - - /** - * Insert time timestamp string from $rc into $s - * - * @param string $s HTML to update - * @param $rc RecentChange - */ - public function insertTimestamp( &$s, $rc ) { - $s .= $this->getTimestamp( $rc ); - } - - /** - * Insert links to user page, user talk page and eventually a blocking link - * - * @param &$s String HTML to update - * @param &$rc RecentChange - */ - public function insertUserRelatedLinks( &$s, &$rc ) { - if ( $this->isDeleted( $rc, Revision::DELETED_USER ) ) { - $s .= ' ' . $this->msg( 'rev-deleted-user' )->escaped() . ''; - } else { - $s .= $this->getLanguage()->getDirMark() . Linker::userLink( $rc->mAttribs['rc_user'], - $rc->mAttribs['rc_user_text'] ); - $s .= Linker::userToolLinks( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); - } - } - - /** - * Insert a formatted action - * - * @param $rc RecentChange - * @return string - */ - public function insertLogEntry( $rc ) { - $formatter = LogFormatter::newFromRow( $rc->mAttribs ); - $formatter->setContext( $this->getContext() ); - $formatter->setShowUserToolLinks( true ); - $mark = $this->getLanguage()->getDirMark(); - return $formatter->getActionText() . " $mark" . $formatter->getComment(); - } - - /** - * Insert a formatted comment - * @param $rc RecentChange - * @return string - */ - public function insertComment( $rc ) { - if ( $rc->mAttribs['rc_type'] != RC_MOVE && $rc->mAttribs['rc_type'] != RC_MOVE_OVER_REDIRECT ) { - if ( $this->isDeleted( $rc, Revision::DELETED_COMMENT ) ) { - return ' ' . $this->msg( 'rev-deleted-comment' )->escaped() . ''; - } else { - return Linker::commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() ); - } - } - return ''; - } - - /** - * Check whether to enable recent changes patrol features - * - * @deprecated since 1.22 - * @return Boolean - */ - public static function usePatrol() { - global $wgUser; - - wfDeprecated( __METHOD__, '1.22' ); - - return $wgUser->useRCPatrol(); - } - - /** - * Returns the string which indicates the number of watching users - * @return string - */ - protected function numberofWatchingusers( $count ) { - static $cache = array(); - if ( $count > 0 ) { - if ( !isset( $cache[$count] ) ) { - $cache[$count] = $this->msg( 'number_of_watching_users_RCview' )->numParams( $count )->escaped(); - } - return $cache[$count]; - } else { - return ''; - } - } - - /** - * Determine if said field of a revision is hidden - * @param $rc RCCacheEntry - * @param $field Integer: one of DELETED_* bitfield constants - * @return Boolean - */ - public static function isDeleted( $rc, $field ) { - return ( $rc->mAttribs['rc_deleted'] & $field ) == $field; - } - - /** - * Determine if the current user is allowed to view a particular - * field of this revision, if it's marked as deleted. - * @param $rc RCCacheEntry - * @param $field Integer - * @param $user User object to check, or null to use $wgUser - * @return Boolean - */ - public static function userCan( $rc, $field, User $user = null ) { - if ( $rc->mAttribs['rc_type'] == RC_LOG ) { - return LogEventsList::userCanBitfield( $rc->mAttribs['rc_deleted'], $field, $user ); - } else { - return Revision::userCanBitfield( $rc->mAttribs['rc_deleted'], $field, $user ); - } - } - - /** - * @param $link string - * @param $watched bool - * @return string - */ - protected function maybeWatchedLink( $link, $watched = false ) { - if ( $watched ) { - return '' . $link . ''; - } else { - return '' . $link . ''; - } - } - - /** Inserts a rollback link - * - * @param $s string - * @param $rc RecentChange - */ - public function insertRollback( &$s, &$rc ) { - if ( $rc->mAttribs['rc_type'] == RC_EDIT && $rc->mAttribs['rc_this_oldid'] && $rc->mAttribs['rc_cur_id'] ) { - $page = $rc->getTitle(); - /** Check for rollback and edit permissions, disallow special pages, and only - * show a link on the top-most revision */ - if ( $this->getUser()->isAllowed( 'rollback' ) && $rc->mAttribs['page_latest'] == $rc->mAttribs['rc_this_oldid'] ) - { - $rev = new Revision( array( - 'title' => $page, - 'id' => $rc->mAttribs['rc_this_oldid'], - 'user' => $rc->mAttribs['rc_user'], - 'user_text' => $rc->mAttribs['rc_user_text'], - 'deleted' => $rc->mAttribs['rc_deleted'] - ) ); - $s .= ' ' . Linker::generateRollback( $rev, $this->getContext() ); - } - } - } - - /** - * @param $s string - * @param $rc RecentChange - * @param $classes - */ - public function insertTags( &$s, &$rc, &$classes ) { - if ( empty( $rc->mAttribs['ts_tags'] ) ) { - return; - } - - list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $rc->mAttribs['ts_tags'], 'changeslist' ); - $classes = array_merge( $classes, $newClasses ); - $s .= ' ' . $tagSummary; - } - - public function insertExtra( &$s, &$rc, &$classes ) { - // Empty, used for subclasses to add anything special. - } - - protected function showAsUnpatrolled( RecentChange $rc ) { - $unpatrolled = false; - if ( !$rc->mAttribs['rc_patrolled'] ) { - if ( $this->getUser()->useRCPatrol() ) { - $unpatrolled = true; - } elseif ( $this->getUser()->useNPPatrol() && $rc->mAttribs['rc_type'] == RC_NEW ) { - $unpatrolled = true; - } - } - return $unpatrolled; - } -} - -/** - * Generate a list of changes using the good old system (no javascript) - */ -class OldChangesList extends ChangesList { - /** - * Format a line using the old system (aka without any javascript). - * - * @param $rc RecentChange, passed by reference - * @param bool $watched (default false) - * @param int $linenumber (default null) - * - * @return string|bool - */ - public function recentChangesLine( &$rc, $watched = false, $linenumber = null ) { - global $wgRCShowChangedSize; - wfProfileIn( __METHOD__ ); - - # Should patrol-related stuff be shown? - $unpatrolled = $this->showAsUnpatrolled( $rc ); - - $dateheader = ''; // $s now contains only
    • ...
    • , for hooks' convenience. - $this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] ); - - $s = ''; - $classes = array(); - // use mw-line-even/mw-line-odd class only if linenumber is given (feature from bug 14468) - if ( $linenumber ) { - if ( $linenumber & 1 ) { - $classes[] = 'mw-line-odd'; - } else { - $classes[] = 'mw-line-even'; - } - } - - // Indicate watched status on the line to allow for more - // comprehensive styling. - $classes[] = $watched && $rc->mAttribs['rc_timestamp'] >= $watched - ? 'mw-changeslist-line-watched' : 'mw-changeslist-line-not-watched'; - - // Moved pages (very very old, not supported anymore) - if ( $rc->mAttribs['rc_type'] == RC_MOVE || $rc->mAttribs['rc_type'] == RC_MOVE_OVER_REDIRECT ) { - // Log entries - } elseif ( $rc->mAttribs['rc_log_type'] ) { - $logtitle = SpecialPage::getTitleFor( 'Log', $rc->mAttribs['rc_log_type'] ); - $this->insertLog( $s, $logtitle, $rc->mAttribs['rc_log_type'] ); - // Log entries (old format) or log targets, and special pages - } elseif ( $rc->mAttribs['rc_namespace'] == NS_SPECIAL ) { - list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $rc->mAttribs['rc_title'] ); - if ( $name == 'Log' ) { - $this->insertLog( $s, $rc->getTitle(), $subpage ); - } - // Regular entries - } else { - $this->insertDiffHist( $s, $rc, $unpatrolled ); - # M, N, b and ! (minor, new, bot and unpatrolled) - $s .= $this->recentChangesFlags( - array( - 'newpage' => $rc->mAttribs['rc_type'] == RC_NEW, - 'minor' => $rc->mAttribs['rc_minor'], - 'unpatrolled' => $unpatrolled, - 'bot' => $rc->mAttribs['rc_bot'] - ), - '' - ); - $this->insertArticleLink( $s, $rc, $unpatrolled, $watched ); - } - # Edit/log timestamp - $this->insertTimestamp( $s, $rc ); - # Bytes added or removed - if ( $wgRCShowChangedSize ) { - $cd = $this->formatCharacterDifference( $rc ); - if ( $cd !== '' ) { - $s .= $cd . ' . . '; - } - } - - if ( $rc->mAttribs['rc_type'] == RC_LOG ) { - $s .= $this->insertLogEntry( $rc ); - } else { - # User tool links - $this->insertUserRelatedLinks( $s, $rc ); - # LTR/RTL direction mark - $s .= $this->getLanguage()->getDirMark(); - $s .= $this->insertComment( $rc ); - } - - # Tags - $this->insertTags( $s, $rc, $classes ); - # Rollback - $this->insertRollback( $s, $rc ); - # For subclasses - $this->insertExtra( $s, $rc, $classes ); - - # How many users watch this page - if ( $rc->numberofWatchingusers > 0 ) { - $s .= ' ' . $this->numberofWatchingusers( $rc->numberofWatchingusers ); - } - - if ( $this->watchlist ) { - $classes[] = Sanitizer::escapeClass( 'watchlist-' . $rc->mAttribs['rc_namespace'] . '-' . $rc->mAttribs['rc_title'] ); - } - - if ( !wfRunHooks( 'OldChangesListRecentChangesLine', array( &$this, &$s, $rc, &$classes ) ) ) { - wfProfileOut( __METHOD__ ); - return false; - } - - wfProfileOut( __METHOD__ ); - return "$dateheader
    • " . $s . "
    • \n"; - } -} - -/** - * Generate a list of changes using an Enhanced system (uses javascript). - */ class EnhancedChangesList extends ChangesList { protected $rc_cache; diff --git a/includes/changes/OldChangesList.php b/includes/changes/OldChangesList.php new file mode 100644 index 0000000000..a7fe9342ef --- /dev/null +++ b/includes/changes/OldChangesList.php @@ -0,0 +1,130 @@ +showAsUnpatrolled( $rc ); + + $dateheader = ''; // $s now contains only
    • ...
    • , for hooks' convenience. + $this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] ); + + $s = ''; + $classes = array(); + // use mw-line-even/mw-line-odd class only if linenumber is given (feature from bug 14468) + if ( $linenumber ) { + if ( $linenumber & 1 ) { + $classes[] = 'mw-line-odd'; + } else { + $classes[] = 'mw-line-even'; + } + } + + // Indicate watched status on the line to allow for more + // comprehensive styling. + $classes[] = $watched && $rc->mAttribs['rc_timestamp'] >= $watched + ? 'mw-changeslist-line-watched' : 'mw-changeslist-line-not-watched'; + + // Moved pages (very very old, not supported anymore) + if ( $rc->mAttribs['rc_type'] == RC_MOVE || $rc->mAttribs['rc_type'] == RC_MOVE_OVER_REDIRECT ) { + // Log entries + } elseif ( $rc->mAttribs['rc_log_type'] ) { + $logtitle = SpecialPage::getTitleFor( 'Log', $rc->mAttribs['rc_log_type'] ); + $this->insertLog( $s, $logtitle, $rc->mAttribs['rc_log_type'] ); + // Log entries (old format) or log targets, and special pages + } elseif ( $rc->mAttribs['rc_namespace'] == NS_SPECIAL ) { + list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $rc->mAttribs['rc_title'] ); + if ( $name == 'Log' ) { + $this->insertLog( $s, $rc->getTitle(), $subpage ); + } + // Regular entries + } else { + $this->insertDiffHist( $s, $rc, $unpatrolled ); + # M, N, b and ! (minor, new, bot and unpatrolled) + $s .= $this->recentChangesFlags( + array( + 'newpage' => $rc->mAttribs['rc_type'] == RC_NEW, + 'minor' => $rc->mAttribs['rc_minor'], + 'unpatrolled' => $unpatrolled, + 'bot' => $rc->mAttribs['rc_bot'] + ), + '' + ); + $this->insertArticleLink( $s, $rc, $unpatrolled, $watched ); + } + # Edit/log timestamp + $this->insertTimestamp( $s, $rc ); + # Bytes added or removed + if ( $wgRCShowChangedSize ) { + $cd = $this->formatCharacterDifference( $rc ); + if ( $cd !== '' ) { + $s .= $cd . ' . . '; + } + } + + if ( $rc->mAttribs['rc_type'] == RC_LOG ) { + $s .= $this->insertLogEntry( $rc ); + } else { + # User tool links + $this->insertUserRelatedLinks( $s, $rc ); + # LTR/RTL direction mark + $s .= $this->getLanguage()->getDirMark(); + $s .= $this->insertComment( $rc ); + } + + # Tags + $this->insertTags( $s, $rc, $classes ); + # Rollback + $this->insertRollback( $s, $rc ); + # For subclasses + $this->insertExtra( $s, $rc, $classes ); + + # How many users watch this page + if ( $rc->numberofWatchingusers > 0 ) { + $s .= ' ' . $this->numberofWatchingusers( $rc->numberofWatchingusers ); + } + + if ( $this->watchlist ) { + $classes[] = Sanitizer::escapeClass( 'watchlist-' . $rc->mAttribs['rc_namespace'] . '-' . $rc->mAttribs['rc_title'] ); + } + + if ( !wfRunHooks( 'OldChangesListRecentChangesLine', array( &$this, &$s, $rc, &$classes ) ) ) { + wfProfileOut( __METHOD__ ); + return false; + } + + wfProfileOut( __METHOD__ ); + return "$dateheader
    • " . $s . "
    • \n"; + } +} diff --git a/includes/changes/RCCacheEntry.php b/includes/changes/RCCacheEntry.php new file mode 100644 index 0000000000..9aef3d30e2 --- /dev/null +++ b/includes/changes/RCCacheEntry.php @@ -0,0 +1,35 @@ +mAttribs = $rc->mAttribs; + $rc2->mExtra = $rc->mExtra; + return $rc2; + } +} diff --git a/includes/RecentChange.php b/includes/changes/RecentChange.php similarity index 100% rename from includes/RecentChange.php rename to includes/changes/RecentChange.php -- 2.20.1