MediaWiki  REL1_22
ChangesList.php
Go to the documentation of this file.
00001 <?php
00025 class ChangesList extends ContextSource {
00026 
00030     public $skin;
00031 
00032     protected $watchlist = false;
00033 
00034     protected $message;
00035 
00041     public function __construct( $obj ) {
00042         if ( $obj instanceof IContextSource ) {
00043             $this->setContext( $obj );
00044             $this->skin = $obj->getSkin();
00045         } else {
00046             $this->setContext( $obj->getContext() );
00047             $this->skin = $obj;
00048         }
00049         $this->preCacheMessages();
00050     }
00051 
00060     public static function newFromUser( $unused ) {
00061         wfDeprecated( __METHOD__, '1.18' );
00062         return self::newFromContext( RequestContext::getMain() );
00063     }
00064 
00072     public static function newFromContext( IContextSource $context ) {
00073         $user = $context->getUser();
00074         $sk = $context->getSkin();
00075         $list = null;
00076         if ( wfRunHooks( 'FetchChangesList', array( $user, &$sk, &$list ) ) ) {
00077             $new = $context->getRequest()->getBool( 'enhanced', $user->getOption( 'usenewrc' ) );
00078             return $new ? new EnhancedChangesList( $context ) : new OldChangesList( $context );
00079         } else {
00080             return $list;
00081         }
00082     }
00083 
00088     public function setWatchlistDivs( $value = true ) {
00089         $this->watchlist = $value;
00090     }
00091 
00096     private function preCacheMessages() {
00097         if ( !isset( $this->message ) ) {
00098             foreach ( array(
00099                 'cur', 'diff', 'hist', 'enhancedrc-history', 'last', 'blocklink', 'history',
00100                 'semicolon-separator', 'pipe-separator' ) as $msg
00101             ) {
00102                 $this->message[$msg] = $this->msg( $msg )->escaped();
00103             }
00104         }
00105     }
00106 
00113     public function recentChangesFlags( $flags, $nothing = '&#160;' ) {
00114         global $wgRecentChangesFlags;
00115         $f = '';
00116         foreach ( array_keys( $wgRecentChangesFlags ) as $flag ) {
00117             $f .= isset( $flags[$flag] ) && $flags[$flag]
00118                 ? self::flag( $flag )
00119                 : $nothing;
00120         }
00121         return $f;
00122     }
00123 
00133     public static function flag( $flag ) {
00134         static $flagInfos = null;
00135         if ( is_null( $flagInfos ) ) {
00136             global $wgRecentChangesFlags;
00137             $flagInfos = array();
00138             foreach ( $wgRecentChangesFlags as $key => $value ) {
00139                 $flagInfos[$key]['letter'] = wfMessage( $value['letter'] )->escaped();
00140                 $flagInfos[$key]['title'] = wfMessage( $value['title'] )->escaped();
00141                 // Allow customized class name, fall back to flag name
00142                 $flagInfos[$key]['class'] = Sanitizer::escapeClass(
00143                     isset( $value['class'] ) ? $value['class'] : $key );
00144             }
00145         }
00146 
00147         // Inconsistent naming, bleh, kepted for b/c
00148         $map = array(
00149             'minoredit' => 'minor',
00150             'botedit' => 'bot',
00151         );
00152         if ( isset( $map[$flag] ) ) {
00153             $flag = $map[$flag];
00154         }
00155 
00156         return "<abbr class='" . $flagInfos[$flag]['class'] . "' title='" . $flagInfos[$flag]['title'] . "'>" .
00157             $flagInfos[$flag]['letter'] .
00158             '</abbr>';
00159     }
00160 
00165     public function beginRecentChangesList() {
00166         $this->rc_cache = array();
00167         $this->rcMoveIndex = 0;
00168         $this->rcCacheIndex = 0;
00169         $this->lastdate = '';
00170         $this->rclistOpen = false;
00171         $this->getOutput()->addModuleStyles( 'mediawiki.special.changeslist' );
00172         return '';
00173     }
00174 
00182     public static function showCharacterDifference( $old, $new, IContextSource $context = null ) {
00183         global $wgRCChangedSizeThreshold, $wgMiserMode;
00184 
00185         if ( !$context ) {
00186             $context = RequestContext::getMain();
00187         }
00188 
00189         $new = (int)$new;
00190         $old = (int)$old;
00191         $szdiff = $new - $old;
00192 
00193         $lang = $context->getLanguage();
00194         $code = $lang->getCode();
00195         static $fastCharDiff = array();
00196         if ( !isset( $fastCharDiff[$code] ) ) {
00197             $fastCharDiff[$code] = $wgMiserMode || $context->msg( 'rc-change-size' )->plain() === '$1';
00198         }
00199 
00200         $formattedSize = $lang->formatNum( $szdiff );
00201 
00202         if ( !$fastCharDiff[$code] ) {
00203             $formattedSize = $context->msg( 'rc-change-size', $formattedSize )->text();
00204         }
00205 
00206         if ( abs( $szdiff ) > abs( $wgRCChangedSizeThreshold ) ) {
00207             $tag = 'strong';
00208         } else {
00209             $tag = 'span';
00210         }
00211 
00212         if ( $szdiff === 0 ) {
00213             $formattedSizeClass = 'mw-plusminus-null';
00214         }
00215         if ( $szdiff > 0 ) {
00216             $formattedSize = '+' . $formattedSize;
00217             $formattedSizeClass = 'mw-plusminus-pos';
00218         }
00219         if ( $szdiff < 0 ) {
00220             $formattedSizeClass = 'mw-plusminus-neg';
00221         }
00222 
00223         $formattedTotalSize = $context->msg( 'rc-change-size-new' )->numParams( $new )->text();
00224 
00225         return Html::element( $tag,
00226             array( 'dir' => 'ltr', 'class' => $formattedSizeClass, 'title' => $formattedTotalSize ),
00227             $context->msg( 'parentheses', $formattedSize )->plain() ) . $lang->getDirMark();
00228     }
00229 
00237     public function formatCharacterDifference( RecentChange $old, RecentChange $new = null ) {
00238         $oldlen = $old->mAttribs['rc_old_len'];
00239 
00240         if ( $new ) {
00241             $newlen = $new->mAttribs['rc_new_len'];
00242         } else {
00243             $newlen = $old->mAttribs['rc_new_len'];
00244         }
00245 
00246         if ( $oldlen === null || $newlen === null ) {
00247             return '';
00248         }
00249 
00250         return self::showCharacterDifference( $oldlen, $newlen, $this->getContext() );
00251     }
00252 
00257     public function endRecentChangesList() {
00258         if ( $this->rclistOpen ) {
00259             return "</ul>\n";
00260         } else {
00261             return '';
00262         }
00263     }
00264 
00269     public function insertDateHeader( &$s, $rc_timestamp ) {
00270         # Make date header if necessary
00271         $date = $this->getLanguage()->userDate( $rc_timestamp, $this->getUser() );
00272         if ( $date != $this->lastdate ) {
00273             if ( $this->lastdate != '' ) {
00274                 $s .= "</ul>\n";
00275             }
00276             $s .= Xml::element( 'h4', null, $date ) . "\n<ul class=\"special\">";
00277             $this->lastdate = $date;
00278             $this->rclistOpen = true;
00279         }
00280     }
00281 
00287     public function insertLog( &$s, $title, $logtype ) {
00288         $page = new LogPage( $logtype );
00289         $logname = $page->getName()->escaped();
00290         $s .= $this->msg( 'parentheses' )->rawParams( Linker::linkKnown( $title, $logname ) )->escaped();
00291     }
00292 
00298     public function insertDiffHist( &$s, &$rc, $unpatrolled ) {
00299         # Diff link
00300         if ( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) {
00301             $diffLink = $this->message['diff'];
00302         } elseif ( !self::userCan( $rc, Revision::DELETED_TEXT, $this->getUser() ) ) {
00303             $diffLink = $this->message['diff'];
00304         } else {
00305             $query = array(
00306                 'curid' => $rc->mAttribs['rc_cur_id'],
00307                 'diff' => $rc->mAttribs['rc_this_oldid'],
00308                 'oldid' => $rc->mAttribs['rc_last_oldid']
00309             );
00310 
00311             $diffLink = Linker::linkKnown(
00312                 $rc->getTitle(),
00313                 $this->message['diff'],
00314                 array( 'tabindex' => $rc->counter ),
00315                 $query
00316             );
00317         }
00318         $diffhist = $diffLink . $this->message['pipe-separator'];
00319         # History link
00320         $diffhist .= Linker::linkKnown(
00321             $rc->getTitle(),
00322             $this->message['hist'],
00323             array(),
00324             array(
00325                 'curid' => $rc->mAttribs['rc_cur_id'],
00326                 'action' => 'history'
00327             )
00328         );
00329         $s .= $this->msg( 'parentheses' )->rawParams( $diffhist )->escaped() . ' <span class="mw-changeslist-separator">. .</span> ';
00330     }
00331 
00338     public function insertArticleLink( &$s, &$rc, $unpatrolled, $watched ) {
00339         $params = array();
00340 
00341         $articlelink = Linker::linkKnown(
00342             $rc->getTitle(),
00343             null,
00344             array( 'class' => 'mw-changeslist-title' ),
00345             $params
00346         );
00347         if ( $this->isDeleted( $rc, Revision::DELETED_TEXT ) ) {
00348             $articlelink = '<span class="history-deleted">' . $articlelink . '</span>';
00349         }
00350         # To allow for boldening pages watched by this user
00351         $articlelink = "<span class=\"mw-title\">{$articlelink}</span>";
00352         # RTL/LTR marker
00353         $articlelink .= $this->getLanguage()->getDirMark();
00354 
00355         wfRunHooks( 'ChangesListInsertArticleLink',
00356             array( &$this, &$articlelink, &$s, &$rc, $unpatrolled, $watched ) );
00357 
00358         $s .= " $articlelink";
00359     }
00360 
00368     public function getTimestamp( $rc ) {
00369         return $this->message['semicolon-separator'] . '<span class="mw-changeslist-date">' .
00370             $this->getLanguage()->userTime( $rc->mAttribs['rc_timestamp'], $this->getUser() ) . '</span> <span class="mw-changeslist-separator">. .</span> ';
00371     }
00372 
00379     public function insertTimestamp( &$s, $rc ) {
00380         $s .= $this->getTimestamp( $rc );
00381     }
00382 
00389     public function insertUserRelatedLinks( &$s, &$rc ) {
00390         if ( $this->isDeleted( $rc, Revision::DELETED_USER ) ) {
00391             $s .= ' <span class="history-deleted">' . $this->msg( 'rev-deleted-user' )->escaped() . '</span>';
00392         } else {
00393             $s .= $this->getLanguage()->getDirMark() . Linker::userLink( $rc->mAttribs['rc_user'],
00394                 $rc->mAttribs['rc_user_text'] );
00395             $s .= Linker::userToolLinks( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] );
00396         }
00397     }
00398 
00405     public function insertLogEntry( $rc ) {
00406         $formatter = LogFormatter::newFromRow( $rc->mAttribs );
00407         $formatter->setContext( $this->getContext() );
00408         $formatter->setShowUserToolLinks( true );
00409         $mark = $this->getLanguage()->getDirMark();
00410         return $formatter->getActionText() . " $mark" . $formatter->getComment();
00411     }
00412 
00418     public function insertComment( $rc ) {
00419         if ( $rc->mAttribs['rc_type'] != RC_MOVE && $rc->mAttribs['rc_type'] != RC_MOVE_OVER_REDIRECT ) {
00420             if ( $this->isDeleted( $rc, Revision::DELETED_COMMENT ) ) {
00421                 return ' <span class="history-deleted">' . $this->msg( 'rev-deleted-comment' )->escaped() . '</span>';
00422             } else {
00423                 return Linker::commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() );
00424             }
00425         }
00426         return '';
00427     }
00428 
00435     public static function usePatrol() {
00436         global $wgUser;
00437 
00438         wfDeprecated( __METHOD__, '1.22' );
00439 
00440         return $wgUser->useRCPatrol();
00441     }
00442 
00447     protected function numberofWatchingusers( $count ) {
00448         static $cache = array();
00449         if ( $count > 0 ) {
00450             if ( !isset( $cache[$count] ) ) {
00451                 $cache[$count] = $this->msg( 'number_of_watching_users_RCview' )->numParams( $count )->escaped();
00452             }
00453             return $cache[$count];
00454         } else {
00455             return '';
00456         }
00457     }
00458 
00465     public static function isDeleted( $rc, $field ) {
00466         return ( $rc->mAttribs['rc_deleted'] & $field ) == $field;
00467     }
00468 
00477     public static function userCan( $rc, $field, User $user = null ) {
00478         if ( $rc->mAttribs['rc_type'] == RC_LOG ) {
00479             return LogEventsList::userCanBitfield( $rc->mAttribs['rc_deleted'], $field, $user );
00480         } else {
00481             return Revision::userCanBitfield( $rc->mAttribs['rc_deleted'], $field, $user );
00482         }
00483     }
00484 
00490     protected function maybeWatchedLink( $link, $watched = false ) {
00491         if ( $watched ) {
00492             return '<strong class="mw-watched">' . $link . '</strong>';
00493         } else {
00494             return '<span class="mw-rc-unwatched">' . $link . '</span>';
00495         }
00496     }
00497 
00503     public function insertRollback( &$s, &$rc ) {
00504         if ( $rc->mAttribs['rc_type'] == RC_EDIT && $rc->mAttribs['rc_this_oldid'] && $rc->mAttribs['rc_cur_id'] ) {
00505             $page = $rc->getTitle();
00508             if ( $this->getUser()->isAllowed( 'rollback' ) && $rc->mAttribs['page_latest'] == $rc->mAttribs['rc_this_oldid'] )
00509             {
00510                 $rev = new Revision( array(
00511                     'title' => $page,
00512                     'id' => $rc->mAttribs['rc_this_oldid'],
00513                     'user' => $rc->mAttribs['rc_user'],
00514                     'user_text' => $rc->mAttribs['rc_user_text'],
00515                     'deleted' => $rc->mAttribs['rc_deleted']
00516                 ) );
00517                 $s .= ' ' . Linker::generateRollback( $rev, $this->getContext() );
00518             }
00519         }
00520     }
00521 
00527     public function insertTags( &$s, &$rc, &$classes ) {
00528         if ( empty( $rc->mAttribs['ts_tags'] ) ) {
00529             return;
00530         }
00531 
00532         list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $rc->mAttribs['ts_tags'], 'changeslist' );
00533         $classes = array_merge( $classes, $newClasses );
00534         $s .= ' ' . $tagSummary;
00535     }
00536 
00537     public function insertExtra( &$s, &$rc, &$classes ) {
00538         // Empty, used for subclasses to add anything special.
00539     }
00540 
00541     protected function showAsUnpatrolled( RecentChange $rc ) {
00542         $unpatrolled = false;
00543         if ( !$rc->mAttribs['rc_patrolled'] ) {
00544             if ( $this->getUser()->useRCPatrol() ) {
00545                 $unpatrolled = true;
00546             } elseif ( $this->getUser()->useNPPatrol() && $rc->mAttribs['rc_type'] == RC_NEW ) {
00547                 $unpatrolled = true;
00548             }
00549         }
00550         return $unpatrolled;
00551     }
00552 }