RCFilters UI: Add 'remove' and 'restore defaults' to filter list
Bug: T144448 Bug: T149391 Change-Id: I418ad6b34ae8a7456a7e66bc703d4dccf36764a5
This commit is contained in:
parent
0972ef625d
commit
dc3a4da2c5
9 changed files with 180 additions and 3 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
|
|||
|
|
@ -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' => [
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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' ]
|
||||
|
|
|
|||
Loading…
Reference in a new issue