From: jenkins-bot Date: Fri, 18 Aug 2017 22:01:36 +0000 (+0000) Subject: Merge "Enable RCFilters app on Watchlist" X-Git-Tag: 1.31.0-rc.0~2361 X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=ad2b0c7053a9b33eee5ac7995dbd32128179f4ef;hp=15e60f03985dabc302750d29029e54012dc99e60 Merge "Enable RCFilters app on Watchlist" --- diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 4e162f6ef5..610df45ae7 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -6846,6 +6846,11 @@ $wgStructuredChangeFiltersEnableExperimentalViews = false; */ $wgStructuredChangeFiltersEnableLiveUpdate = false; +/** + * Whether to enable RCFilters app on Special:Watchlist + */ +$wgStructuredChangeFiltersOnWatchlist = false; + /** * Use new page patrolling to check new pages on Special:Newpages */ diff --git a/includes/Preferences.php b/includes/Preferences.php index c74d6e1dce..25f0dbd796 100644 --- a/includes/Preferences.php +++ b/includes/Preferences.php @@ -920,6 +920,9 @@ class Preferences { $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 645fbb288f..52db51aa8e 100644 --- a/includes/specialpage/ChangesListSpecialPage.php +++ b/includes/specialpage/ChangesListSpecialPage.php @@ -553,6 +553,105 @@ abstract class ChangesListSpecialPage extends SpecialPage { 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 @@ abstract class ChangesListSpecialPage extends SpecialPage { * @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 ); } @@ -857,8 +957,6 @@ abstract class ChangesListSpecialPage extends SpecialPage { 'messageKeys' => [], ]; - $context = $this->getContext(); - usort( $this->filterGroups, function ( $a, $b ) { return $b->getPriority() - $a->getPriority(); } ); @@ -1055,9 +1153,7 @@ abstract class ChangesListSpecialPage extends SpecialPage { &$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 @@ abstract class ChangesListSpecialPage extends SpecialPage { ) . "\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 = '
' . $legendHeading . @@ -1305,6 +1400,11 @@ abstract class ChangesListSpecialPage extends SpecialPage { '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 @@ abstract class ChangesListSpecialPage extends SpecialPage { $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 0b48d4081c..4659b9d739 100644 --- a/includes/specials/SpecialRecentchanges.php +++ b/includes/specials/SpecialRecentchanges.php @@ -164,94 +164,12 @@ class SpecialRecentChanges extends ChangesListSpecialPage { 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 + 'wgStructuredChangeFiltersSavedQueriesPreferenceName', + 'rcfilters-saved-queries' ); - $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; } /** @@ -540,8 +458,6 @@ class SpecialRecentChanges extends ChangesListSpecialPage { && $this->getUser()->getOption( 'shownumberswatching' ); $watcherCache = []; - $dbr = $this->getDB(); - $counter = 1; $list = ChangesList::newFromContext( $this->getContext(), $this->filterGroups ); $list->initChangesListRows( $rows ); @@ -636,7 +552,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage { ++$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 @@ class SpecialRecentChanges extends ChangesListSpecialPage { $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 @@ class SpecialRecentChanges extends ChangesListSpecialPage { $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() @@ -785,17 +701,6 @@ class SpecialRecentChanges extends ChangesListSpecialPage { return $extraOpts; } - /** - * Check whether the structured filter UI is enabled - * - * @return bool - */ - protected function isStructuredFilterUiEnabled() { - return $this->getUser()->getOption( - 'rcenhancedfilters' - ); - } - /** * Add page-specific modules. */ @@ -803,10 +708,6 @@ class SpecialRecentChanges extends ChangesListSpecialPage { 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 @@ class SpecialRecentChanges extends ChangesListSpecialPage { $filterGroups = $this->getFilterGroups(); - $context = $this->getContext(); foreach ( $filterGroups as $groupName => $group ) { if ( !$group->isPerGroupRequestParameter() ) { foreach ( $group->getFilters() as $key => $filter ) { @@ -1047,7 +947,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage { [ $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 1d76e36106..088bc1b8b3 100644 --- a/includes/specials/SpecialWatchlist.php +++ b/includes/specials/SpecialWatchlist.php @@ -32,6 +32,8 @@ use Wikimedia\Rdbms\IDatabase; * @ingroup SpecialPage */ class SpecialWatchlist extends ChangesListSpecialPage { + private $maxDays; + public function __construct( $page = 'Watchlist', $restriction = 'viewmywatchlist' ) { parent::__construct( $page, $restriction ); @@ -93,6 +95,20 @@ class SpecialWatchlist extends ChangesListSpecialPage { } 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 @@ class SpecialWatchlist extends ChangesListSpecialPage { $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 @@ class SpecialWatchlist extends ChangesListSpecialPage { $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 @@ class SpecialWatchlist extends ChangesListSpecialPage { } $s = $list->beginRecentChangesList(); + + if ( $this->isStructuredFilterUiEnabled() ) { + $s .= $this->makeLegend(); + } + $userShowHiddenCats = $this->getUser()->getBoolOption( 'showhiddencats' ); $counter = 1; foreach ( $rows as $obj ) { @@ -518,6 +541,24 @@ class SpecialWatchlist extends ChangesListSpecialPage { $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 @@ class SpecialWatchlist extends ChangesListSpecialPage { $days = $this->maxDays; } $timestamp = wfTimestampNow(); - $wlInfo = $this->msg( 'wlnote' )->numParams( $numRows, round( $days * 24 ) )->params( - $lang->userDate( $timestamp, $user ), $lang->userTime( $timestamp, $user ) - )->parse() . "
\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() + ) . "
\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 @@ class SpecialWatchlist extends ChangesListSpecialPage { $nondefaults, $filter->getShowHide(), $filterName, - $opts[$filterName] + $opts[$filterName], + $filter->isFeatureAvailableOnStructuredUi( $this ) ); } } @@ -562,17 +611,19 @@ class SpecialWatchlist extends ChangesListSpecialPage { 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
\n"; - $form .= Html::namespaceSelector( + + $namespaceForm = Html::namespaceSelector( [ 'selected' => $opts['namespace'], 'all' => '', @@ -583,27 +634,66 @@ class SpecialWatchlist extends ChangesListSpecialPage { 'class' => 'namespaceselector', ] ) . "\n"; - $form .= '' . Xml::checkLabel( + $namespaceForm .= '' . Xml::checkLabel( $this->msg( 'invert' )->text(), 'invert', 'nsinvert', $opts['invert'], [ 'title' => $this->msg( 'tooltip-invert' )->text() ] ) . "\n"; - $form .= '' . Xml::checkLabel( + $namespaceForm .= '' . Xml::checkLabel( $this->msg( 'namespace_association' )->text(), 'associated', 'nsassociated', $opts['associated'], [ 'title' => $this->msg( 'tooltip-namespace_association' )->text() ] ) . "\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 @@ class SpecialWatchlist extends ChangesListSpecialPage { function setTopText( FormOptions $opts ) { $nondefaults = $opts->getChangedValues(); - $form = ""; + $form = ''; $user = $this->getUser(); $numItems = $this->countItems(); @@ -692,32 +782,27 @@ class SpecialWatchlist extends ChangesListSpecialPage { $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 '' . Xml::checkLabel( - $this->msg( $message, '' )->text(), - $name, - $name, - (int)$value - ) . ''; + $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 f221b2b81f..65943989f1 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 0085bd6afc..98a628167e 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 701e61d1b2..dba8fe060e 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 = $( '
' ) .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 7bdc2a2f25..e39be6c4db 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 ef296555d8..d5528e1f51 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 ba3ca97af2..28a80cca1c 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 82992fb847..5a64edd636 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(); } };