jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/372187 )
Change subject: Enable RCFilters app on Watchlist
......................................................................
Enable RCFilters app on Watchlist
* Add classes prefixed with cl (for ChangesList)
to both RC and WL so that the JS app can locate
similar elements using the same selectors
* Make saved queries preference name configurable
so that RC and WL use different preferences
* Move some code from SpecialRecentchanges.php to
its base class so it's accessible to SpecialWatchlist.php
To use the RCFilters app on WL, append ?rcfilters=1 to the URL
Bug: T171132
Bug: T171218
Change-Id: If7c63284224df24fa02022b4ea74bef116f28ca6
---
M includes/DefaultSettings.php
M includes/Preferences.php
M includes/specialpage/ChangesListSpecialPage.php
M includes/specials/SpecialRecentchanges.php
M includes/specials/SpecialWatchlist.php
M resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
M resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
M resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
M resources/src/mediawiki.rcfilters/mw.rcfilters.js
M resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
M
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
M resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
12 files changed, 310 insertions(+), 183 deletions(-)
Approvals:
Catrope: Looks good to me, approved
jenkins-bot: Verified
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 4e162f6..610df45 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -6847,6 +6847,11 @@
$wgStructuredChangeFiltersEnableLiveUpdate = false;
/**
+ * Whether to enable RCFilters app on Special:Watchlist
+ */
+$wgStructuredChangeFiltersOnWatchlist = false;
+
+/**
* Use new page patrolling to check new pages on Special:Newpages
*/
$wgUseNPPatrol = true;
diff --git a/includes/Preferences.php b/includes/Preferences.php
index c74d6e1..25f0dbd 100644
--- a/includes/Preferences.php
+++ b/includes/Preferences.php
@@ -920,6 +920,9 @@
$defaultPreferences['rcfilters-saved-queries'] = [
'type' => 'api',
];
+ $defaultPreferences['rcfilters-wl-saved-queries'] = [
+ 'type' => 'api',
+ ];
$defaultPreferences['rcfilters-rclimit'] = [
'type' => 'api',
];
diff --git a/includes/specialpage/ChangesListSpecialPage.php
b/includes/specialpage/ChangesListSpecialPage.php
index 645fbb2..52db51a 100644
--- a/includes/specialpage/ChangesListSpecialPage.php
+++ b/includes/specialpage/ChangesListSpecialPage.php
@@ -553,6 +553,105 @@
LoggerFactory::getInstance( 'objectcache' )
) );
}
+
+ $this->includeRcFiltersApp();
+ }
+
+ /**
+ * Include the modules and configuration for the RCFilters app.
+ * Conditional on the user having the feature enabled.
+ */
+ protected function includeRcFiltersApp() {
+ if ( $this->isStructuredFilterUiEnabled() ) {
+ $out = $this->getOutput();
+ $jsData = $this->getStructuredFilterJsData();
+
+ $messages = [];
+ foreach ( $jsData['messageKeys'] as $key ) {
+ $messages[$key] = $this->msg( $key )->plain();
+ }
+
+ $out->addHTML(
+ ResourceLoader::makeInlineScript(
+ ResourceLoader::makeMessageSetScript(
$messages )
+ )
+ );
+
+ $experimentalStructuredChangeFilters =
+ $this->getConfig()->get(
'StructuredChangeFiltersEnableExperimentalViews' );
+
+ $out->addJsConfigVars( 'wgStructuredChangeFilters',
$jsData['groups'] );
+ $out->addJsConfigVars(
+
'wgStructuredChangeFiltersEnableExperimentalViews',
+ $experimentalStructuredChangeFilters
+ );
+ $out->addJsConfigVars(
+ 'wgStructuredChangeFiltersEnableLiveUpdate',
+ $this->getConfig()->get(
'StructuredChangeFiltersEnableLiveUpdate' )
+ );
+ $out->addJsConfigVars(
+ 'wgRCFiltersChangeTags',
+ $this->buildChangeTagList()
+ );
+ $out->addJsConfigVars(
+ 'StructuredChangeFiltersDisplayConfig',
+ [
+ 'maxDays' =>
(int)$this->getConfig()->get( 'RCMaxAge' ) / ( 24 * 3600 ), // Translate to days
+ 'limitArray' =>
$this->getConfig()->get( 'RCLinkLimits' ),
+ 'daysArray' => $this->getConfig()->get(
'RCLinkDays' ),
+ ]
+ );
+ }
+ }
+
+ /**
+ * 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 );
+
+ // Hit counts disabled for perf reasons, see T169997
+ /*
+ $tagStats = ChangeTags::tagUsageStatistics();
+ $tagHitCounts = array_merge( $explicitlyDefinedTags,
$softwareActivatedTags, $tagStats );
+
+ // Sort by hits
+ arsort( $tagHitCounts );
+ */
+ $tagHitCounts = array_merge( $explicitlyDefinedTags,
$softwareActivatedTags );
+
+ // 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,
+ ];
+ }
+ }
+
+ // Instead of sorting by hit count (disabled, see above), sort
by display name
+ usort( $result, function ( $a, $b ) {
+ return strcasecmp( $a['label'], $b['label'] );
+ } );
+
+ return $result;
}
/**
@@ -779,19 +878,20 @@
* @return FormOptions
*/
public function getDefaultOptions() {
- $config = $this->getConfig();
$opts = new FormOptions();
- $structuredUI = $this->getUser()->getOption(
'rcenhancedfilters' );
+ $structuredUI = $this->isStructuredFilterUiEnabled();
// If urlversion=2 is set, ignore the filter defaults and set
them all to false/empty
$useDefaults = $this->getRequest()->getInt( 'urlversion' ) !==
2;
// Add all filters
+ /** @var ChangesListFilterGroup $filterGroup */
foreach ( $this->filterGroups as $filterGroup ) {
// URL parameters can be per-group, like 'userExpLevel',
// or per-filter, like 'hideminor'.
if ( $filterGroup->isPerGroupRequestParameter() ) {
$opts->add( $filterGroup->getName(),
$useDefaults ? $filterGroup->getDefault() : '' );
} else {
+ /** @var ChangesListBooleanFilter $filter */
foreach ( $filterGroup->getFilters() as $filter
) {
$opts->add( $filter->getName(),
$useDefaults ? $filter->getDefault( $structuredUI ) : false );
}
@@ -856,8 +956,6 @@
'groups' => [],
'messageKeys' => [],
];
-
- $context = $this->getContext();
usort( $this->filterGroups, function ( $a, $b ) {
return $b->getPriority() - $a->getPriority();
@@ -1055,9 +1153,7 @@
&$join_conds, FormOptions $opts
) {
$dbr = $this->getDB();
- $user = $this->getUser();
- $context = $this->getContext();
foreach ( $this->filterGroups as $filterGroup ) {
// URL parameters can be per-group, like 'userExpLevel',
// or per-filter, like 'hideminor'.
@@ -1279,12 +1375,11 @@
) . "\n";
$legend .= Html::closeElement( 'dl' ) . "\n";
- # Collapsibility
- $legendHeading = $this->getUser()->getOption(
- 'rcenhancedfilters'
- ) ?
+ $legendHeading = $this->isStructuredFilterUiEnabled() ?
$context->msg( 'rcfilters-legend-heading' )->parse() :
$context->msg( 'recentchanges-legend-heading'
)->parse();
+
+ # Collapsible
$legend =
'<div class="mw-changeslist-legend">' .
$legendHeading .
@@ -1305,6 +1400,11 @@
'mediawiki.special.changeslist',
] );
$out->addModules( 'mediawiki.special.changeslist.legend.js' );
+
+ if ( $this->isStructuredFilterUiEnabled() ) {
+ $out->addModules( 'mediawiki.rcfilters.filters.ui' );
+ $out->addModuleStyles(
'mediawiki.rcfilters.filters.base.styles' );
+ }
}
protected function getGroupName() {
@@ -1426,4 +1526,13 @@
$conds[] = reset( $conditions );
}
}
+
+ /**
+ * Check whether the structured filter UI is enabled
+ *
+ * @return bool
+ */
+ protected function isStructuredFilterUiEnabled() {
+ return $this->getUser()->getOption( 'rcenhancedfilters' );
+ }
}
diff --git a/includes/specials/SpecialRecentchanges.php
b/includes/specials/SpecialRecentchanges.php
index 0b48d40..4659b9d 100644
--- a/includes/specials/SpecialRecentchanges.php
+++ b/includes/specials/SpecialRecentchanges.php
@@ -164,94 +164,12 @@
parent::execute( $subpage );
if ( $this->isStructuredFilterUiEnabled() ) {
- $jsData = $this->getStructuredFilterJsData();
-
- $messages = [];
- foreach ( $jsData['messageKeys'] as $key ) {
- $messages[$key] = $this->msg( $key )->plain();
- }
-
- $out->addHTML(
- ResourceLoader::makeInlineScript(
- ResourceLoader::makeMessageSetScript(
$messages )
- )
- );
-
- $experimentalStructuredChangeFilters =
- $this->getConfig()->get(
'StructuredChangeFiltersEnableExperimentalViews' );
-
- $out->addJsConfigVars( 'wgStructuredChangeFilters',
$jsData['groups'] );
+ $out->addJsConfigVars(
'wgStructuredChangeFiltersLiveUpdateSupported', true );
$out->addJsConfigVars(
-
'wgStructuredChangeFiltersEnableExperimentalViews',
- $experimentalStructuredChangeFilters
- );
- $out->addJsConfigVars(
- 'wgStructuredChangeFiltersEnableLiveUpdate',
- $this->getConfig()->get(
'StructuredChangeFiltersEnableLiveUpdate' )
- );
- $out->addJsConfigVars(
- 'wgRCFiltersChangeTags',
- $this->buildChangeTagList()
- );
- $out->addJsConfigVars(
- 'StructuredChangeFiltersDisplayConfig',
- [
- 'maxDays' =>
(int)$this->getConfig()->get( 'RCMaxAge' ) / ( 24 * 3600 ), // Translate to days
- 'limitArray' =>
$this->getConfig()->get( 'RCLinkLimits' ),
- 'daysArray' => $this->getConfig()->get(
'RCLinkDays' ),
- ]
+
'wgStructuredChangeFiltersSavedQueriesPreferenceName',
+ 'rcfilters-saved-queries'
);
}
- }
-
- /**
- * 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 );
-
- // Hit counts disabled for perf reasons, see T169997
- /*
- $tagStats = ChangeTags::tagUsageStatistics();
- $tagHitCounts = array_merge( $explicitlyDefinedTags,
$softwareActivatedTags, $tagStats );
-
- // Sort by hits
- arsort( $tagHitCounts );
- */
- $tagHitCounts = array_merge( $explicitlyDefinedTags,
$softwareActivatedTags );
-
- // 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,
- ];
- }
- }
-
- // Instead of sorting by hit count (disabled, see above), sort
by display name
- usort( $result, function ( $a, $b ) {
- return strcasecmp( $a['label'], $b['label'] );
- } );
-
- return $result;
}
/**
@@ -540,8 +458,6 @@
&& $this->getUser()->getOption( 'shownumberswatching' );
$watcherCache = [];
- $dbr = $this->getDB();
-
$counter = 1;
$list = ChangesList::newFromContext( $this->getContext(),
$this->filterGroups );
$list->initChangesListRows( $rows );
@@ -636,7 +552,7 @@
++$count;
$addSubmit = ( $count === $extraOptsCount ) ? $submit :
'';
- $out .= Xml::openElement( 'tr' );
+ $out .= Xml::openElement( 'tr', [ 'class' => $name .
'Form' ] );
if ( is_array( $optionRow ) ) {
$out .= Xml::tags(
'td',
@@ -673,11 +589,11 @@
$rcoptions = Xml::fieldset(
$this->msg( 'recentchanges-legend' )->text(),
$panelString,
- [ 'class' => 'rcoptions' ]
+ [ 'class' => 'rcoptions cloptions' ]
);
// Insert a placeholder for RCFilters
- if ( $this->getUser()->getOption( 'rcenhancedfilters' ) ) {
+ if ( $this->isStructuredFilterUiEnabled() ) {
$rcfilterContainer = Html::element(
'div',
[ 'class' => 'rcfilters-container' ]
@@ -729,7 +645,7 @@
$topLinksAttributes = [ 'class' =>
'mw-recentchanges-toplinks' ];
- if ( $this->getUser()->getOption( 'rcenhancedfilters' )
) {
+ if ( $this->isStructuredFilterUiEnabled() ) {
$contentTitle = Html::rawElement( 'div',
[ 'class' =>
'mw-recentchanges-toplinks-title' ],
$this->msg(
'rcfilters-other-review-tools' )->parse()
@@ -786,27 +702,12 @@
}
/**
- * Check whether the structured filter UI is enabled
- *
- * @return bool
- */
- protected function isStructuredFilterUiEnabled() {
- return $this->getUser()->getOption(
- 'rcenhancedfilters'
- );
- }
-
- /**
* Add page-specific modules.
*/
protected function addModules() {
parent::addModules();
$out = $this->getOutput();
$out->addModules( 'mediawiki.special.recentchanges' );
- if ( $this->isStructuredFilterUiEnabled() ) {
- $out->addModules( 'mediawiki.rcfilters.filters.ui' );
- $out->addModuleStyles(
'mediawiki.rcfilters.filters.base.styles' );
- }
}
/**
@@ -1030,7 +931,6 @@
$filterGroups = $this->getFilterGroups();
- $context = $this->getContext();
foreach ( $filterGroups as $groupName => $group ) {
if ( !$group->isPerGroupRequestParameter() ) {
foreach ( $group->getFilters() as $key =>
$filter ) {
@@ -1047,7 +947,7 @@
[ $key => 1 -
$options[$key] ], $nondefaults );
$attribs = [
- 'class' => "$msg
rcshowhideoption",
+ 'class' => "$msg
rcshowhideoption clshowhideoption",
'data-filter-name' =>
$filter->getName(),
];
diff --git a/includes/specials/SpecialWatchlist.php
b/includes/specials/SpecialWatchlist.php
index 1d76e36..088bc1b 100644
--- a/includes/specials/SpecialWatchlist.php
+++ b/includes/specials/SpecialWatchlist.php
@@ -32,6 +32,8 @@
* @ingroup SpecialPage
*/
class SpecialWatchlist extends ChangesListSpecialPage {
+ private $maxDays;
+
public function __construct( $page = 'Watchlist', $restriction =
'viewmywatchlist' ) {
parent::__construct( $page, $restriction );
@@ -93,6 +95,20 @@
}
parent::execute( $subpage );
+
+ if ( $this->isStructuredFilterUiEnabled() ) {
+ $output->addJsConfigVars(
'wgStructuredChangeFiltersLiveUpdateSupported', false );
+ $output->addJsConfigVars(
+
'wgStructuredChangeFiltersSavedQueriesPreferenceName',
+ 'rcfilters-wl-saved-queries'
+ );
+ }
+ }
+
+ protected function isStructuredFilterUiEnabled() {
+ return parent::isStructuredFilterUiEnabled()
+ && ( $this->getConfig()->get(
'StructuredChangeFiltersOnWatchlist' )
+ || $this->getRequest()->getBool( 'rcfilters' )
);
}
/**
@@ -172,12 +188,14 @@
$opts->add( 'days', $user->getOption( 'watchlistdays' ),
FormOptions::FLOAT );
$opts->add( 'extended', $user->getBoolOption( 'extendwatchlist'
) );
+ $opts->add( 'limit', $user->getIntOption( 'wllimit' ),
FormOptions::INT );
return $opts;
}
public function validateOptions( FormOptions $opts ) {
$opts->validateBounds( 'days', 0, $this->maxDays );
+ $opts->validateIntBounds( 'limit', 0, 5000 );
parent::validateOptions( $opts );
}
@@ -300,7 +318,7 @@
$query_options = array_merge( [
'ORDER BY' => 'rc_timestamp DESC',
- 'LIMIT' => $user->getIntOption( 'wllimit' )
+ 'LIMIT' => $opts['limit']
], $query_options );
$join_conds = array_merge(
[
@@ -458,6 +476,11 @@
}
$s = $list->beginRecentChangesList();
+
+ if ( $this->isStructuredFilterUiEnabled() ) {
+ $s .= $this->makeLegend();
+ }
+
$userShowHiddenCats = $this->getUser()->getBoolOption(
'showhiddencats' );
$counter = 1;
foreach ( $rows as $obj ) {
@@ -518,6 +541,24 @@
$this->setTopText( $opts );
+ $form = '';
+
+ $form .= Xml::openElement( 'form', [
+ 'method' => 'get',
+ 'action' => wfScript(),
+ 'id' => 'mw-watchlist-form'
+ ] );
+ $form .= Html::hidden( 'title',
$this->getPageTitle()->getPrefixedText() );
+ $form .= Xml::fieldset(
+ $this->msg( 'watchlist-options' )->text(),
+ false,
+ [ 'id' => 'mw-watchlist-options', 'class' =>
'cloptions' ]
+ );
+
+ if ( !$this->isStructuredFilterUiEnabled() ) {
+ $form .= $this->makeLegend();
+ }
+
$lang = $this->getLanguage();
if ( $opts['days'] > 0 ) {
$days = $opts['days'];
@@ -525,16 +566,23 @@
$days = $this->maxDays;
}
$timestamp = wfTimestampNow();
- $wlInfo = $this->msg( 'wlnote' )->numParams( $numRows, round(
$days * 24 ) )->params(
- $lang->userDate( $timestamp, $user ), $lang->userTime(
$timestamp, $user )
- )->parse() . "<br />\n";
+ $wlInfo = Html::rawElement(
+ 'span',
+ [ 'class' => 'wlinfo' ],
+ $this->msg( 'wlnote' )->numParams( $numRows, round(
$days * 24 ) )->params(
+ $lang->userDate( $timestamp, $user ),
$lang->userTime( $timestamp, $user )
+ )->parse()
+ ) . "<br />\n";
$nondefaults = $opts->getChangedValues();
- $cutofflinks = $this->msg( 'wlshowtime' ) . ' ' .
$this->cutoffselector( $opts );
+ $cutofflinks = Html::rawElement(
+ 'span',
+ [ 'class' => 'cldays cloption' ],
+ $this->msg( 'wlshowtime' ) . ' ' .
$this->cutoffselector( $opts )
+ );
# Spit out some control panel links
$links = [];
- $context = $this->getContext();
$namesOfDisplayedFilters = [];
foreach ( $this->getFilterGroups() as $groupName => $group ) {
if ( !$group->isPerGroupRequestParameter() ) {
@@ -545,7 +593,8 @@
$nondefaults,
$filter->getShowHide(),
$filterName,
- $opts[$filterName]
+ $opts[$filterName],
+
$filter->isFeatureAvailableOnStructuredUi( $this )
);
}
}
@@ -562,17 +611,19 @@
unset( $hiddenFields[$filterName] );
}
- # Create output
- $form = '';
-
# Namespace filter and put the whole form together.
$form .= $wlInfo;
$form .= $cutofflinks;
- $form .= $this->msg( 'watchlist-hide' ) .
+ $form .= Html::rawElement(
+ 'span',
+ [ 'class' => 'clshowhide' ],
+ $this->msg( 'watchlist-hide' ) .
$this->msg( 'colon-separator' )->escaped() .
- implode( ' ', $links );
+ implode( ' ', $links )
+ );
$form .= "\n<br />\n";
- $form .= Html::namespaceSelector(
+
+ $namespaceForm = Html::namespaceSelector(
[
'selected' => $opts['namespace'],
'all' => '',
@@ -583,27 +634,66 @@
'class' => 'namespaceselector',
]
) . "\n";
- $form .= '<span class="mw-input-with-label">' . Xml::checkLabel(
+ $namespaceForm .= '<span class="mw-input-with-label">' .
Xml::checkLabel(
$this->msg( 'invert' )->text(),
'invert',
'nsinvert',
$opts['invert'],
[ 'title' => $this->msg( 'tooltip-invert' )->text() ]
) . "</span>\n";
- $form .= '<span class="mw-input-with-label">' . Xml::checkLabel(
+ $namespaceForm .= '<span class="mw-input-with-label">' .
Xml::checkLabel(
$this->msg( 'namespace_association' )->text(),
'associated',
'nsassociated',
$opts['associated'],
[ 'title' => $this->msg(
'tooltip-namespace_association' )->text() ]
) . "</span>\n";
- $form .= Xml::submitButton( $this->msg( 'watchlist-submit'
)->text() ) . "\n";
+ $form .= Html::rawElement(
+ 'span',
+ [ 'class' => 'namespaceForm cloption' ],
+ $namespaceForm
+ );
+
+ $form .= Xml::submitButton(
+ $this->msg( 'watchlist-submit' )->text(),
+ [ 'class' => 'cloption-submit' ]
+ ) . "\n";
foreach ( $hiddenFields as $key => $value ) {
$form .= Html::hidden( $key, $value ) . "\n";
}
$form .= Xml::closeElement( 'fieldset' ) . "\n";
$form .= Xml::closeElement( 'form' ) . "\n";
- $this->getOutput()->addHTML( $form );
+
+ // Insert a placeholder for RCFilters
+ if ( $this->isStructuredFilterUiEnabled() ) {
+ $rcfilterContainer = Html::element(
+ 'div',
+ [ 'class' => 'rcfilters-container' ]
+ );
+
+ $loadingContainer = Html::rawElement(
+ 'div',
+ [ 'class' => 'rcfilters-spinner' ],
+ Html::element(
+ 'div',
+ [ 'class' => 'rcfilters-spinner-bounce'
]
+ )
+ );
+
+ // Wrap both with rcfilters-head
+ $this->getOutput()->addHTML(
+ Html::rawElement(
+ 'div',
+ [ 'class' => 'rcfilters-head' ],
+ $rcfilterContainer . $form
+ )
+ );
+
+ // Add spinner
+ $this->getOutput()->addHTML( $loadingContainer );
+ } else {
+ $this->getOutput()->addHTML( $form );
+ }
$this->setBottomText( $opts );
}
@@ -655,7 +745,7 @@
function setTopText( FormOptions $opts ) {
$nondefaults = $opts->getChangedValues();
- $form = "";
+ $form = '';
$user = $this->getUser();
$numItems = $this->countItems();
@@ -692,32 +782,27 @@
$form .= Xml::closeElement( 'form' ) . "\n";
}
- $form .= Xml::openElement( 'form', [
- 'method' => 'get',
- 'action' => wfScript(),
- 'id' => 'mw-watchlist-form'
- ] );
- $form .= Html::hidden( 'title',
$this->getPageTitle()->getPrefixedText() );
- $form .= Xml::fieldset(
- $this->msg( 'watchlist-options' )->text(),
- false,
- [ 'id' => 'mw-watchlist-options' ]
- );
-
- $form .= $this->makeLegend();
-
$this->getOutput()->addHTML( $form );
}
- protected function showHideCheck( $options, $message, $name, $value ) {
+ protected function showHideCheck( $options, $message, $name, $value,
$inStructuredUi ) {
$options[$name] = 1 - (int)$value;
- return '<span class="mw-input-with-label">' . Xml::checkLabel(
- $this->msg( $message, '' )->text(),
- $name,
- $name,
- (int)$value
- ) . '</span>';
+ $attribs = [ 'class' => 'mw-input-with-label clshowhideoption
cloption' ];
+ if ( $inStructuredUi ) {
+ $attribs[ 'data-feature-in-structured-ui' ] = true;
+ }
+
+ return Html::rawElement(
+ 'span',
+ $attribs,
+ Xml::checkLabel(
+ $this->msg( $message, '' )->text(),
+ $name,
+ $name,
+ (int)$value
+ )
+ );
}
/**
diff --git
a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
index f221b2b..6594398 100644
---
a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
+++
b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
@@ -78,7 +78,9 @@
mw.rcfilters.dm.ChangesListViewModel.prototype.update = function (
changesListContent, $fieldset, isInitialDOM, separateOldAndNew ) {
var from = this.nextFrom;
this.valid = true;
- this.extractNextFrom( $fieldset );
+ if ( mw.rcfilters.featureFlags.liveUpdate ) {
+ this.extractNextFrom( $fieldset );
+ }
this.emit( 'update', changesListContent, $fieldset,
isInitialDOM, separateOldAndNew ? from : null );
};
diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
index 0085bd6..98a6281 100644
--- a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
+++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
@@ -8,11 +8,15 @@
* @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view
model
* @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
Changes list view model
* @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved
queries model
+ * @param {Object} config Additional configuration
+ * @cfg {string} savedQueriesPreferenceName Where to save the saved
queries
*/
- mw.rcfilters.Controller = function MwRcfiltersController( filtersModel,
changesListModel, savedQueriesModel ) {
+ mw.rcfilters.Controller = function MwRcfiltersController( filtersModel,
changesListModel, savedQueriesModel, config ) {
this.filtersModel = filtersModel;
this.changesListModel = changesListModel;
this.savedQueriesModel = savedQueriesModel;
+ this.savedQueriesPreferenceName =
config.savedQueriesPreferenceName;
+
this.requestCounter = {};
this.baseFilterState = {};
this.uriProcessor = null;
@@ -209,7 +213,7 @@
);
try {
- parsedSavedQueries = JSON.parse( mw.user.options.get(
'rcfilters-saved-queries' ) || '{}' );
+ parsedSavedQueries = JSON.parse( mw.user.options.get(
this.savedQueriesPreferenceName ) || '{}' );
} catch ( err ) {
parsedSavedQueries = {};
}
@@ -254,7 +258,7 @@
// so it gets processed
this.changesListModel.update(
$changesList.length ? $changesList :
'NO_RESULTS',
- $( 'fieldset.rcoptions' ).first(),
+ $( 'fieldset.cloptions' ).first(),
true // We're using existing DOM elements
);
}
@@ -868,9 +872,9 @@
}
// Save the preference
- new mw.Api().saveOption( 'rcfilters-saved-queries', stringified
);
+ new mw.Api().saveOption( this.savedQueriesPreferenceName,
stringified );
// Update the preference for this session
- mw.user.options.set( 'rcfilters-saved-queries', stringified );
+ mw.user.options.set( this.savedQueriesPreferenceName,
stringified );
};
/**
@@ -1150,23 +1154,31 @@
return $.ajax( uri.toString(), { contentType: 'html' } )
.then(
- // Success
function ( html ) {
- var $parsed;
+ var $parsed,
+ pieces;
+
if ( !latestRequest() ) {
return $.Deferred().reject();
}
$parsed = $( $.parseHTML( html ) );
- return {
+ pieces = {
// Changes list
changes: $parsed.find(
'.mw-changeslist' ).first().contents(),
// Fieldset
- fieldset: $parsed.find(
'fieldset.rcoptions' ).first()
+ fieldset: $parsed.find(
'fieldset.cloptions' ).first()
};
+
+ // Watchlist returns 200 when there is
no results
+ if ( pieces.changes.length === 0 ) {
+ pieces.changes = 'NO_RESULTS';
+ }
+
+ return pieces;
},
- // Failure
+ // RC returns 404 when there is no results
function ( responseObj ) {
var $parsed;
@@ -1179,7 +1191,7 @@
// Force a resolve state to this promise
return $.Deferred().resolve( {
changes: 'NO_RESULTS',
- fieldset: $parsed.find(
'fieldset.rcoptions' ).first()
+ fieldset: $parsed.find(
'fieldset.cloptions' ).first()
} ).promise();
}
);
diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
index 701e61d..dba8fe0 100644
--- a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
+++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
@@ -12,10 +12,16 @@
topLinksCookieName =
'rcfilters-toplinks-collapsed-state',
topLinksCookie = mw.cookie.get(
topLinksCookieName ),
topLinksCookieValue = topLinksCookie ||
'collapsed',
+ savedQueriesPreferenceName = mw.config.get(
'wgStructuredChangeFiltersSavedQueriesPreferenceName' ),
filtersModel = new
mw.rcfilters.dm.FiltersViewModel(),
changesListModel = new
mw.rcfilters.dm.ChangesListViewModel(),
savedQueriesModel = new
mw.rcfilters.dm.SavedQueriesModel(),
- controller = new mw.rcfilters.Controller(
filtersModel, changesListModel, savedQueriesModel ),
+ controller = new mw.rcfilters.Controller(
+ filtersModel, changesListModel,
savedQueriesModel,
+ {
+ savedQueriesPreferenceName:
savedQueriesPreferenceName
+ }
+ ),
$overlay = $( '<div>' )
.addClass( 'mw-rcfilters-ui-overlay' ),
filtersWidget = new
mw.rcfilters.ui.FilterWrapperWidget(
@@ -35,7 +41,7 @@
// eslint-disable-next-line no-new
new mw.rcfilters.ui.FormWrapperWidget(
- filtersModel, changesListModel, controller, $(
'fieldset.rcoptions' ) );
+ filtersModel, changesListModel, controller, $(
'fieldset.cloptions' ) );
$( '.rcfilters-container' ).append(
filtersWidget.$element );
$( 'body' ).append( $overlay );
diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.js
b/resources/src/mediawiki.rcfilters/mw.rcfilters.js
index 7bdc2a2..e39be6c 100644
--- a/resources/src/mediawiki.rcfilters/mw.rcfilters.js
+++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.js
@@ -46,7 +46,8 @@
}
},
featureFlags: {
- liveUpdate: mw.config.get(
'wgStructuredChangeFiltersEnableLiveUpdate' ) || new mw.Uri().query.liveupdate
+ liveUpdate: mw.config.get(
'wgStructuredChangeFiltersLiveUpdateSupported' ) &&
+ ( mw.config.get(
'wgStructuredChangeFiltersEnableLiveUpdate' ) || new mw.Uri().query.liveupdate )
}
};
}( mediaWiki ) );
diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
index ef29655..d5528e1 100644
--- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
+++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
@@ -3,7 +3,7 @@
// Corrections for the standard special page
.client-js {
- .rcoptions {
+ .cloptions {
border: 0;
}
@@ -38,7 +38,7 @@
opacity: 0.5;
pointer-events: none;
- .rcoptions {
+ .cloptions {
display: none;
}
}
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
index ba3ca97..28a80cc 100644
---
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
+++
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
@@ -48,7 +48,9 @@
// Set up highlight containers
this.setupHighlightContainers( this.$element );
- this.setupNewChangesButtonContainer( this.$element );
+ if ( mw.rcfilters.featureFlags.liveUpdate ) {
+ this.setupNewChangesButtonContainer( this.$element );
+ }
};
/* Initialization */
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
index 82992fb..5a64edd 100644
--- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
+++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
@@ -117,9 +117,7 @@
* Clean up the old-style show/hide that we have implemented in the
filter list
*/
mw.rcfilters.ui.FormWrapperWidget.prototype.cleanUpFieldset = function
() {
- var $namespaceSelect = this.$element.find( '#namespace' );
-
- this.$element.find(
'.rcshowhideoption[data-feature-in-structured-ui=1]' ).each( function () {
+ this.$element.find(
'.clshowhideoption[data-feature-in-structured-ui=1]' ).each( function () {
// HACK: Remove the text node after the span.
// If there isn't one, we're at the end, so remove the
text node before the span.
// This would be unnecessary if we added separators
with CSS.
@@ -133,11 +131,11 @@
} );
// Hide namespaces and tags
- $namespaceSelect.closest( 'tr' ).detach();
+ this.$element.find( '.namespaceForm' ).detach();
this.$element.find( '.mw-tagfilter-label' ).closest( 'tr'
).detach();
- // Hide limit and days
- this.$element.find( '.rclinks' ).detach();
+ // misc: limit, days, watchlist info msg
+ this.$element.find( '.rclinks, .cldays, .wlinfo' ).detach();
if ( !this.$element.find( '.mw-recentchanges-table tr' ).length
) {
this.$element.find( '.mw-recentchanges-table'
).detach();
@@ -151,13 +149,17 @@
this.$element.find( 'br' ).detach();
}
+ if ( this.$element.find( '.cloption' ).text().trim() === '' ) {
+ this.$element.find( '.cloption-submit' ).detach();
+ }
+
if ( mw.rcfilters.featureFlags.liveUpdate ) {
this.$element.find(
- 'legend, .rclistfrom, .rcnotefrom,
.rcoptions-listfromreset'
+ '.rclistfrom, .rcnotefrom,
.rcoptions-listfromreset'
).detach();
}
- if ( this.$element.text().trim() === '' ) {
+ if ( this.$element.text().trim() === this.$element.find(
'legend' ).text() ) {
this.$element.detach();
}
};
--
To view, visit https://gerrit.wikimedia.org/r/372187
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: If7c63284224df24fa02022b4ea74bef116f28ca6
Gerrit-PatchSet: 17
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Sbisson <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Florianschmidtwelzow <[email protected]>
Gerrit-Reviewer: Jack Phoenix <[email protected]>
Gerrit-Reviewer: Sbisson <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits