Also re-fetch changes list.
Bug: T153949
Change-Id: Id3d4ea2a4de6074ae1c15cadb74e7a324a39e7ff
mw.rcfilters.dm.FilterItem.prototype.isHighlightSupported = function () {
return !!this.getCssClass();
};
+
+ /**
+ * Check if the filter is currently highlighted
+ *
+ * @return {boolean}
+ */
+ mw.rcfilters.dm.FilterItem.prototype.isHighlighted = function () {
+ return this.isHighlightEnabled() && !!this.getHighlightColor();
+ };
}( mediaWiki ) );
mw.rcfilters.dm.FiltersViewModel.prototype.setFiltersToDefaults = function () {
var defaultFilterStates = this.getFiltersFromParameters( this.getDefaultParams() );
- this.updateFilters( defaultFilterStates );
+ this.toggleFiltersSelected( defaultFilterStates );
};
/**
* are the selected highlight colors.
*/
mw.rcfilters.dm.FiltersViewModel.prototype.getHighlightParameters = function () {
- var result = { highlight: this.isHighlightEnabled() };
+ var result = { highlight: Number( this.isHighlightEnabled() ) };
this.getItems().forEach( function ( filterItem ) {
result[ filterItem.getName() + '_color' ] = filterItem.getHighlightColor();
* @return {boolean} Current filters are all empty
*/
mw.rcfilters.dm.FiltersViewModel.prototype.areCurrentFiltersEmpty = function () {
- var model = this;
-
// Check if there are either any selected items or any items
// that have highlight enabled
return !this.getItems().some( function ( filterItem ) {
- return (
- filterItem.isSelected() ||
- ( model.isHighlightEnabled() && filterItem.getHighlightColor() )
- );
+ return filterItem.isSelected() || filterItem.isHighlighted();
} );
};
* This is equivalent to display all.
*/
mw.rcfilters.dm.FiltersViewModel.prototype.emptyAllFilters = function () {
- var filters = {};
-
this.getItems().forEach( function ( filterItem ) {
- filters[ filterItem.getName() ] = false;
- } );
+ this.toggleFilterSelected( filterItem.getName(), false );
+ }.bind( this ) );
+ };
- // Update filters
- this.updateFilters( filters );
+ /**
+ * Toggle selected state of one item
+ *
+ * @param {string} name Name of the filter item
+ * @param {boolean} [isSelected] Filter selected state
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.toggleFilterSelected = function ( name, isSelected ) {
+ this.getItemByName( name ).toggleSelected( isSelected );
};
/**
*
* @param {Object} filterDef Filter definitions
*/
- mw.rcfilters.dm.FiltersViewModel.prototype.updateFilters = function ( filterDef ) {
- var name, filterItem;
-
- for ( name in filterDef ) {
- filterItem = this.getItemByName( name );
- filterItem.toggleSelected( filterDef[ name ] );
- }
+ mw.rcfilters.dm.FiltersViewModel.prototype.toggleFiltersSelected = function ( filterDef ) {
+ Object.keys( filterDef ).forEach( function ( name ) {
+ this.toggleFilterSelected( name, filterDef[ name ] );
+ }.bind( this ) );
};
/**
* @return {boolean}
*/
mw.rcfilters.dm.FiltersViewModel.prototype.isHighlightEnabled = function () {
- return this.highlightEnabled;
+ return !!this.highlightEnabled;
};
/**
* @param {Object} filterStructure Filter definition and structure for the model
*/
mw.rcfilters.Controller.prototype.initialize = function ( filterStructure ) {
- var uri = new mw.Uri();
-
// Initialize the model
this.filtersModel.initializeFilters( filterStructure );
+ this.updateStateBasedOnUrl();
+ };
+
+ /**
+ * Update filter state (selection and highlighting) based
+ * on current URL and default values.
+ */
+ mw.rcfilters.Controller.prototype.updateStateBasedOnUrl = function () {
+ var uri = new mw.Uri();
// Set filter states based on defaults and URL params
- this.filtersModel.updateFilters(
+ this.filtersModel.toggleFiltersSelected(
this.filtersModel.getFiltersFromParameters(
// Merge defaults with URL params for initialization
$.extend(
this.filtersModel.toggleHighlight( !!uri.query.highlight );
this.filtersModel.getItems().forEach( function ( filterItem ) {
var color = uri.query[ filterItem.getName() + '_color' ];
- if ( !color ) {
- return;
+ if ( color ) {
+ filterItem.setHighlightColor( color );
+ } else {
+ filterItem.clearHighlightColor();
}
-
- filterItem.setHighlightColor( color );
} );
// Check all filter interactions
* @param {boolean} [isSelected] Filter selected state
*/
mw.rcfilters.Controller.prototype.toggleFilterSelect = function ( filterName, isSelected ) {
- var obj = {},
- filterItem = this.filtersModel.getItemByName( filterName );
+ var filterItem = this.filtersModel.getItemByName( filterName );
isSelected = isSelected === undefined ? !filterItem.isSelected() : isSelected;
if ( filterItem.isSelected() !== isSelected ) {
- obj[ filterName ] = isSelected;
- this.filtersModel.updateFilters( obj );
+ this.filtersModel.toggleFilterSelected( filterName, isSelected );
this.updateChangesList();
// Check filter interactions
- this.filtersModel.reassessFilterInteractions( this.filtersModel.getItemByName( filterName ) );
+ this.filtersModel.reassessFilterInteractions( filterItem );
}
};
* @param {Object} [params] Extra parameters to add to the API call
*/
mw.rcfilters.Controller.prototype.updateURL = function ( params ) {
- var uri;
+ var updatedUri,
+ notEquivalent = function ( obj1, obj2 ) {
+ var keys = Object.keys( obj1 ).concat( Object.keys( obj2 ) );
+ return keys.some( function ( key ) {
+ return obj1[ key ] != obj2[ key ]; // eslint-disable-line eqeqeq
+ } );
+ };
params = params || {};
- uri = this.getUpdatedUri();
- uri.extend( params );
+ updatedUri = this.getUpdatedUri();
+ updatedUri.extend( params );
- window.history.pushState( { tag: 'rcfilters' }, document.title, uri.toString() );
+ if ( notEquivalent( updatedUri.query, new mw.Uri().query ) ) {
+ window.history.pushState( { tag: 'rcfilters' }, document.title, updatedUri.toString() );
+ }
};
/**
this.filtersModel.clearHighlightColor( filterName );
this.updateURL();
};
+
+ /**
+ * Clear both highlight and selection of a filter
+ *
+ * @param {string} filterName Name of the filter item
+ */
+ mw.rcfilters.Controller.prototype.clearFilter = function ( filterName ) {
+ var filterItem = this.filtersModel.getItemByName( filterName );
+
+ if ( filterItem.isSelected() || filterItem.isHighlighted() ) {
+ this.filtersModel.clearHighlightColor( filterName );
+ this.filtersModel.toggleFilterSelected( filterName, false );
+ this.updateChangesList();
+ this.filtersModel.reassessFilterInteractions( filterItem );
+ }
+ };
+
+ /**
+ * Synchronize the URL with the current state of the filters
+ * without adding an history entry.
+ */
+ mw.rcfilters.Controller.prototype.replaceUrl = function () {
+ window.history.replaceState(
+ { tag: 'rcfilters' },
+ document.title,
+ this.getUpdatedUri().toString()
+ );
+ };
}( mediaWiki, jQuery ) );
$( '.rcfilters-head' ).addClass( 'mw-rcfilters-ui-ready' );
window.addEventListener( 'popstate', function () {
+ controller.updateStateBasedOnUrl();
controller.updateChangesList();
} );
'href',
'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:New_filters_for_edit_review'
);
+
+ controller.replaceUrl();
}
};
}
// Respond to user removing the filter
- this.controller.toggleFilterSelect( this.model.getName(), false );
- this.controller.clearHighlightColor( this.model.getName() );
+ this.controller.clearFilter( this.model.getName() );
};
mw.rcfilters.ui.CapsuleItemWidget.prototype.setHighlightColor = function () {
'Initial state of filters'
);
- model.updateFilters( {
+ model.toggleFiltersSelected( {
group1filter1: true,
group2filter2: true,
group3filter1: true
);
// Select 1 filter
- model.updateFilters( {
+ model.toggleFiltersSelected( {
hidefilter1: true,
hidefilter2: false,
hidefilter3: false,
);
// Select 2 filters
- model.updateFilters( {
+ model.toggleFiltersSelected( {
hidefilter1: true,
hidefilter2: true,
hidefilter3: false,
);
// Select 3 filters
- model.updateFilters( {
+ model.toggleFiltersSelected( {
hidefilter1: true,
hidefilter2: true,
hidefilter3: true,
);
// Select 1 filter from string_options
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter7: true,
filter8: false,
filter9: false
);
// Select 2 filters from string_options
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter7: true,
filter8: true,
filter9: false
);
// Select 3 filters from string_options
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter7: true,
filter8: true,
filter9: true
// This test is demonstrating wrong usage of the method;
// We should be aware that getFiltersFromParameters is stateless,
// so each call gives us a filter state that only reflects the query given.
- // This means that the two calls to updateFilters() below collide.
+ // This means that the two calls to toggleFiltersSelected() below collide.
// The result of the first is overridden by the result of the second,
// since both get a full state object from getFiltersFromParameters that **only** relates
// to the input it receives.
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
hidefilter1: '1'
} )
);
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
hidefilter6: '1'
} )
);
- // The result here is ignoring the first updateFilters call
+ // The result here is ignoring the first toggleFiltersSelected call
// We should receive default values + hidefilter6 as false
assert.deepEqual(
model.getSelectedState(),
model = new mw.rcfilters.dm.FiltersViewModel();
model.initializeFilters( definition );
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
hidefilter1: '0'
} )
);
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
hidefilter1: '1'
} )
'After checking and then unchecking a \'send_unselected_if_any\' filter (without touching other filters in that group), results are default'
);
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
group3: 'filter7'
} )
'A \'string_options\' parameter containing 1 value, results in the corresponding filter as checked'
);
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
group3: 'filter7,filter8'
} )
'A \'string_options\' parameter containing 2 values, results in both corresponding filters as checked'
);
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
group3: 'filter7,filter8,filter9'
} )
'A \'string_options\' parameter containing all values, results in all filters of the group as unchecked.'
);
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
group3: 'filter7,all,filter9'
} )
'A \'string_options\' parameter containing the value \'all\', results in all filters of the group as unchecked.'
);
- model.updateFilters(
+ model.toggleFiltersSelected(
model.getFiltersFromParameters( {
group3: 'filter7,foo,filter9'
} )
'Initial state: default filters are not selected (controller selects defaults explicitly).'
);
- model.updateFilters( {
+ model.toggleFiltersSelected( {
hidefilter1: false,
hidefilter3: false
} );
model.initializeFilters( definition );
// Select a filter that has subset with another filter
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter1: true
} );
);
// Select another filter that has a subset with the same previous filter
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter4: true
} );
model.reassessFilterInteractions( model.getItemByName( 'filter4' ) );
);
// Remove one filter (but leave the other) that affects filter2
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter1: false
} );
model.reassessFilterInteractions( model.getItemByName( 'filter1' ) );
'Removing a filter only un-includes its subset if there is no other filter affecting.'
);
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter4: false
} );
model.reassessFilterInteractions( model.getItemByName( 'filter4' ) );
);
// Select most (but not all) items in each group
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter1: true,
filter2: true,
filter4: true,
);
// Select all items in 'fullCoverage' group (group2)
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter6: true
} );
);
// Select all items in non 'fullCoverage' group (group1)
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter3: true
} );
);
// Uncheck an item from each group
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter3: false,
filter5: false
} );
);
// Select a filter that has a conflict with another
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter1: true // conflicts: filter2, filter4
} );
);
// Select one of the conflicts (both filters are now conflicted and selected)
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter4: true // conflicts: filter 1
} );
model.reassessFilterInteractions( model.getItemByName( 'filter4' ) );
// Select another filter from filter4 group, meaning:
// now filter1 no longer conflicts with filter4
- model.updateFilters( {
+ model.toggleFiltersSelected( {
filter6: true // conflicts: filter2
} );
model.reassessFilterInteractions( model.getItemByName( 'filter6' ) );