* @ingroup SpecialPage
*/
class SpecialWatchlist extends ChangesListSpecialPage {
+ protected static $savedQueriesPreferenceName = 'rcfilters-wl-saved-queries';
+
private $maxDays;
public function __construct( $page = 'Watchlist', $restriction = 'viewmywatchlist' ) {
$output->addJsConfigVars( 'wgStructuredChangeFiltersLiveUpdateSupported', false );
$output->addJsConfigVars(
- 'wgStructuredChangeFiltersSavedQueriesPreferenceName',
- 'rcfilters-wl-saved-queries'
+ 'wgStructuredChangeFiltersEditWatchlistUrl',
+ SpecialPage::getTitleFor( 'EditWatchlist' )->getLocalURL()
);
}
}
- protected function isStructuredFilterUiEnabled() {
- return parent::isStructuredFilterUiEnabled()
- && ( $this->getConfig()->get( 'StructuredChangeFiltersOnWatchlist' )
- || $this->getRequest()->getBool( 'rcfilters' ) );
+ public function isStructuredFilterUiEnabled() {
+ return $this->getRequest()->getBool( 'rcfilters' ) || (
+ $this->getConfig()->get( 'StructuredChangeFiltersOnWatchlist' ) &&
+ $this->getUser()->getOption( 'rcenhancedfilters' )
+ );
+ }
+
+ public function isStructuredFilterUiEnabledByDefault() {
+ return $this->getConfig()->get( 'StructuredChangeFiltersOnWatchlist' ) &&
+ $this->getUser()->getDefaultOption( 'rcenhancedfilters' );
}
/**
*/
public function getDefaultOptions() {
$opts = parent::getDefaultOptions();
- $user = $this->getUser();
- $opts->add( 'days', $user->getOption( 'watchlistdays' ), FormOptions::FLOAT );
- $opts->add( 'limit', $user->getIntOption( 'wllimit' ), FormOptions::INT );
+ $opts->add( 'days', $this->getDefaultDays(), FormOptions::FLOAT );
+ $opts->add( 'limit', $this->getDefaultLimit(), FormOptions::INT );
return $opts;
}
$tables = array_merge( [ 'recentchanges', 'watchlist' ], $tables );
$fields = array_merge( RecentChange::selectFields(), $fields );
- $query_options = array_merge( [
- 'ORDER BY' => 'rc_timestamp DESC',
- 'LIMIT' => $opts['limit']
- ], $query_options );
$join_conds = array_merge(
[
'watchlist' => [
], LIST_OR );
}
+ $tagFilter = $opts['tagfilter'] ? explode( '|', $opts['tagfilter'] ) : [];
ChangeTags::modifyDisplayQuery(
$tables,
$fields,
$conds,
$join_conds,
$query_options,
- ''
+ $tagFilter
);
$this->runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts );
return false;
}
+ $orderByAndLimit = [
+ 'ORDER BY' => 'rc_timestamp DESC',
+ 'LIMIT' => $opts['limit']
+ ];
+ if ( in_array( 'DISTINCT', $query_options ) ) {
+ // ChangeTags::modifyDisplayQuery() adds DISTINCT when filtering on multiple tags.
+ // In order to prevent DISTINCT from causing query performance problems,
+ // we have to GROUP BY the primary key. This in turn requires us to add
+ // the primary key to the end of the ORDER BY, and the old ORDER BY to the
+ // start of the GROUP BY
+ $orderByAndLimit['ORDER BY'] = 'rc_timestamp DESC, rc_id DESC';
+ $orderByAndLimit['GROUP BY'] = 'rc_timestamp, rc_id';
+ }
+ // array_merge() is used intentionally here so that hooks can, should
+ // they so desire, override the ORDER BY / LIMIT condition(s)
+ $query_options = array_merge( $orderByAndLimit, $query_options );
+
return $dbr->select(
$tables,
$fields,
'id' => 'mw-watchlist-form'
] );
$form .= Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() );
- $form .= Xml::fieldset(
- $this->msg( 'watchlist-options' )->text(),
- false,
+ $form .= Xml::openElement(
+ 'fieldset',
[ 'id' => 'mw-watchlist-options', 'class' => 'cloptions' ]
);
+ $form .= Xml::element(
+ 'legend', null, $this->msg( 'watchlist-options' )->text()
+ );
if ( !$this->isStructuredFilterUiEnabled() ) {
$form .= $this->makeLegend();
$showUpdatedMarker = $this->getConfig()->get( 'ShowUpdatedMarker' );
// Show watchlist header
- $form .= "<p>";
+ $watchlistHeader = '';
if ( $numItems == 0 ) {
- $form .= $this->msg( 'nowatchlist' )->parse() . "\n";
+ $watchlistHeader = $this->msg( 'nowatchlist' )->parse();
} else {
- $form .= $this->msg( 'watchlist-details' )->numParams( $numItems )->parse() . "\n";
+ $watchlistHeader .= $this->msg( 'watchlist-details' )->numParams( $numItems )->parse() . "\n";
if ( $this->getConfig()->get( 'EnotifWatchlist' )
&& $user->getOption( 'enotifwatchlistpages' )
) {
- $form .= $this->msg( 'wlheader-enotif' )->parse() . "\n";
+ $watchlistHeader .= $this->msg( 'wlheader-enotif' )->parse() . "\n";
}
if ( $showUpdatedMarker ) {
- $form .= $this->msg( 'wlheader-showupdated' )->parse() . "\n";
+ $watchlistHeader .= $this->msg(
+ $this->isStructuredFilterUiEnabled() ?
+ 'rcfilters-watchlist-showupdated' :
+ 'wlheader-showupdated'
+ )->parse() . "\n";
}
}
- $form .= "</p>";
+ $form .= Html::rawElement(
+ 'div',
+ [ 'class' => 'watchlistDetails' ],
+ $watchlistHeader
+ );
if ( $numItems > 0 && $showUpdatedMarker ) {
$form .= Xml::openElement( 'form', [ 'method' => 'post',
}
function getDefaultDays() {
- return $this->getUser()->getIntOption( 'watchlistdays' );
+ return floatval( $this->getUser()->getOption( 'watchlistdays' ) );
}
}