class ContribsPager extends RangeChronologicalPager {
- public $mDefaultDirection = IndexPager::DIR_DESCENDING;
- public $messages;
- public $target;
- public $namespace = '';
- public $mDb;
- public $preventClickjacking = false;
+ /**
+ * @var string[] Local cache for escaped messages
+ */
+ private $messages;
+
+ /**
+ * @var string User name, or a string describing an IP address range
+ */
+ private $target;
+
+ /**
+ * @var string Set to "newbie" to list contributions from the most recent 1% registered users.
+ * $this->target is ignored then. Defaults to "users".
+ */
+ private $contribs;
+
+ /**
+ * @var string|int A single namespace number, or an empty string for all namespaces
+ */
+ private $namespace = '';
+
+ /**
+ * @var string|false Name of tag to filter, or false to ignore tags
+ */
+ private $tagFilter;
+
+ /**
+ * @var bool Set to true to invert the namespace selection
+ */
+ private $nsInvert;
+
+ /**
+ * @var bool Set to true to show both the subject and talk namespace, no matter which got
+ * selected
+ */
+ private $associated;
+
+ /**
+ * @var bool Set to true to show only deleted revisions
+ */
+ private $deletedOnly;
+
+ /**
+ * @var bool Set to true to show only latest (a.k.a. current) revisions
+ */
+ private $topOnly;
+
+ /**
+ * @var bool Set to true to show only new pages
+ */
+ private $newOnly;
+
+ /**
+ * @var bool Set to true to hide edits marked as minor by the user
+ */
+ private $hideMinor;
+
+ private $preventClickjacking = false;
/** @var IDatabase */
- public $mDbSecondary;
+ private $mDbSecondary;
/**
* @var array
*/
- protected $mParentLens;
+ private $mParentLens;
/**
* @var TemplateParser
*/
- protected $templateParser;
+ private $templateParser;
- function __construct( IContextSource $context, array $options ) {
+ public function __construct( IContextSource $context, array $options ) {
parent::__construct( $context );
$msgs = [
}
$this->getDateRangeCond( $startTimestamp, $endTimestamp );
- // This property on IndexPager is set by $this->getIndexField() in parent::__construct().
- // We need to reassign it here so that it is used when the actual query is ran.
- $this->mIndexField = $this->getIndexField();
-
// Most of this code will use the 'contributions' group DB, which can map to replica DBs
// with extra user based indexes or partioning by user. The additional metadata
// queries should use a regular replica DB since the lookup pattern is not all by user.
$ipRangeConds = $user->isAnon() ? $this->getIpRangeConds( $this->mDb, $this->target ) : null;
if ( $ipRangeConds ) {
$queryInfo['tables'][] = 'ip_changes';
+ /**
+ * These aliases make `ORDER BY rev_timestamp, rev_id` from {@see getIndexField} and
+ * {@see getExtraSortFields} use the replicated `ipc_rev_timestamp` and `ipc_rev_id`
+ * columns from the `ip_changes` table, for more efficient queries.
+ * @see https://phabricator.wikimedia.org/T200259#4832318
+ */
+ $queryInfo['fields'] = array_merge(
+ [
+ 'rev_timestamp' => 'ipc_rev_timestamp',
+ 'rev_id' => 'ipc_rev_id',
+ ],
+ array_diff( $queryInfo['fields'], [
+ 'rev_timestamp',
+ 'rev_id',
+ ] )
+ );
$queryInfo['join_conds']['ip_changes'] = [
'LEFT JOIN', [ 'ipc_rev_id = rev_id' ]
];
}
/**
- * Override of getIndexField() in IndexPager.
- * For IP ranges, it's faster to use the replicated ipc_rev_timestamp
- * on the `ip_changes` table than the rev_timestamp on the `revision` table.
- * @return string Name of field
+ * @return string
*/
public function getIndexField() {
- if ( $this->isQueryableRange( $this->target ) ) {
- return 'ipc_rev_timestamp';
- } else {
- return 'rev_timestamp';
- }
+ // Note this is run via parent::__construct() *before* $this->target is set!
+ return 'rev_timestamp';
+ }
+
+ /**
+ * @return string[]
+ */
+ protected function getExtraSortFields() {
+ // Note this is run via parent::__construct() *before* $this->target is set!
+ return [ 'rev_id' ];
}
protected function doBatchLookups() {
* id then null is returned.
*
* @param object $row
+ * @param Title|null $title
* @return Revision|null
*/
- public function tryToCreateValidRevision( $row ) {
+ public function tryToCreateValidRevision( $row, $title = null ) {
/*
* There may be more than just revision rows. To make sure that we'll only be processing
* revisions here, let's _try_ to build a revision out of our row (without displaying
*/
Wikimedia\suppressWarnings();
try {
- $rev = new Revision( $row );
+ $rev = new Revision( $row, 0, $title );
$validRevision = (bool)$rev->getId();
} catch ( Exception $e ) {
$validRevision = false;
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
- $rev = $this->tryToCreateValidRevision( $row );
+ $page = null;
+ // Create a title for the revision if possible
+ // Rows from the hook may not include title information
+ if ( isset( $row->page_namespace ) && isset( $row->page_title ) ) {
+ $page = Title::newFromRow( $row );
+ }
+ $rev = $this->tryToCreateValidRevision( $row, $page );
if ( $rev ) {
$attribs['data-mw-revid'] = $rev->getId();
- $page = Title::newFromRow( $row );
$link = $linkRenderer->makeLink(
$page,
$page->getPrefixedText(),
}
$lang = $this->getLanguage();
- $comment = $lang->getDirMark() . Linker::revComment( $rev, false, true );
+ $comment = $lang->getDirMark() . Linker::revComment( $rev, false, true, false );
$date = $lang->userTimeAndDate( $row->rev_timestamp, $user );
if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
$d = $linkRenderer->makeKnownLink(
$del .= ' ';
}
- $diffHistLinks = Html::rawElement( 'ul',
- [ 'class' => 'mw-changeslist-link-list' ],
- Html::rawElement( 'li', [], $difftext ) .
- Html::rawElement( 'li', [], $histlink )
+ // While it might be tempting to use a list here
+ // this would result in clutter and slows down navigating the content
+ // in assistive technology.
+ // See https://phabricator.wikimedia.org/T205581#4734812
+ $diffHistLinks = Html::rawElement( 'span',
+ [ 'class' => 'mw-changeslist-links' ],
+ // The spans are needed to ensure the dividing '|' elements are not
+ // themselves styled as links.
+ Html::rawElement( 'span', [], $difftext ) .
+ ' ' . // Space needed for separating two words.
+ Html::rawElement( 'span', [], $histlink )
);
# Tags, if any.