RCFilters UI: Add 'remove' and 'restore defaults' to filter list

Bug: T144448
Bug: T149391
Change-Id: I418ad6b34ae8a7456a7e66bc703d4dccf36764a5
This commit is contained in:
Moriel Schottlender 2016-12-09 16:18:59 -08:00 committed by Roan Kattouw
parent 0972ef625d
commit dc3a4da2c5
9 changed files with 180 additions and 3 deletions

View file

@ -1360,8 +1360,11 @@
"recentchanges-legend-plusminus": "(<em>±123</em>)",
"recentchanges-submit": "Show",
"rcfilters-activefilters": "Active filters",
"rcfilters-restore-default-filters": "Restore default filters",
"rcfilters-clear-all-filters": "Clear all filters",
"rcfilters-search-placeholder": "Filter recent changes (browse or start typing)",
"rcfilters-invalid-filter": "Invalid filter",
"rcfilters-empty-filter": "No active filters. All contributions are shown.",
"rcfilters-filterlist-title": "Filters",
"rcfilters-filterlist-noresults": "No filters found",
"rcfilters-filtergroup-registration": "User registration",

View file

@ -1546,8 +1546,11 @@
"recentchanges-legend-plusminus": "{{optional}}\nA plus/minus sign with a number for the legend.",
"recentchanges-submit": "Label for submit button in [[Special:RecentChanges]]\n{{Identical|Show}}",
"rcfilters-activefilters": "Title for the filters selection showing the active filters.",
"rcfilters-restore-default-filters": "Label for the button that resets filters to defaults",
"rcfilters-clear-all-filters": "Title for the button that clears all filters",
"rcfilters-search-placeholder": "Placeholder for the filter search input.",
"rcfilters-invalid-filter": "A label for an invalid filter.",
"rcfilters-empty-filter": "Placeholder for the filter list when no filters were chosen.",
"rcfilters-filterlist-title": "Title for the filters list.\n{{Identical|Filter}}",
"rcfilters-filterlist-noresults": "Message showing no results found for searching a filter.",
"rcfilters-filtergroup-registration": "Title for the filter group for editor registration type.",

View file

@ -1756,8 +1756,11 @@ return [
],
'messages' => [
'rcfilters-activefilters',
'rcfilters-restore-default-filters',
'rcfilters-clear-all-filters',
'rcfilters-search-placeholder',
'rcfilters-invalid-filter',
'rcfilters-empty-filter',
'rcfilters-filterlist-title',
'rcfilters-filterlist-noresults',
'rcfilters-filtergroup-registration',
@ -1800,6 +1803,7 @@ return [
'dependencies' => [
'oojs-ui',
'mediawiki.Uri',
'oojs-ui.styles.icons-moderation'
],
],
'mediawiki.special' => [

View file

@ -15,6 +15,7 @@
this.groups = {};
this.excludedByMap = {};
this.defaultParams = {};
this.defaultFiltersEmpty = null;
// Events
this.aggregate( { update: 'filterItemUpdate' } );
@ -431,6 +432,39 @@
return result;
};
/**
* Check whether the current filter state is set to all false.
*
* @return {boolean} Current filters are all empty
*/
mw.rcfilters.dm.FiltersViewModel.prototype.areCurrentFiltersEmpty = function () {
var currFilters = this.getSelectedState();
return Object.keys( currFilters ).every( function ( filterName ) {
return !currFilters[ filterName ];
} );
};
/**
* Check whether the default values of the filters are all false.
*
* @return {boolean} Default filters are all false
*/
mw.rcfilters.dm.FiltersViewModel.prototype.areDefaultFiltersEmpty = function () {
var defaultFilters;
if ( this.defaultFiltersEmpty !== null ) {
// We only need to do this test once,
// because defaults are set once per session
defaultFilters = this.getFiltersFromParameters();
this.defaultFiltersEmpty = Object.keys( defaultFilters ).every( function ( filterName ) {
return !defaultFilters[ filterName ];
} );
}
return this.defaultFiltersEmpty;
};
/**
* This is the opposite of the #getParametersFromFilters method; this goes over
* the given parameters and translates into a selected/unselected value in the filters.
@ -524,6 +558,21 @@
} )[ 0 ];
};
/**
* Set all filters to false or empty/all
* This is equivalent to display all.
*/
mw.rcfilters.dm.FiltersViewModel.prototype.emptyAllFilters = function () {
var filters = {};
this.getItems().forEach( function ( filterItem ) {
filters[ filterItem.getName() ] = false;
} );
// Update filters
this.updateFilters( filters );
};
/**
* Toggle selected state of items by their names
*

View file

@ -27,6 +27,20 @@
);
};
/**
* Reset to default filters
*/
mw.rcfilters.Controller.prototype.resetToDefaults = function () {
this.model.setFiltersToDefaults();
};
/**
* Empty all selected filters
*/
mw.rcfilters.Controller.prototype.emptyFilters = function () {
this.model.emptyAllFilters();
};
/**
* Update the state of a filter
*

View file

@ -8,6 +8,27 @@
opacity: 0.5;
}
&-emptyFilters {
color: #72777d;
}
&-table {
display: table;
width: 100%;
}
&-row {
display: table-row;
}
&-cell {
display: table-cell;
&:last-child {
text-align: right;
}
}
.oo-ui-capsuleItemWidget {
color: #222;
background-color: #fff;

View file

@ -17,7 +17,7 @@
&-popup {
// We have to override OOUI's definition, which is set
// on the inline style of the popup
margin-top: 2em !important;
margin-top: 2.4em !important;
max-width: 650px;
}

View file

@ -5,15 +5,19 @@
* @extends OO.ui.CapsuleMultiselectWidget
*
* @constructor
* @param {mw.rcfilters.Controller} controller RCFilters controller
* @param {mw.rcfilters.dm.FiltersViewModel} model RCFilters view model
* @param {OO.ui.InputWidget} filterInput A filter input that focuses the capsule widget
* @param {Object} config Configuration object
*/
mw.rcfilters.ui.FilterCapsuleMultiselectWidget = function MwRcfiltersUiFilterCapsuleMultiselectWidget( filterInput, config ) {
mw.rcfilters.ui.FilterCapsuleMultiselectWidget = function MwRcfiltersUiFilterCapsuleMultiselectWidget( controller, model, filterInput, config ) {
// Parent
mw.rcfilters.ui.FilterCapsuleMultiselectWidget.parent.call( this, $.extend( {
$autoCloseIgnore: filterInput.$element
}, config ) );
this.controller = controller;
this.model = model;
this.filterInput = filterInput;
this.$content.prepend(
@ -22,13 +26,54 @@
.text( mw.msg( 'rcfilters-activefilters' ) )
);
this.resetButton = new OO.ui.ButtonWidget( {
icon: 'trash',
framed: false,
title: mw.msg( 'rcfilters-clear-all-filters' ),
classes: [ 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-resetButton' ]
} );
this.emptyFilterMessage = new OO.ui.LabelWidget( {
label: mw.msg( 'rcfilters-empty-filter' ),
classes: [ 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-emptyFilters' ]
} );
// Events
this.resetButton.connect( this, { click: 'onResetButtonClick' } );
this.model.connect( this, { itemUpdate: 'onModelItemUpdate' } );
// Add the filterInput as trigger
this.filterInput.$input
.on( 'focus', this.focus.bind( this ) );
// Initialize
this.$content.append( this.emptyFilterMessage.$element );
this.$handle
.append(
// The content and button should appear side by side regardless of how
// wide the button is; the button also changes its width depending
// on language and its state, so the safest way to present both side
// by side is with a table layout
$( '<div>' )
.addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-table' )
.append(
$( '<div>' )
.addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-row' )
.append(
$( '<div>' )
.addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-content' )
.addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-cell' )
.append( this.$content ),
$( '<div>' )
.addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget-cell' )
.append( this.resetButton.$element )
)
)
);
this.$element
.addClass( 'mw-rcfilters-ui-filterCapsuleMultiselectWidget' );
this.reevaluateResetRestoreState();
};
/* Initialization */
@ -46,6 +91,44 @@
/* Methods */
mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onModelItemUpdate = function () {
// Re-evaluate reset state
this.reevaluateResetRestoreState();
};
/**
* Respond to click event on the reset button
*/
mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onResetButtonClick = function () {
if ( this.model.areCurrentFiltersEmpty() ) {
// Reset to default filters
this.controller.resetToDefaults();
} else {
// Reset to have no filters
this.controller.emptyFilters();
}
};
/**
* Reevaluate the restore state for the widget between setting to defaults and clearing all filters
*/
mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.reevaluateResetRestoreState = function () {
var defaultsAreEmpty = this.model.areDefaultFiltersEmpty(),
currFiltersAreEmpty = this.model.areCurrentFiltersEmpty(),
hideResetButton = currFiltersAreEmpty && defaultsAreEmpty;
this.resetButton.setIcon(
currFiltersAreEmpty ? 'history' : 'trash'
);
this.resetButton.setLabel(
currFiltersAreEmpty ? mw.msg( 'rcfilters-restore-default-filters' ) : ''
);
this.resetButton.toggle( !hideResetButton );
this.emptyFilterMessage.toggle( currFiltersAreEmpty );
};
/**
* @inheritdoc
*/

View file

@ -37,7 +37,7 @@
placeholder: mw.msg( 'rcfilters-search-placeholder' )
} );
this.capsule = new mw.rcfilters.ui.FilterCapsuleMultiselectWidget( this.textInput, {
this.capsule = new mw.rcfilters.ui.FilterCapsuleMultiselectWidget( controller, this.model, this.textInput, {
popup: {
$content: this.filterPopup.$element,
classes: [ 'mw-rcfilters-ui-filterWrapperWidget-popup' ]