From 232deffd8178c079a855eff15e7704e4bfc63f89 Mon Sep 17 00:00:00 2001 From: Moriel Schottlender Date: Mon, 18 Jun 2018 15:04:47 -0700 Subject: [PATCH] RCFilters: Preserve collapsed state and adjust display When collapsed, make sure we are adjusting the 'min-height' on the 'rcfilters-head' div so that it actually takes the space it should. Make sure the preference of whether the area is collapsed or not is preserved for the user, per RC or WL pages, and that it is loaded properly with the correct minimum height dimensions depending on which state is in the preferences, so to prevent "jump" of the result list after load. Bug: T177206 Change-Id: I82c3042cd1bb85dedcd6b5458b157fed94def808 --- .../preferences/DefaultPreferencesFactory.php | 6 +++ .../specialpage/ChangesListSpecialPage.php | 17 +++++++- includes/specials/SpecialRecentchanges.php | 1 + includes/specials/SpecialWatchlist.php | 1 + languages/i18n/en.json | 2 + languages/i18n/qqq.json | 2 + resources/Resources.php | 2 + .../mw.rcfilters.Controller.js | 12 ++++++ .../mediawiki.rcfilters/mw.rcfilters.init.js | 7 ++- .../styles/mw.rcfilters.less | 13 ++++++ ...filters.ui.FilterTagMultiselectWidget.less | 2 +- ...rcfilters.ui.FilterTagMultiselectWidget.js | 43 +++++++++++-------- .../ui/mw.rcfilters.ui.FilterWrapperWidget.js | 10 ++++- .../ui/mw.rcfilters.ui.MainWrapperWidget.js | 8 +++- 14 files changed, 104 insertions(+), 22 deletions(-) diff --git a/includes/preferences/DefaultPreferencesFactory.php b/includes/preferences/DefaultPreferencesFactory.php index bf6ab4a82c..03e4bdbd20 100644 --- a/includes/preferences/DefaultPreferencesFactory.php +++ b/includes/preferences/DefaultPreferencesFactory.php @@ -1022,6 +1022,12 @@ class DefaultPreferencesFactory implements PreferencesFactory { 'label-message' => 'tog-hideminor', 'section' => 'rc/advancedrc', ]; + $defaultPreferences['rcfilters-rc-collapsed'] = [ + 'type' => 'api', + ]; + $defaultPreferences['rcfilters-wl-collapsed'] = [ + 'type' => 'api', + ]; $defaultPreferences['rcfilters-saved-queries'] = [ 'type' => 'api', ]; diff --git a/includes/specialpage/ChangesListSpecialPage.php b/includes/specialpage/ChangesListSpecialPage.php index 831644ef2f..58944b4ce0 100644 --- a/includes/specialpage/ChangesListSpecialPage.php +++ b/includes/specialpage/ChangesListSpecialPage.php @@ -57,6 +57,12 @@ abstract class ChangesListSpecialPage extends SpecialPage { */ protected static $limitPreferenceName; + /** + * Preference name for collapsing the active filter display. Subclasses should override this. + * @var string + */ + protected static $collapsedPreferenceName; + /** @var string */ protected $rcSubpage; @@ -779,9 +785,13 @@ abstract class ChangesListSpecialPage extends SpecialPage { foreach ( $jsData['messageKeys'] as $key ) { $messages[$key] = $this->msg( $key )->plain(); } - $out->addBodyClasses( 'mw-rcfilters-enabled' ); + $collapsed = $this->getUser()->getBoolOption( static::$collapsedPreferenceName ); + if ( $collapsed ) { + $out->addBodyClasses( 'mw-rcfilters-collapsed' ); + } + $out->addHTML( ResourceLoader::makeInlineScript( ResourceLoader::makeMessageSetScript( $messages ), @@ -790,6 +800,7 @@ abstract class ChangesListSpecialPage extends SpecialPage { ); $out->addJsConfigVars( 'wgStructuredChangeFilters', $jsData['groups'] ); + $out->addJsConfigVars( 'wgStructuredChangeFiltersCollapsedState', $collapsed ); $out->addJsConfigVars( 'wgRCFiltersChangeTags', @@ -818,6 +829,10 @@ abstract class ChangesListSpecialPage extends SpecialPage { 'wgStructuredChangeFiltersDaysPreferenceName', static::$daysPreferenceName ); + $out->addJsConfigVars( + 'wgStructuredChangeFiltersCollapsedPreferenceName', + static::$collapsedPreferenceName + ); $out->addJsConfigVars( 'StructuredChangeFiltersLiveUpdatePollingRate', diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php index bfef5e0363..2496192b2f 100644 --- a/includes/specials/SpecialRecentchanges.php +++ b/includes/specials/SpecialRecentchanges.php @@ -35,6 +35,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage { protected static $savedQueriesPreferenceName = 'rcfilters-saved-queries'; protected static $daysPreferenceName = 'rcdays'; // Use general RecentChanges preference protected static $limitPreferenceName = 'rcfilters-limit'; // Use RCFilters-specific preference + protected static $collapsedPreferenceName = 'rcfilters-rc-collapsed'; private $watchlistFilterGroupDefinition; diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php index ce7fea9c6f..b9543d9bf6 100644 --- a/includes/specials/SpecialWatchlist.php +++ b/includes/specials/SpecialWatchlist.php @@ -35,6 +35,7 @@ class SpecialWatchlist extends ChangesListSpecialPage { protected static $savedQueriesPreferenceName = 'rcfilters-wl-saved-queries'; protected static $daysPreferenceName = 'watchlistdays'; protected static $limitPreferenceName = 'wllimit'; + protected static $collapsedPreferenceName = 'rcfilters-wl-collapsed'; private $maxDays; diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 86a05f0418..139140fa15 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1386,6 +1386,8 @@ "rcfilters-activefilters": "Active filters", "rcfilters-activefilters-hide": "Hide", "rcfilters-activefilters-show": "Show", + "rcfilters-activefilters-hide-tooltip": "Hide Active Filters area", + "rcfilters-activefilters-show-tooltip": "Show Active Filters area", "rcfilters-advancedfilters": "Advanced filters", "rcfilters-limit-title": "Results to show", "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|change|changes}}, $2", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 0b920098ed..ee09e97c13 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -1586,6 +1586,8 @@ "rcfilters-activefilters": "{{doc-important|Translations of this message should not more than 3 cm long, otherwise it will make bad user experiences for potential mobile users.}}\nTitle for the filters selection showing the active filters.", "rcfilters-activefilters-hide": "Label for the button that hides the active filters list and dropdown in [[Special:RecentChanges]].\n{{Identical|Hide}}", "rcfilters-activefilters-show": "Label for the button that shows the active filters list and dropdown in [[Special:RecentChanges]].\n{{Identical|Show}}", + "rcfilters-activefilters-hide-tooltip": "Tooltip for the button that hides the active filters list and dropdown in [[Special:RecentChanges]].", + "rcfilters-activefilters-show-tooltip": "Tooltip for the button that shows the active filters list and dropdown in [[Special:RecentChanges]].", "rcfilters-advancedfilters": "Title for the buttons allowing the user to switch to the various advanced filters views.", "rcfilters-limit-title": "Title for the options to change the number of results shown.", "rcfilters-limit-and-date-label": "Title for the button that opens the operation to control how many results to show and in which time period to search. \n\nParameters: $1 - Number of results shown\n\n$2 - Time period to search. One of {{msg-mw|rcfilters-days-title}} or {{msg-mw|rcfilters-hours-title}} is used as $2\n{{Identical|Change}}", diff --git a/resources/Resources.php b/resources/Resources.php index 69e9a2b74f..b7ecd10c61 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1889,6 +1889,8 @@ return [ 'rcfilters-activefilters', 'rcfilters-activefilters-hide', 'rcfilters-activefilters-show', + 'rcfilters-activefilters-hide-tooltip', + 'rcfilters-activefilters-show-tooltip', 'rcfilters-advancedfilters', 'rcfilters-group-results-by-page', 'rcfilters-limit-title', diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js index cd3f684285..3e900f0dc5 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js @@ -15,6 +15,8 @@ * @cfg {string} savedQueriesPreferenceName Where to save the saved queries * @cfg {string} daysPreferenceName Preference name for the days filter * @cfg {string} limitPreferenceName Preference name for the limit filter + * @cfg {string} collapsedPreferenceName Preference name for collapsing and showing + * the active filters area * @cfg {boolean} [normalizeTarget] Dictates whether or not to go through the * title normalization to separate title subpage/parts into the target= url * parameter @@ -26,6 +28,7 @@ this.savedQueriesPreferenceName = config.savedQueriesPreferenceName; this.daysPreferenceName = config.daysPreferenceName; this.limitPreferenceName = config.limitPreferenceName; + this.collapsedPreferenceName = config.collapsedPreferenceName; this.normalizeTarget = !!config.normalizeTarget; this.requestCounter = {}; @@ -874,6 +877,15 @@ this.updateNumericPreference( 'usenewrc', Number( newValue ) ); }; + /** + * Update the collapsed state value + * + * @param {boolean} isCollapsed Filter area is collapsed + */ + mw.rcfilters.Controller.prototype.updateCollapsedState = function ( isCollapsed ) { + this.updateNumericPreference( this.collapsedPreferenceName, Number( isCollapsed ) ); + }; + /** * Update a numeric preference with a new value * diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js index d181532709..c918df8430 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js @@ -15,6 +15,8 @@ savedQueriesPreferenceName = mw.config.get( 'wgStructuredChangeFiltersSavedQueriesPreferenceName' ), daysPreferenceName = mw.config.get( 'wgStructuredChangeFiltersDaysPreferenceName' ), limitPreferenceName = mw.config.get( 'wgStructuredChangeFiltersLimitPreferenceName' ), + activeFiltersCollapsedName = mw.config.get( 'wgStructuredChangeFiltersCollapsedPreferenceName' ), + initialCollapsedState = mw.config.get( 'wgStructuredChangeFiltersCollapsedState' ), filtersModel = new mw.rcfilters.dm.FiltersViewModel(), changesListModel = new mw.rcfilters.dm.ChangesListViewModel( $initialFieldset ), savedQueriesModel = new mw.rcfilters.dm.SavedQueriesModel( filtersModel ), @@ -25,6 +27,7 @@ savedQueriesPreferenceName: savedQueriesPreferenceName, daysPreferenceName: daysPreferenceName, limitPreferenceName: limitPreferenceName, + collapsedPreferenceName: activeFiltersCollapsedName, normalizeTarget: specialPage === 'Recentchangeslinked' } ); @@ -76,10 +79,12 @@ savedQueriesModel, changesListModel, { + $wrapper: $( 'body' ), $topSection: $topSection, $filtersContainer: $( '.rcfilters-container' ), $changesListContainer: $( '.mw-changeslist, .mw-changeslist-empty' ), - $formContainer: $initialFieldset + $formContainer: $initialFieldset, + collapsed: initialCollapsedState } ); diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less index 11972de06c..c6d8d17d3a 100644 --- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less @@ -6,6 +6,8 @@ @rcfilters-head-min-height: 210px; @rcfilters-head-margin-bottom: 20px; @rcfilters-wl-head-min-height: 270px; +@rcfilters-head-min-height-collapsed: 130px; +@rcfilters-wl-head-min-height-collapsed: 200px; // Corrections for the standard special page .client-js { @@ -24,6 +26,17 @@ min-height: @rcfilters-wl-head-min-height; } + .mw-rcfilters-collapsed { + .rcfilters-head { + min-height: @rcfilters-head-min-height-collapsed; + } + + // On the watchlist, reserve a bit more + &.mw-special-Watchlist .rcfilters-head { + min-height: @rcfilters-wl-head-min-height-collapsed; + } + } + .mw-recentchanges-toplinks { padding-left: 0.5em; diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.FilterTagMultiselectWidget.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.FilterTagMultiselectWidget.less index 83ca2bdeba..a2b3eb7313 100644 --- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.FilterTagMultiselectWidget.less +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.FilterTagMultiselectWidget.less @@ -22,7 +22,7 @@ line-height: normal; } - &-collapsed { + .mw-rcfilters-collapsed & { // Taking from the handle, since border-bottom is set on the // filters view which is hidden when collapsed border-bottom: 1px solid @colorGray10; diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterTagMultiselectWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterTagMultiselectWidget.js index 5df70323cc..96f2f0bfe2 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterTagMultiselectWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterTagMultiselectWidget.js @@ -12,6 +12,9 @@ * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model * @param {Object} config Configuration object * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups + * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general + * system. If not given, falls back to this widget's $element + * @cfg {boolean} [collapsed] Filter area is collapsed */ mw.rcfilters.ui.FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( controller, model, savedQueriesModel, config ) { var rcFiltersRow, @@ -28,8 +31,10 @@ this.model = model; this.queriesModel = savedQueriesModel; this.$overlay = config.$overlay || this.$element; + this.$wrapper = config.$wrapper || this.$element; this.matchingQuery = null; this.currentView = this.model.getCurrentView(); + this.collapsed = false; // Parent mw.rcfilters.ui.FilterTagMultiselectWidget.parent.call( this, $.extend( true, { @@ -90,10 +95,9 @@ this.hideShowButton = new OO.ui.ButtonWidget( { framed: false, flags: [ 'progressive' ], - label: mw.msg( 'rcfilters-activefilters-hide' ), classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-hideshowButton' ] } ); - this.collapsed = false; + this.toggleCollapsed( !!config.collapsed ); if ( !mw.user.isAnon() ) { this.saveQueryButton = new mw.rcfilters.ui.SaveFiltersPopupButtonWidget( @@ -605,23 +609,28 @@ mw.rcfilters.ui.FilterTagMultiselectWidget.prototype.toggleCollapsed = function ( isCollapsed ) { isCollapsed = isCollapsed === undefined ? !this.collapsed : !!isCollapsed; - if ( this.collapsed !== isCollapsed ) { - this.collapsed = isCollapsed; - - if ( isCollapsed ) { - // If we are collapsing, close the menu, in case it was open - // We should make sure the menu closes before the rest of the elements - // are hidden, otherwise there is an unknown error in jQuery as ooui - // sets and unsets properties on the input (which is hidden at that point) - this.menu.toggle( false ); - } - this.input.setDisabled( isCollapsed ); - this.hideShowButton.setLabel( mw.msg( - isCollapsed ? 'rcfilters-activefilters-show' : 'rcfilters-activefilters-hide' - ) ); + this.collapsed = isCollapsed; - this.$element.toggleClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-collapsed', isCollapsed ); + if ( isCollapsed ) { + // If we are collapsing, close the menu, in case it was open + // We should make sure the menu closes before the rest of the elements + // are hidden, otherwise there is an unknown error in jQuery as ooui + // sets and unsets properties on the input (which is hidden at that point) + this.menu.toggle( false ); } + this.input.setDisabled( isCollapsed ); + this.hideShowButton.setLabel( mw.msg( + isCollapsed ? 'rcfilters-activefilters-show' : 'rcfilters-activefilters-hide' + ) ); + this.hideShowButton.setTitle( mw.msg( + isCollapsed ? 'rcfilters-activefilters-show-tooltip' : 'rcfilters-activefilters-hide-tooltip' + ) ); + + // Toggle the wrapper class, so we have min height values correctly throughout + this.$wrapper.toggleClass( 'mw-rcfilters-collapsed', isCollapsed ); + + // Save the state + this.controller.updateCollapsedState( isCollapsed ); }; /** diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js index dba24fc06a..a5a8187a71 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js @@ -13,6 +13,9 @@ * @param {Object} [config] Configuration object * @cfg {Object} [filters] A definition of the filter groups in this list * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups + * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general + * system. If not given, falls back to this widget's $element + * @cfg {boolean} [collapsed] Filter area is collapsed */ mw.rcfilters.ui.FilterWrapperWidget = function MwRcfiltersUiFilterWrapperWidget( controller, model, savedQueriesModel, changesListModel, config @@ -30,12 +33,17 @@ this.queriesModel = savedQueriesModel; this.changesListModel = changesListModel; this.$overlay = config.$overlay || this.$element; + this.$wrapper = config.$wrapper || this.$element; this.filterTagWidget = new mw.rcfilters.ui.FilterTagMultiselectWidget( this.controller, this.model, this.queriesModel, - { $overlay: this.$overlay } + { + $overlay: this.$overlay, + collapsed: config.collapsed, + $wrapper: this.$wrapper + } ); this.liveUpdateButton = new mw.rcfilters.ui.LiveUpdateButtonWidget( diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MainWrapperWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MainWrapperWidget.js index 8002045dc8..eab8499193 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MainWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MainWrapperWidget.js @@ -14,6 +14,9 @@ * @cfg {jQuery} $filtersContainer * @cfg {jQuery} $changesListContainer * @cfg {jQuery} $formContainer + * @cfg {boolean} [collapsed] Filter area is collapsed + * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general + * system. If not given, falls back to this widget's $element */ mw.rcfilters.ui.MainWrapperWidget = function MwRcfiltersUiMainWrapperWidget( controller, model, savedQueriesModel, changesListModel, config @@ -31,6 +34,7 @@ this.$changesListContainer = config.$changesListContainer; this.$formContainer = config.$formContainer; this.$overlay = $( '
' ).addClass( 'mw-rcfilters-ui-overlay' ); + this.$wrapper = config.$wrapper || this.$element; this.savedLinksListWidget = new mw.rcfilters.ui.SavedLinksListWidget( controller, savedQueriesModel, { $overlay: this.$overlay } @@ -42,7 +46,9 @@ savedQueriesModel, changesListModel, { - $overlay: this.$overlay + $overlay: this.$overlay, + $wrapper: this.$wrapper, + collapsed: config.collapsed } ); -- 2.20.1