Go to the documentation of this file.
68 $this->skin = $obj->getSkin();
75 $this->linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
91 if (
Hooks::run(
'FetchChangesList', [ $user, &$sk, &$list, $groups ] ) ) {
114 throw new RuntimeException(
'recentChangesLine should be implemented' );
124 $highlightColorDivs =
'';
125 foreach ( [
'none',
'c1',
'c2',
'c3',
'c4',
'c5' ] as $color ) {
126 $highlightColorDivs .= Html::rawElement(
129 'class' =>
'mw-rcfilters-ui-highlights-color-' . $color,
130 'data-color' => $color
135 return Html::rawElement(
137 [
'class' =>
'mw-rcfilters-ui-highlights' ],
147 $this->watchlist = $value;
163 if ( !isset( $this->message ) ) {
166 'cur',
'diff',
'hist',
'enhancedrc-history',
'last',
'blocklink',
'history',
167 'semicolon-separator',
'pipe-separator' ] as $msg
169 $this->message[$msg] = $this->
msg( $msg )->escaped();
182 foreach ( array_keys( $this->
getConfig()->
get(
'RecentChangesFlags' ) ) as $flag ) {
183 $f .= isset( $flags[$flag] ) && $flags[$flag]
200 $classes = [ self::CSS_CLASS_PREFIX .
'line' ];
201 $logType = $rc->mAttribs[
'rc_log_type'];
204 $classes[] = self::CSS_CLASS_PREFIX .
'log';
205 $classes[] = Sanitizer::escapeClass( self::CSS_CLASS_PREFIX .
'log-' . $logType );
207 $classes[] = self::CSS_CLASS_PREFIX .
'edit';
208 $classes[] = Sanitizer::escapeClass( self::CSS_CLASS_PREFIX .
'ns' .
209 $rc->mAttribs[
'rc_namespace'] .
'-' . $rc->mAttribs[
'rc_title'] );
214 $classes[] = $watched && $rc->mAttribs[
'rc_timestamp'] >= $watched
215 ? self::CSS_CLASS_PREFIX .
'line-watched'
216 : self::CSS_CLASS_PREFIX .
'line-not-watched';
233 $classes[] = Sanitizer::escapeClass( self::CSS_CLASS_PREFIX .
'ns-' .
234 $rc->mAttribs[
'rc_namespace'] );
236 $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
237 $classes[] = Sanitizer::escapeClass(
238 self::CSS_CLASS_PREFIX .
240 ( $nsInfo->isTalk( $rc->mAttribs[
'rc_namespace'] ) ?
'talk' :
'subject' )
243 if ( $this->filterGroups !==
null ) {
244 foreach ( $this->filterGroups as $filterGroup ) {
245 foreach ( $filterGroup->getFilters() as
$filter ) {
246 $filter->applyCssClassIfNeeded( $this, $rc, $classes );
263 static $map = [
'minoredit' =>
'minor',
'botedit' =>
'bot' ];
264 static $flagInfos =
null;
266 if ( is_null( $flagInfos ) ) {
270 $flagInfos[$key][
'letter'] = $value[
'letter'];
271 $flagInfos[$key][
'title'] = $value[
'title'];
273 $flagInfos[$key][
'class'] = $value[
'class'] ?? $key;
280 if ( isset( $map[$flag] ) ) {
284 $info = $flagInfos[$flag];
285 return Html::element(
'abbr', [
286 'class' => $info[
'class'],
296 $this->rc_cache = [];
297 $this->rcMoveIndex = 0;
298 $this->rcCacheIndex = 0;
299 $this->lastdate =
'';
300 $this->rclistOpen =
false;
302 'mediawiki.interface.helpers.styles',
303 'mediawiki.special.changeslist'
306 return '<div class="mw-changeslist">';
313 Hooks::run(
'ChangesListInitRows', [ $this, $rows ] );
333 $szdiff = $new - $old;
337 $code =
$lang->getCode();
338 static $fastCharDiff = [];
339 if ( !isset( $fastCharDiff[$code] ) ) {
340 $fastCharDiff[$code] = $config->get(
'MiserMode' )
341 ||
$context->
msg(
'rc-change-size' )->plain() ===
'$1';
344 $formattedSize =
$lang->formatNum( $szdiff );
346 if ( !$fastCharDiff[$code] ) {
347 $formattedSize =
$context->
msg(
'rc-change-size', $formattedSize )->text();
350 if ( abs( $szdiff ) > abs( $config->get(
'RCChangedSizeThreshold' ) ) ) {
356 if ( $szdiff === 0 ) {
357 $formattedSizeClass =
'mw-plusminus-null';
358 } elseif ( $szdiff > 0 ) {
359 $formattedSize =
'+' . $formattedSize;
360 $formattedSizeClass =
'mw-plusminus-pos';
362 $formattedSizeClass =
'mw-plusminus-neg';
364 $formattedSizeClass .=
' mw-diff-bytes';
366 $formattedTotalSize =
$context->
msg(
'rc-change-size-new' )->numParams( $new )->text();
368 return Html::element( $tag,
369 [
'dir' =>
'ltr',
'class' => $formattedSizeClass,
'title' => $formattedTotalSize ],
370 $formattedSize ) .
$lang->getDirMark();
381 $oldlen = $old->mAttribs[
'rc_old_len'];
384 $newlen = $new->mAttribs[
'rc_new_len'];
386 $newlen = $old->mAttribs[
'rc_new_len'];
389 if ( $oldlen ===
null || $newlen ===
null ) {
401 $out = $this->rclistOpen ?
"</ul>\n" :
'';
420 $date =
$lang->userTimeAndDate( $ts, $user );
421 if ( $rev->
userCan( RevisionRecord::DELETED_TEXT, $user ) ) {
422 $link = MediaWikiServices::getInstance()->getLinkRenderer()->makeKnownLink(
425 [
'class' =>
'mw-changeslist-date' ],
426 [
'oldid' => $rev->
getId() ]
429 $link = htmlspecialchars( $date );
431 if ( $rev->
isDeleted( RevisionRecord::DELETED_TEXT ) ) {
432 $link =
"<span class=\"history-deleted mw-changeslist-date\">$link</span>";
442 # Make date header if necessary
444 if ( $date != $this->lastdate ) {
445 if ( $this->lastdate !=
'' ) {
448 $s .=
Xml::element(
'h4',
null, $date ) .
"\n<ul class=\"special\">";
449 $this->lastdate = $date;
450 $this->rclistOpen =
true;
461 $page =
new LogPage( $logtype );
462 $logname = $page->getName()->setContext( $this->
getContext() )->text();
463 $link = $this->linkRenderer->makeKnownLink(
$title, $logname, [
464 'class' => $useParentheses ?
'' :
'mw-changeslist-links'
466 if ( $useParentheses ) {
467 $s .= $this->
msg(
'parentheses' )->rawParams(
483 $rc->mAttribs[
'rc_type'] ==
RC_NEW ||
484 $rc->mAttribs[
'rc_type'] ==
RC_LOG ||
487 $diffLink = $this->message[
'diff'];
488 } elseif ( !self::userCan( $rc, RevisionRecord::DELETED_TEXT, $this->
getUser() ) ) {
489 $diffLink = $this->message[
'diff'];
492 'curid' => $rc->mAttribs[
'rc_cur_id'],
493 'diff' => $rc->mAttribs[
'rc_this_oldid'],
494 'oldid' => $rc->mAttribs[
'rc_last_oldid']
497 $diffLink = $this->linkRenderer->makeKnownLink(
500 [
'class' =>
'mw-changeslist-diff' ],
505 $histLink = $this->message[
'hist'];
507 $histLink = $this->linkRenderer->makeKnownLink(
510 [
'class' =>
'mw-changeslist-history' ],
512 'curid' => $rc->mAttribs[
'rc_cur_id'],
513 'action' =>
'history'
518 $s .= Html::rawElement(
'div', [
'class' =>
'mw-changeslist-links' ],
519 Html::rawElement(
'span', [], $diffLink ) .
520 Html::rawElement(
'span', [], $histLink )
522 ' <span class="mw-changeslist-separator"></span> ';
534 if ( $rc->getTitle()->isRedirect() ) {
535 $params = [
'redirect' =>
'no' ];
538 $articlelink = $this->linkRenderer->makeLink(
541 [
'class' =>
'mw-changeslist-title' ],
544 if ( $this->
isDeleted( $rc, RevisionRecord::DELETED_TEXT ) ) {
545 $articlelink =
'<span class="history-deleted">' . $articlelink .
'</span>';
547 # To allow for boldening pages watched by this user
548 $articlelink =
"<span class=\"mw-title\">{$articlelink}</span>";
550 $articlelink .= $this->
getLanguage()->getDirMark();
552 # TODO: Deprecate the $s argument, it seems happily unused.
554 # Avoid PHP 7.1 warning from passing $this by reference
555 $changesList = $this;
557 [ &$changesList, &$articlelink, &
$s, &$rc, $unpatrolled, $watched ] );
559 return "{$s} {$articlelink}";
572 return $this->message[
'semicolon-separator'] .
'<span class="mw-changeslist-date">' .
574 $rc->mAttribs[
'rc_timestamp'],
576 ) ) .
'</span> <span class="mw-changeslist-separator"></span> ';
596 if ( $this->
isDeleted( $rc, RevisionRecord::DELETED_USER ) ) {
597 $s .=
' <span class="history-deleted">' .
598 $this->
msg(
'rev-deleted-user' )->escaped() .
'</span>';
601 $rc->mAttribs[
'rc_user_text'] );
603 $rc->mAttribs[
'rc_user'], $rc->mAttribs[
'rc_user_text'],
620 $formatter->setContext( $this->
getContext() );
621 $formatter->setShowUserToolLinks(
true );
624 return Html::openElement(
'span', [
'class' =>
'mw-changeslist-log-entry' ] )
625 . $formatter->getActionText() .
" $mark" . $formatter->getComment()
626 . Html::closeElement(
'span' );
635 if ( $this->
isDeleted( $rc, RevisionRecord::DELETED_COMMENT ) ) {
636 return ' <span class="history-deleted comment">' .
637 $this->
msg(
'rev-deleted-comment' )->escaped() .
'</span>';
659 return $this->watchMsgCache->getWithSetCallback(
660 "watching-users-msg:$count",
661 function () use ( $count ) {
662 return $this->
msg(
'number-of-watching-users-for-recent-changes' )
663 ->numParams( $count )->escaped();
675 return ( $rc->mAttribs[
'rc_deleted'] & $field ) == $field;
687 public static function userCan( $rc, $field,
User $user =
null ) {
688 if ( $user ===
null ) {
692 if ( $rc->mAttribs[
'rc_type'] ==
RC_LOG ) {
696 return RevisionRecord::userCanBitfield( $rc->mAttribs[
'rc_deleted'], $field, $user );
706 return '<strong class="mw-watched">' . $link .
'</strong>';
708 return '<span class="mw-rc-unwatched">' . $link .
'</span>';
719 if ( $rc->mAttribs[
'rc_type'] ==
RC_EDIT
720 && $rc->mAttribs[
'rc_this_oldid']
721 && $rc->mAttribs[
'rc_cur_id']
722 && $rc->getAttribute(
'page_latest' ) == $rc->mAttribs[
'rc_this_oldid']
733 'id' => $rc->mAttribs[
'rc_this_oldid'],
734 'user' => $rc->mAttribs[
'rc_user'],
735 'user_text' => $rc->mAttribs[
'rc_user_text'],
736 'actor' => $rc->mAttribs[
'rc_actor'] ??
null,
737 'deleted' => $rc->mAttribs[
'rc_deleted']
762 if ( empty( $rc->mAttribs[
'ts_tags'] ) ) {
767 $rc->mAttribs[
'ts_tags'],
771 $classes = array_merge( $classes, $newClasses );
772 $s .=
' ' . $tagSummary;
802 $isPatrolled = $rc->mAttribs[
'rc_patrolled'];
803 $rcType = $rc->mAttribs[
'rc_type'];
804 $rcLogType = $rc->mAttribs[
'rc_log_type'];
806 $isPatrolled = $rc->rc_patrolled;
807 $rcType = $rc->rc_type;
808 $rcLogType = $rc->rc_log_type;
811 if ( !$isPatrolled ) {
836 return intval( $rcObj->getAttribute(
'rc_type' ) ) ===
RC_CATEGORIZE
837 && intval( $rcObj->getAttribute(
'rc_this_oldid' ) ) === 0;
852 $attrs[
'data-mw-revid'] = $rc->mAttribs[
'rc_this_oldid'];
855 $attrs[
'data-mw-logid'] = $rc->mAttribs[
'rc_logid'];
856 $attrs[
'data-mw-logaction'] =
857 $rc->mAttribs[
'rc_log_type'] .
'/' . $rc->mAttribs[
'rc_log_action'];
861 $attrs[
'data-mw-ts' ] = $rc->
getAttribute(
'rc_timestamp' );
874 $this->changeLinePrefixer = $prefixer;
endRecentChangesList()
Returns text for the end of RC.
getContext()
Get the base IContextSource object.
Marks HTML that shouldn't be escaped.
insertComment( $rc)
Insert a formatted comment.
setWatchlistDivs( $value=true)
Sets the list to use a "<li class='watchlist-(namespace)-(page)'>" tag.
useFilePatrol()
Check whether to enable new files patrol features for this user.
setChangeLinePrefixer(callable $prefixer)
Sets the callable that generates a change line prefix added to the beginning of each line.
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
if(!isset( $args[0])) $lang
Utility class for creating new RC entries.
MapCacheLRU $watchMsgCache
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null, $useParentheses=true)
Generate standard user tool links (talk, contributions, block link, etc.)
maybeWatchedLink( $link, $watched=false)
getTags(RecentChange $rc, array &$classes)
getHighlightsContainerDiv()
Get the container for highlights that are used in the new StructuredFilters system.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
useNPPatrol()
Check whether to enable new pages patrol features for this user.
formatCharacterDifference(RecentChange $old, RecentChange $new=null)
Format the character difference of one or several changes.
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
static isDeleted( $rc, $field)
Determine if said field of a revision is hidden.
insertLog(&$s, $title, $logtype, $useParentheses=true)
insertDateHeader(&$s, $rc_timestamp)
$wgRecentChangesFlags
Flags (letter symbols) shown in recent changes and watchlist to indicate certain types of edits.
msg( $key,... $params)
This is the method for getting translated interface messages.
static generateRollback( $rev, IContextSource $context=null, $options=[ 'verify'])
Generate a rollback link for a given revision.
insertLogEntry( $rc)
Insert a formatted action.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
insertTags(&$s, &$rc, &$classes)
Class to simplify the use of log pages.
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Handles a simple LRU key/value map with a maximum number of entries.
static flag( $flag, IContextSource $context=null)
Make an "<abbr>" element for a given change flag.
insertUserRelatedLinks(&$s, &$rc)
Insert links to user page, user talk page and eventually a blocking link.
setContext(IContextSource $context)
getRollback(RecentChange $rc)
getArticleLink(&$rc, $unpatrolled, $watched)
static newFromContext(IContextSource $context, array $groups=[])
Fetch an appropriate changes list class for the specified context Some users might want to use an enh...
getTitle()
Returns the title of the page associated with this entry.
callable $changeLinePrefixer
getDataAttributes(RecentChange $rc)
Get recommended data attributes for a change line.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
static commentBlock( $comment, $title=null, $local=false, $wikiId=null, $useParentheses=true)
Wrap a comment in standard punctuation and formatting if it's non-empty, otherwise return empty strin...
insertTimestamp(&$s, $rc)
Insert time timestamp string from $rc into $s.
static revDateLink(Revision $rev, User $user, Language $lang, $title=null)
Render the date and time of a revision in the current user language based on whether the user is able...
numberofWatchingusers( $count)
Returns the string which indicates the number of watching users.
showAsUnpatrolled(RecentChange $rc)
static showCharacterDifference( $old, $new, IContextSource $context=null)
Show formatted char difference.
preCacheMessages()
As we use the same small set of messages in various methods and that they are called often,...
static getMain()
Get the RequestContext object associated with the main request.
Interface for objects which can provide a MediaWiki context on request.
getHTMLClasses( $rc, $watched)
Get an array of default HTML class attributes for the change.
__construct( $obj, array $filterGroups=[])
getAttribute( $name)
Get an attribute value.
recentChangesFlags( $flags, $nothing="\u{00A0}")
Returns the appropriate flags for new page, minor change and patrolling.
beginRecentChangesList()
Returns text for the start of the tabular part of RC.
insertDiffHist(&$s, &$rc, $unpatrolled=null)
static userCanBitfield( $bitfield, $field, User $user=null)
Determine if the current user is allowed to view a particular field of this log row,...
initChangesListRows( $rows)
getConfig()
Get the site configuration.
isCategorizationWithoutRevision( $rcObj)
Determines whether a revision is linked to this change; this may not be the case when the categorizat...
getTimestamp( $rc)
Get the timestamp from $rc formatted with current user's settings and a separator.
static isUnpatrolled( $rc, User $user)
The main skin class which provides methods and properties for all other skins.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Internationalisation code.
getHTMLClassesForFilters( $rc)
Get an array of CSS classes attributed to filters for this row.
recentChangesLine(&$rc, $watched=false, $linenumber=null)
Format a line.
static userCan( $rc, $field, User $user=null)
Determine if the current user is allowed to view a particular field of this revision,...
insertExtra(&$s, &$rc, &$classes)
insertRollback(&$s, &$rc)
Insert a rollback link.
userCan( $field, User $user=null)
Determine if the current user is allowed to view a particular field of this revision,...
LinkRenderer $linkRenderer