model.groups[ group ].title = data.title;
model.groups[ group ].type = data.type;
+ model.groups[ group ].separator = data.separator || '|';
for ( i = 0; i < data.filters.length; i++ ) {
filterItem = new mw.rcfilters.dm.FilterItem( data.filters[ i ].name, {
* @return {Object} Parameter state object
*/
mw.rcfilters.dm.FiltersViewModel.prototype.getParametersFromFilters = function () {
- var i, filterItems, anySelected,
+ var i, filterItems, anySelected, values,
result = {},
groupItems = this.getFilterGroups();
$.each( groupItems, function ( group, data ) {
- if ( data.type === 'send_unselected_if_any' ) {
- filterItems = data.filters;
+ filterItems = data.filters;
+ if ( data.type === 'send_unselected_if_any' ) {
// First, check if any of the items are selected at all.
// If none is selected, we're treating it as if they are
// all false
result[ filterItems[ i ].getName() ] = anySelected ?
Number( !filterItems[ i ].isSelected() ) : 0;
}
+ } else if ( data.type === 'string_options' ) {
+ values = [];
+ for ( i = 0; i < filterItems.length; i++ ) {
+ if ( filterItems[ i ].isSelected() ) {
+ values.push( filterItems[ i ].getName() );
+ }
+ }
+
+ if ( values.length === 0 || values.length === filterItems.length ) {
+ result[ group ] = 'all';
+ } else {
+ result[ group ] = values.join( data.separator );
+ }
+ }
+ } );
+
+ return result;
+ };
+
+ /**
+ * Sanitize value group of a string_option groups type
+ * Remove duplicates and make sure to only use valid
+ * values.
+ *
+ * @param {string} groupName Group name
+ * @param {string[]} valueArray Array of values
+ * @return {string[]} Array of valid values
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.sanitizeStringOptionGroup = function( groupName, valueArray ) {
+ var result = [],
+ validNames = this.groups[ groupName ].filters.map( function ( filterItem ) {
+ return filterItem.getName();
+ } );
+
+ if ( valueArray.indexOf( 'all' ) > -1 ) {
+ // If anywhere in the values there's 'all', we
+ // treat it as if only 'all' was selected.
+ // Example: param=valid1,valid2,all
+ // Result: param=all
+ return [ 'all' ];
+ }
+
+ // Get rid of any dupe and invalid parameter, only output
+ // valid ones
+ // Example: param=valid1,valid2,invalid1,valid1
+ // Result: param=valid1,valid2
+ valueArray.forEach( function ( value ) {
+ if (
+ validNames.indexOf( value ) > -1 &&
+ result.indexOf( value ) === -1
+ ) {
+ result.push( value );
}
} );
* @return {Object} Filter state object
*/
mw.rcfilters.dm.FiltersViewModel.prototype.getFiltersFromParameters = function ( params ) {
- var i, filterItem, allItemsInGroup,
+ var i, filterItem,
groupMap = {},
model = this,
base = this.getParametersFromFilters(),
$.each( params, function ( paramName, paramValue ) {
// Find the filter item
filterItem = model.getItemByName( paramName );
-
// Ignore if no filter item exists
if ( filterItem ) {
groupMap[ filterItem.getGroup() ] = groupMap[ filterItem.getGroup() ] || {};
// Add the relevant filter into the group map
groupMap[ filterItem.getGroup() ].filters = groupMap[ filterItem.getGroup() ].filters || [];
groupMap[ filterItem.getGroup() ].filters.push( filterItem );
+ } else if ( model.groups.hasOwnProperty( paramName ) ) {
+ // This parameter represents a group (values are the filters)
+ // this is equivalent to checking if the group is 'string_options'
+ groupMap[ paramName ] = { filters: model.groups[ paramName ].filters };
}
} );
// Now that we know the groups' selection states, we need to go over
// the filters in the groups and mark their selected states appropriately
$.each( groupMap, function ( group, data ) {
- if ( model.groups[ group ].type === 'send_unselected_if_any' ) {
- allItemsInGroup = model.groups[ group ].filters;
+ var paramValues, filterItem,
+ allItemsInGroup = data.filters;
+ if ( model.groups[ group ].type === 'send_unselected_if_any' ) {
for ( i = 0; i < allItemsInGroup.length; i++ ) {
filterItem = allItemsInGroup[ i ];
// group, which means the state is false
false;
}
+ } else if ( model.groups[ group ].type === 'string_options' ) {
+ paramValues = model.sanitizeStringOptionGroup( group, params[ group ].split( model.groups[ group ].separator ) );
+
+ for ( i = 0; i < allItemsInGroup.length; i++ ) {
+ filterItem = allItemsInGroup[ i ];
+
+ result[ filterItem.getName() ] = (
+ // If it is the word 'all'
+ paramValues.length === 1 && paramValues[ 0 ] === 'all' ||
+ // All values are written
+ paramValues.length === model.groups[ group ].filters.length
+ ) ?
+ // All true (either because all values are written or the term 'all' is written)
+ // is the same as all filters set to false
+ false :
+ // Otherwise, the filter is selected only if it appears in the parameter values
+ paramValues.indexOf( filterItem.getName() ) > -1;
+ }
}
} );
return result;
description: 'Description of Filter 2 in Group 2'
}
]
+ },
+ group3: {
+ title: 'Group 3',
+ type: 'string_options',
+ filters: [
+ {
+ name: 'group3filter1',
+ label: 'Group 3: Filter 1',
+ description: 'Description of Filter 1 in Group 3'
+ },
+ {
+ name: 'group3filter2',
+ label: 'Group 3: Filter 2',
+ description: 'Description of Filter 2 in Group 3'
+ }
+ ]
}
},
model = new mw.rcfilters.dm.FiltersViewModel();
model.getItemByName( 'group1filter1' ) instanceof mw.rcfilters.dm.FilterItem &&
model.getItemByName( 'group1filter2' ) instanceof mw.rcfilters.dm.FilterItem &&
model.getItemByName( 'group2filter1' ) instanceof mw.rcfilters.dm.FilterItem &&
- model.getItemByName( 'group2filter2' ) instanceof mw.rcfilters.dm.FilterItem,
+ model.getItemByName( 'group2filter2' ) instanceof mw.rcfilters.dm.FilterItem &&
+ model.getItemByName( 'group3filter1' ) instanceof mw.rcfilters.dm.FilterItem &&
+ model.getItemByName( 'group3filter2' ) instanceof mw.rcfilters.dm.FilterItem,
'Filters instantiated and stored correctly'
);
group1filter1: false,
group1filter2: false,
group2filter1: false,
- group2filter2: false
+ group2filter2: false,
+ group3filter1: false,
+ group3filter2: false
},
'Initial state of filters'
);
model.updateFilters( {
group1filter1: true,
- group2filter2: true
+ group2filter2: true,
+ group3filter1: true
} );
assert.deepEqual(
model.getState(),
group1filter1: true,
group1filter2: false,
group2filter1: false,
- group2filter2: true
+ group2filter2: true,
+ group3filter1: true,
+ group3filter2: false
},
'Updating filter states correctly'
);
description: 'Description of Filter 3 in Group 2'
}
]
+ },
+ group3: {
+ title: 'Group 3',
+ type: 'string_options',
+ separator: ',',
+ filters: [
+ {
+ name: 'filter7',
+ label: 'Group 3: Filter 1',
+ description: 'Description of Filter 1 in Group 3'
+ },
+ {
+ name: 'filter8',
+ label: 'Group 3: Filter 2',
+ description: 'Description of Filter 2 in Group 3'
+ },
+ {
+ name: 'filter9',
+ label: 'Group 3: Filter 3',
+ description: 'Description of Filter 3 in Group 3'
+ }
+ ]
}
},
model = new mw.rcfilters.dm.FiltersViewModel();
hidefilter3: 0,
hidefilter4: 0,
hidefilter5: 0,
- hidefilter6: 0
+ hidefilter6: 0,
+ group3: 'all',
},
- 'Unselected filters return all parameters falsey.'
+ 'Unselected filters return all parameters falsey or \'all\'.'
);
// Select 1 filter
// Group 2 (nothing is selected, all false)
hidefilter4: 0,
hidefilter5: 0,
- hidefilter6: 0
+ hidefilter6: 0,
+ group3: 'all'
},
'One filters in one "send_unselected_if_any" group returns the other parameters truthy.'
);
// Group 2 (nothing is selected, all false)
hidefilter4: 0,
hidefilter5: 0,
- hidefilter6: 0
+ hidefilter6: 0,
+ group3: 'all'
},
'One filters in one "send_unselected_if_any" group returns the other parameters truthy.'
);
// Group 2 (nothing is selected, all false)
hidefilter4: 0,
hidefilter5: 0,
- hidefilter6: 0
+ hidefilter6: 0,
+ group3: 'all'
},
'All filters selected in one "send_unselected_if_any" group returns all parameters falsy.'
);
+
+ // Select 1 filter from string_options
+ model.updateFilters( {
+ filter7: true,
+ filter8: false,
+ filter9: false
+ } );
+ // All filters of the group are selected == this is the same as not selecting any
+ assert.deepEqual(
+ model.getParametersFromFilters(),
+ {
+ // Group 1 (all selected, all)
+ hidefilter1: 0,
+ hidefilter2: 0,
+ hidefilter3: 0,
+ // Group 2 (nothing is selected, all false)
+ hidefilter4: 0,
+ hidefilter5: 0,
+ hidefilter6: 0,
+ group3: 'filter7'
+ },
+ 'One filter selected in "string_option" group returns that filter in the value.'
+ );
+
+ // Select 2 filters from string_options
+ model.updateFilters( {
+ filter7: true,
+ filter8: true,
+ filter9: false
+ } );
+ // All filters of the group are selected == this is the same as not selecting any
+ assert.deepEqual(
+ model.getParametersFromFilters(),
+ {
+ // Group 1 (all selected, all)
+ hidefilter1: 0,
+ hidefilter2: 0,
+ hidefilter3: 0,
+ // Group 2 (nothing is selected, all false)
+ hidefilter4: 0,
+ hidefilter5: 0,
+ hidefilter6: 0,
+ group3: 'filter7,filter8'
+ },
+ 'Two filters selected in "string_option" group returns those filters in the value.'
+ );
+
+ // Select 3 filters from string_options
+ model.updateFilters( {
+ filter7: true,
+ filter8: true,
+ filter9: true
+ } );
+ // All filters of the group are selected == this is the same as not selecting any
+ assert.deepEqual(
+ model.getParametersFromFilters(),
+ {
+ // Group 1 (all selected, all)
+ hidefilter1: 0,
+ hidefilter2: 0,
+ hidefilter3: 0,
+ // Group 2 (nothing is selected, all false)
+ hidefilter4: 0,
+ hidefilter5: 0,
+ hidefilter6: 0,
+ group3: 'all'
+ },
+ 'All filters selected in "string_option" group returns \'all\'.'
+ );
+
} );
QUnit.test( 'getFiltersFromParameters', function ( assert ) {
description: 'Description of Filter 3 in Group 2'
}
]
+ },
+ group3: {
+ title: 'Group 3',
+ type: 'string_options',
+ separator: ',',
+ filters: [
+ {
+ name: 'filter7',
+ label: 'Group 3: Filter 1',
+ description: 'Description of Filter 1 in Group 3'
+ },
+ {
+ name: 'filter8',
+ label: 'Group 3: Filter 2',
+ description: 'Description of Filter 2 in Group 3'
+ },
+ {
+ name: 'filter9',
+ label: 'Group 3: Filter 3',
+ description: 'Description of Filter 3 in Group 3'
+ }
+ ]
}
},
model = new mw.rcfilters.dm.FiltersViewModel();
hidefilter3: false, // The text is "show filter 3"
hidefilter4: false, // The text is "show filter 4"
hidefilter5: false, // The text is "show filter 5"
- hidefilter6: false // The text is "show filter 6"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
},
'Empty parameter query results in filters in initial state'
);
hidefilter3: true, // The text is "show filter 3"
hidefilter4: false, // The text is "show filter 4"
hidefilter5: false, // The text is "show filter 5"
- hidefilter6: false // The text is "show filter 6"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
},
'One falsey parameter in a group makes the rest of the filters in the group truthy (checked) in the interface'
);
hidefilter3: true, // The text is "show filter 3"
hidefilter4: false, // The text is "show filter 4"
hidefilter5: false, // The text is "show filter 5"
- hidefilter6: false // The text is "show filter 6"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
},
- 'Two falsey parameters in a group makes the rest of the filters in the group truthy (checked) in the interface'
+ 'Two falsey parameters in a \'send_unselected_if_any\' group makes the rest of the filters in the group truthy (checked) in the interface'
);
assert.deepEqual(
hidefilter3: false, // The text is "show filter 3"
hidefilter4: false, // The text is "show filter 4"
hidefilter5: false, // The text is "show filter 5"
- hidefilter6: false // The text is "show filter 6"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
},
- 'All paremeters in the same group false is equivalent to none are truthy (checked) in the interface'
+ 'All paremeters in the same \'send_unselected_if_any\' group false is equivalent to none are truthy (checked) in the interface'
);
// The ones above don't update the model, so we have a clean state.
hidefilter3: false, // The text is "show filter 3"
hidefilter4: false, // The text is "show filter 4"
hidefilter5: false, // The text is "show filter 5"
- hidefilter6: false // The text is "show filter 6"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
},
- 'After unchecking 2 of 3 filters via separate updateFilters calls, only the remaining one is still checked.'
+ 'After unchecking 2 of 3 \'send_unselected_if_any\' filters via separate updateFilters calls, only the remaining one is still checked.'
);
// Reset
hidefilter3: false, // The text is "show filter 3"
hidefilter4: false, // The text is "show filter 4"
hidefilter5: false, // The text is "show filter 5"
- hidefilter6: false // The text is "show filter 6"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
+ },
+ 'After unchecking then checking a \'send_unselected_if_any\' filter (without touching other filters in that group), all are checked'
+ );
+
+ model.updateFilters(
+ model.getFiltersFromParameters( {
+ group3: 'filter7'
+ } )
+ );
+ assert.deepEqual(
+ model.getState(),
+ {
+ hidefilter1: false, // The text is "show filter 1"
+ hidefilter2: false, // The text is "show filter 2"
+ hidefilter3: false, // The text is "show filter 3"
+ hidefilter4: false, // The text is "show filter 4"
+ hidefilter5: false, // The text is "show filter 5"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: true,
+ filter8: false,
+ filter9: false
},
- 'After unchecking then checking a filter (without touching other filters in that group), all are checked'
+ 'A \'string_options\' parameter containing 1 value, results in the corresponding filter as checked'
+ );
+
+ model.updateFilters(
+ model.getFiltersFromParameters( {
+ group3: 'filter7,filter8'
+ } )
+ );
+ assert.deepEqual(
+ model.getState(),
+ {
+ hidefilter1: false, // The text is "show filter 1"
+ hidefilter2: false, // The text is "show filter 2"
+ hidefilter3: false, // The text is "show filter 3"
+ hidefilter4: false, // The text is "show filter 4"
+ hidefilter5: false, // The text is "show filter 5"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: true,
+ filter8: true,
+ filter9: false
+ },
+ 'A \'string_options\' parameter containing 2 values, results in both corresponding filters as checked'
+ );
+
+ model.updateFilters(
+ model.getFiltersFromParameters( {
+ group3: 'filter7,filter8,filter9'
+ } )
+ );
+ assert.deepEqual(
+ model.getState(),
+ {
+ hidefilter1: false, // The text is "show filter 1"
+ hidefilter2: false, // The text is "show filter 2"
+ hidefilter3: false, // The text is "show filter 3"
+ hidefilter4: false, // The text is "show filter 4"
+ hidefilter5: false, // The text is "show filter 5"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
+ },
+ 'A \'string_options\' parameter containing all values, results in all filters of the group as unchecked.'
+ );
+
+ model.updateFilters(
+ model.getFiltersFromParameters( {
+ group3: 'filter7,filter8,filter9'
+ } )
+ );
+ assert.deepEqual(
+ model.getState(),
+ {
+ hidefilter1: false, // The text is "show filter 1"
+ hidefilter2: false, // The text is "show filter 2"
+ hidefilter3: false, // The text is "show filter 3"
+ hidefilter4: false, // The text is "show filter 4"
+ hidefilter5: false, // The text is "show filter 5"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: false,
+ filter8: false,
+ filter9: false
+ },
+ 'A \'string_options\' parameter containing the value \'all\', results in all filters of the group as unchecked.'
+ );
+
+ model.updateFilters(
+ model.getFiltersFromParameters( {
+ group3: 'filter7,foo,filter9'
+ } )
+ );
+ assert.deepEqual(
+ model.getState(),
+ {
+ hidefilter1: false, // The text is "show filter 1"
+ hidefilter2: false, // The text is "show filter 2"
+ hidefilter3: false, // The text is "show filter 3"
+ hidefilter4: false, // The text is "show filter 4"
+ hidefilter5: false, // The text is "show filter 5"
+ hidefilter6: false, // The text is "show filter 6"
+ filter7: true,
+ filter8: false,
+ filter9: true
+ },
+ 'A \'string_options\' parameter containing an invalid value, results in the invalid value ignored and the valid corresponding filters checked.'
+ );
+ } );
+
+ QUnit.test( 'sanitizeStringOptionGroup', function ( assert ) {
+ var definition = {
+ group1: {
+ title: 'Group 1',
+ type: 'string_options',
+ filters: [
+ {
+ name: 'filter1',
+ label: 'Show filter 1',
+ description: 'Description of Filter 1 in Group 1'
+ },
+ {
+ name: 'filter2',
+ label: 'Show filter 2',
+ description: 'Description of Filter 2 in Group 1'
+ },
+ {
+ name: 'filter3',
+ label: 'Show filter 3',
+ description: 'Description of Filter 3 in Group 1'
+ }
+ ]
+ }
+ },
+ model = new mw.rcfilters.dm.FiltersViewModel();
+
+ model.initializeFilters( definition );
+
+ assert.deepEqual(
+ model.sanitizeStringOptionGroup( 'group1', [ 'filter1', 'filter1', 'filter2' ] ),
+ [ 'filter1', 'filter2' ],
+ 'Remove duplicate values'
+ );
+
+ assert.deepEqual(
+ model.sanitizeStringOptionGroup( 'group1', [ 'filter1', 'foo', 'filter2' ] ),
+ [ 'filter1', 'filter2' ],
+ 'Remove invalid values'
+ );
+
+ assert.deepEqual(
+ model.sanitizeStringOptionGroup( 'group1', [ 'filter1', 'all', 'filter2' ] ),
+ [ 'all' ],
+ 'If any value is "all", the only value is "all".'
);
} );
}( mediaWiki, jQuery ) );