* @ingroup SpecialPage
*/
class SpecialRecentChanges extends ChangesListSpecialPage {
+
+ private $watchlistFilterGroupDefinition;
+
// @codingStandardsIgnoreStart Needed "useless" override to change parameters.
public function __construct( $name = 'Recentchanges', $restriction = '' ) {
parent::__construct( $name, $restriction );
+
+ $this->watchlistFilterGroupDefinition = [
+ 'name' => 'watchlist',
+ 'title' => 'rcfilters-filtergroup-watchlist',
+ 'class' => ChangesListStringOptionsFilterGroup::class,
+ 'priority' => -9,
+ 'isFullCoverage' => true,
+ 'filters' => [
+ [
+ 'name' => 'watched',
+ 'label' => 'rcfilters-filter-watchlist-watched-label',
+ 'description' => 'rcfilters-filter-watchlist-watched-description',
+ 'cssClassSuffix' => 'watched',
+ 'isRowApplicableCallable' => function ( $ctx, $rc ) {
+ return $rc->getAttribute( 'wl_user' );
+ }
+ ],
+ [
+ 'name' => 'watchednew',
+ 'label' => 'rcfilters-filter-watchlist-watchednew-label',
+ 'description' => 'rcfilters-filter-watchlist-watchednew-description',
+ 'cssClassSuffix' => 'watchednew',
+ 'isRowApplicableCallable' => function ( $ctx, $rc ) {
+ return $rc->getAttribute( 'wl_user' ) &&
+ $rc->getAttribute( 'rc_timestamp' ) &&
+ $rc->getAttribute( 'wl_notificationtimestamp' ) &&
+ $rc->getAttribute( 'rc_timestamp' ) >= $rc->getAttribute( 'wl_notificationtimestamp' );
+ },
+ ],
+ [
+ 'name' => 'notwatched',
+ 'label' => 'rcfilters-filter-watchlist-notwatched-label',
+ 'description' => 'rcfilters-filter-watchlist-notwatched-description',
+ 'cssClassSuffix' => 'notwatched',
+ 'isRowApplicableCallable' => function ( $ctx, $rc ) {
+ return $rc->getAttribute( 'wl_user' ) === null;
+ },
+ ]
+ ],
+ 'default' => ChangesListStringOptionsFilterGroup::NONE,
+ 'queryCallable' => function ( $specialPageClassName, $context, $dbr,
+ &$tables, &$fields, &$conds, &$query_options, &$join_conds, $selectedValues ) {
+ sort( $selectedValues );
+ $notwatchedCond = 'wl_user IS NULL';
+ $watchedCond = 'wl_user IS NOT NULL';
+ $newCond = 'rc_timestamp >= wl_notificationtimestamp';
+
+ if ( $selectedValues === [ 'notwatched' ] ) {
+ $conds[] = $notwatchedCond;
+ return;
+ }
+
+ if ( $selectedValues === [ 'watched' ] ) {
+ $conds[] = $watchedCond;
+ return;
+ }
+
+ if ( $selectedValues === [ 'watchednew' ] ) {
+ $conds[] = $dbr->makeList( [
+ $watchedCond,
+ $newCond
+ ], LIST_AND );
+ return;
+ }
+
+ if ( $selectedValues === [ 'notwatched', 'watched' ] ) {
+ // no filters
+ return;
+ }
+
+ if ( $selectedValues === [ 'notwatched', 'watchednew' ] ) {
+ $conds[] = $dbr->makeList( [
+ $notwatchedCond,
+ $dbr->makeList( [
+ $watchedCond,
+ $newCond
+ ], LIST_AND )
+ ], LIST_OR );
+ return;
+ }
+
+ if ( $selectedValues === [ 'watched', 'watchednew' ] ) {
+ $conds[] = $watchedCond;
+ return;
+ }
+
+ if ( $selectedValues === [ 'notwatched', 'watched', 'watchednew' ] ) {
+ // no filters
+ return;
+ }
+ }
+ ];
}
// @codingStandardsIgnoreEnd
$jsData = $this->getStructuredFilterJsData();
$messages = [];
- foreach ( $jsData['messageKeys'] as $key ){
+ foreach ( $jsData['messageKeys'] as $key ) {
$messages[$key] = $this->msg( $key )->plain();
}
);
$out->addJsConfigVars( 'wgStructuredChangeFilters', $jsData['groups'] );
+ $out->addJsConfigVars(
+ 'wgStructuredChangeFiltersEnableSaving',
+ $this->getConfig()->get( 'StructuredChangeFiltersEnableSaving' )
+ );
+ $out->addJsConfigVars(
+ 'wgStructuredChangeFiltersEnableExperimentalViews',
+ $this->getConfig()->get( 'StructuredChangeFiltersEnableExperimentalViews' )
+ );
+ $out->addJsConfigVars(
+ 'wgStructuredChangeFiltersEnableLiveUpdate',
+ $this->getConfig()->get( 'StructuredChangeFiltersEnableLiveUpdate' )
+ );
+ $out->addJsConfigVars(
+ 'wgRCFiltersChangeTags',
+ $this->buildChangeTagList()
+ );
}
}
+ /**
+ * Fetch the change tags list for the front end
+ *
+ * @return Array Tag data
+ */
+ protected function buildChangeTagList() {
+ $explicitlyDefinedTags = array_fill_keys( ChangeTags::listExplicitlyDefinedTags(), 0 );
+ $softwareActivatedTags = array_fill_keys( ChangeTags::listSoftwareActivatedTags(), 0 );
+ $tagStats = ChangeTags::tagUsageStatistics();
+
+ $tagHitCounts = array_merge( $explicitlyDefinedTags, $softwareActivatedTags, $tagStats );
+
+ // Sort by hits
+ arsort( $tagHitCounts );
+
+ // Build the list and data
+ $result = [];
+ foreach ( $tagHitCounts as $tagName => $hits ) {
+ if (
+ // Only get active tags
+ isset( $explicitlyDefinedTags[ $tagName ] ) ||
+ isset( $softwareActivatedTags[ $tagName ] )
+ ) {
+ // Parse description
+ $desc = ChangeTags::tagLongDescriptionMessage( $tagName, $this->getContext() );
+
+ $result[] = [
+ 'name' => $tagName,
+ 'label' => Sanitizer::stripAllTags(
+ ChangeTags::tagDescription( $tagName, $this->getContext() )
+ ),
+ 'description' => $desc ? Sanitizer::stripAllTags( $desc->parse() ) : '',
+ 'cssClass' => Sanitizer::escapeClass( 'mw-tag-' . $tagName ),
+ 'hits' => $hits,
+ ];
+ }
+ }
+
+ return $result;
+ }
+
/**
* @inheritdoc
*/
protected function registerFilters() {
parent::registerFilters();
+ if (
+ !$this->including() &&
+ $this->getUser()->isLoggedIn() &&
+ $this->getUser()->isAllowed( 'viewmywatchlist' )
+ ) {
+ $this->registerFiltersFromDefinitions( [ $this->watchlistFilterGroupDefinition ] );
+ $watchlistGroup = $this->getFilterGroup( 'watchlist' );
+ $watchlistGroup->getFilter( 'watched' )->setAsSupersetOf(
+ $watchlistGroup->getFilter( 'watchednew' )
+ );
+ }
+
$user = $this->getUser();
$significance = $this->getFilterGroup( 'significance' );
if ( preg_match( '/^days=(\d+)$/', $bit, $m ) ) {
$opts['days'] = $m[1];
}
- if ( preg_match( '/^namespace=(\d+)$/', $bit, $m ) ) {
+ if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
$opts['namespace'] = $m[1];
}
if ( preg_match( '/^tagfilter=(.*)$/', $bit, $m ) ) {
* @inheritdoc
*/
protected function buildQuery( &$tables, &$fields, &$conds,
- &$query_options, &$join_conds, FormOptions $opts ) {
-
+ &$query_options, &$join_conds, FormOptions $opts
+ ) {
$dbr = $this->getDB();
parent::buildQuery( $tables, $fields, $conds,
$query_options, $join_conds, $opts );
* @inheritdoc
*/
protected function doMainQuery( $tables, $fields, $conds, $query_options,
- $join_conds, FormOptions $opts ) {
-
+ $join_conds, FormOptions $opts
+ ) {
$dbr = $this->getDB();
$user = $this->getUser();
$fields = array_merge( RecentChange::selectFields(), $fields );
// JOIN on watchlist for users
- if ( $user->getId() && $user->isAllowed( 'viewmywatchlist' ) ) {
+ if ( $user->isLoggedIn() && $user->isAllowed( 'viewmywatchlist' ) ) {
$tables[] = 'watchlist';
$fields[] = 'wl_user';
$fields[] = 'wl_notificationtimestamp';
] ];
}
- if ( $user->isAllowed( 'rollback' ) ) {
- $tables[] = 'page';
- $fields[] = 'page_latest';
- $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
- }
+ // JOIN on page, used for 'last revision' filter highlight
+ $tables[] = 'page';
+ $fields[] = 'page_latest';
+ $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
ChangeTags::modifyDisplayQuery(
$tables,
$userShowHiddenCats = $this->getUser()->getBoolOption( 'showhiddencats' );
$rclistOutput = $list->beginRecentChangesList();
+ if ( $this->isStructuredFilterUiEnabled() ) {
+ $rclistOutput .= $this->makeLegend();
+ }
+
foreach ( $rows as $obj ) {
if ( $limit == 0 ) {
break;
$nondefaults = $opts->getChangedValues();
$panel = [];
- $panel[] = $this->makeLegend();
+ if ( !$this->isStructuredFilterUiEnabled() ) {
+ $panel[] = $this->makeLegend();
+ }
$panel[] = $this->optionsPanel( $defaults, $nondefaults, $numRows );
$panel[] = '<hr />';
if ( !$message->isDisabled() ) {
$this->getOutput()->addWikiText(
Html::rawElement( 'div',
- [ 'lang' => $wgContLang->getHtmlCode(), 'dir' => $wgContLang->getDir() ],
+ [
+ 'class' => 'mw-recentchanges-toplinks',
+ 'lang' => $wgContLang->getHtmlCode(),
+ 'dir' => $wgContLang->getDir()
+ ],
"\n" . $message->plain() . "\n"
),
/* $lineStart */ true,
* @return string
*/
function makeOptionsLink( $title, $override, $options, $active = false ) {
- $params = $override + $options;
-
- // T38524: false values have be converted to "0" otherwise
- // wfArrayToCgi() will omit it them.
- foreach ( $params as &$value ) {
- if ( $value === false ) {
- $value = '0';
- }
- }
- unset( $value );
+ $params = $this->convertParamsForLink( $override + $options );
if ( $active ) {
$title = new HtmlArmor( '<strong>' . htmlspecialchars( $title ) . '</strong>' );