* @cfg {boolean} [active] Group is active
* @cfg {boolean} [fullCoverage] This filters in this group collectively cover all results
* @cfg {Object} [conflicts] Defines the conflicts for this filter group
+ * @cfg {Object} [whatsThis] Defines the messages that should appear for the 'what's this' popup
+ * @cfg {string} [whatsThis.header] The header of the whatsThis popup message
+ * @cfg {string} [whatsThis.body] The body of the whatsThis popup message
+ * @cfg {string} [whatsThis.url] The url for the link in the whatsThis popup message
+ * @cfg {string} [whatsThis.linkMessage] The text for the link in the whatsThis popup message
*/
mw.rcfilters.dm.FilterGroup = function MwRcfiltersDmFilterGroup( name, config ) {
config = config || {};
this.active = !!config.active;
this.fullCoverage = !!config.fullCoverage;
+ this.whatsThis = config.whatsThis || {};
+
this.conflicts = config.conflicts || {};
this.aggregate( { update: 'filterItemUpdate' } );
return this.name;
};
+ /**
+ * Get the messags defining the 'whats this' popup for this group
+ *
+ * @return {Object} What's this messages
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.getWhatsThis = function () {
+ return this.whatsThis;
+ };
+
+ /**
+ * Check whether this group has a 'what's this' message
+ *
+ * @return {boolean} This group has a what's this message
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.hasWhatsThis = function () {
+ return !!this.whatsThis.body;
+ };
+
/**
* Get the conflicts associated with the entire group.
* Conflict object is set up by filter name keys and conflict
);
};
+ /**
+ * Get the parameter representation from this group
+ *
+ * @return {Object} Parameter representation
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.getParamRepresentation = function () {
+ var i, values,
+ result = {},
+ filterItems = this.getItems();
+
+ if ( this.getType() === '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
+
+ // Go over the items and define the correct values
+ for ( i = 0; i < filterItems.length; i++ ) {
+ result[ filterItems[ i ].getParamName() ] = this.areAnySelected() ?
+ Number( !filterItems[ i ].isSelected() ) : 0;
+ }
+
+ } else if ( this.getType() === 'string_options' ) {
+ values = [];
+ for ( i = 0; i < filterItems.length; i++ ) {
+ if ( filterItems[ i ].isSelected() ) {
+ values.push( filterItems[ i ].getParamName() );
+ }
+ }
+
+ result[ this.getName() ] = ( values.length === filterItems.length ) ?
+ 'all' : values.join( this.getSeparator() );
+ }
+
+ return result;
+ };
+
/**
* Get group type
*
return this.type;
};
+ /**
+ * Get the prefix used for the filter names inside this group
+ *
+ * @return {string} Group prefix
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.getNamePrefix = function () {
+ return this.getName() + '__';
+ };
+
/**
* Get group's title
*
this.defaultParams = {};
this.defaultFiltersEmpty = null;
this.highlightEnabled = false;
+ this.parameterMap = {};
// Events
this.aggregate( { update: 'filterItemUpdate' } );
* @param {Array} filters Filter group definition
*/
mw.rcfilters.dm.FiltersViewModel.prototype.initializeFilters = function ( filters ) {
- var i, filterItem, selectedFilterNames, filterConflictResult, groupConflictResult,
+ var i, filterItem, selectedFilterNames, filterConflictResult, groupConflictResult, subsetNames,
model = this,
items = [],
supersetMap = {},
expandConflictDefinitions = function ( obj ) {
var result = {};
- $.each( obj, function ( group, conflicts ) {
- var adjustedConflicts = {};
+ $.each( obj, function ( key, conflicts ) {
+ var filterName,
+ adjustedConflicts = {};
+
conflicts.forEach( function ( conflict ) {
if ( conflict.filter ) {
- adjustedConflicts[ conflict.filter ] = conflict;
+ filterName = model.groups[ conflict.group ].getNamePrefix() + conflict.filter;
+
+ // Rename
+ adjustedConflicts[ filterName ] = $.extend(
+ {},
+ conflict,
+ { filter: filterName }
+ );
} else {
// This conflict is for an entire group. Split it up to
// represent each filter
// Get the relevant group items
model.groups[ conflict.group ].getItems().forEach( function ( groupItem ) {
// Rebuild the conflict
- adjustedConflicts[ groupItem.getName() ] = $.extend( {}, conflict, { filter: groupItem.getName() } );
+ adjustedConflicts[ groupItem.getName() ] = $.extend(
+ {},
+ conflict,
+ { filter: groupItem.getName() }
+ );
} );
}
} );
- result[ group ] = adjustedConflicts;
+ result[ key ] = adjustedConflicts;
} );
return result;
type: data.type,
title: mw.msg( data.title ),
separator: data.separator,
- fullCoverage: !!data.fullCoverage
+ fullCoverage: !!data.fullCoverage,
+ whatsThis: {
+ body: data.whatsThisBody,
+ header: data.whatsThisHeader,
+ linkText: data.whatsThisLinkText,
+ url: data.whatsThisUrl
+ }
} );
}
group: group,
label: mw.msg( data.filters[ i ].label ),
description: mw.msg( data.filters[ i ].description ),
- subset: data.filters[ i ].subset,
cssClass: data.filters[ i ].cssClass
} );
- // For convenience, we should store each filter's "supersets" -- these are
- // the filters that have that item in their subset list. This will just
- // make it easier to go through whether the item has any other items
- // that affect it (and are selected) at any given time
if ( data.filters[ i ].subset ) {
+ subsetNames = [];
data.filters[ i ].subset.forEach( function ( subsetFilterName ) { // eslint-disable-line no-loop-func
- supersetMap[ subsetFilterName ] = supersetMap[ subsetFilterName ] || [];
+ var subsetName = model.groups[ group ].getNamePrefix() + subsetFilterName;
+ // For convenience, we should store each filter's "supersets" -- these are
+ // the filters that have that item in their subset list. This will just
+ // make it easier to go through whether the item has any other items
+ // that affect it (and are selected) at any given time
+ supersetMap[ subsetName ] = supersetMap[ subsetName ] || [];
addArrayElementsUnique(
- supersetMap[ subsetFilterName ],
+ supersetMap[ subsetName ],
filterItem.getName()
);
+
+ // Translate subset param name to add the group name, so we
+ // get consistent naming. We know that subsets are only within
+ // the same group
+ subsetNames.push( subsetName );
} );
+
+ // Set translated subset
+ filterItem.setSubset( subsetNames );
}
// Store conflicts
if ( data.filters[ i ].conflicts ) {
- filterConflictMap[ data.filters[ i ].name ] = data.filters[ i ].conflicts;
+ filterConflictMap[ filterItem.getName() ] = data.filters[ i ].conflicts;
}
if ( data.type === 'send_unselected_if_any' ) {
}
} );
+ // Create a map between known parameters and their models
+ $.each( this.groups, function ( group, groupModel ) {
+ if ( groupModel.getType() === 'send_unselected_if_any' ) {
+ // Individual filters
+ groupModel.getItems().forEach( function ( filterItem ) {
+ model.parameterMap[ filterItem.getParamName() ] = filterItem;
+ } );
+ } else if ( groupModel.getType() === 'string_options' ) {
+ // Group
+ model.parameterMap[ groupModel.getName() ] = groupModel;
+ }
+ } );
+
// Add items to the model
this.addItems( items );
* @return {Object} Parameter state object
*/
mw.rcfilters.dm.FiltersViewModel.prototype.getParametersFromFilters = function ( filterGroups ) {
- var i, filterItems, anySelected, values,
- result = {},
+ var result = {},
groupItems = filterGroups || this.getFilterGroups();
$.each( groupItems, function ( group, model ) {
- filterItems = model.getItems();
-
- if ( model.getType() === '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
- anySelected = filterItems.some( function ( filterItem ) {
- return filterItem.isSelected();
- } );
-
- // Go over the items and define the correct values
- for ( i = 0; i < filterItems.length; i++ ) {
- result[ filterItems[ i ].getName() ] = anySelected ?
- Number( !filterItems[ i ].isSelected() ) : 0;
- }
- } else if ( model.getType() === 'string_options' ) {
- values = [];
- for ( i = 0; i < filterItems.length; i++ ) {
- if ( filterItems[ i ].isSelected() ) {
- values.push( filterItems[ i ].getName() );
- }
- }
-
- if ( values.length === filterItems.length ) {
- result[ group ] = 'all';
- } else {
- result[ group ] = values.join( model.getSeparator() );
- }
- }
+ $.extend( result, model.getParamRepresentation() );
} );
return result;
mw.rcfilters.dm.FiltersViewModel.prototype.sanitizeStringOptionGroup = function( groupName, valueArray ) {
var result = [],
validNames = this.getGroupFilters( groupName ).map( function ( filterItem ) {
- return filterItem.getName();
+ return filterItem.getParamName();
} );
if ( valueArray.indexOf( 'all' ) > -1 ) {
* @return {Object} Filter state object
*/
mw.rcfilters.dm.FiltersViewModel.prototype.getFiltersFromParameters = function ( params ) {
- var i, filterItem,
+ var i,
groupMap = {},
model = this,
base = this.getDefaultParams(),
params = $.extend( {}, base, params );
+ // Go over the given parameters
$.each( params, function ( paramName, paramValue ) {
- // Find the filter item
- filterItem = model.getItemByName( paramName );
- // Ignore if no filter item exists
- if ( filterItem ) {
- groupMap[ filterItem.getGroupName() ] = groupMap[ filterItem.getGroupName() ] || {};
+ var itemOrGroup = model.parameterMap[ paramName ];
+ if ( itemOrGroup instanceof mw.rcfilters.dm.FilterItem ) {
// Mark the group if it has any items that are selected
- groupMap[ filterItem.getGroupName() ].hasSelected = (
- groupMap[ filterItem.getGroupName() ].hasSelected ||
+ groupMap[ itemOrGroup.getGroupName() ] = groupMap[ itemOrGroup.getGroupName() ] || {};
+ groupMap[ itemOrGroup.getGroupName() ].hasSelected = (
+ groupMap[ itemOrGroup.getGroupName() ].hasSelected ||
!!Number( paramValue )
);
- // Add the relevant filter into the group map
- groupMap[ filterItem.getGroupName() ].filters = groupMap[ filterItem.getGroupName() ].filters || [];
- groupMap[ filterItem.getGroupName() ].filters.push( filterItem );
- } else if ( model.groups.hasOwnProperty( paramName ) ) {
+ // Add filters
+ groupMap[ itemOrGroup.getGroupName() ].filters = groupMap[ itemOrGroup.getGroupName() ].filters || [];
+ groupMap[ itemOrGroup.getGroupName() ].filters.push( itemOrGroup );
+ } else if ( itemOrGroup instanceof mw.rcfilters.dm.FilterGroup ) {
+ groupMap[ itemOrGroup.getName() ] = groupMap[ itemOrGroup.getName() ] || {};
// 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 ].getItems() };
+ groupMap[ itemOrGroup.getName() ].filters = itemOrGroup.getItems();
}
} );
for ( i = 0; i < allItemsInGroup.length; i++ ) {
filterItem = allItemsInGroup[ i ];
- result[ filterItem.getName() ] = data.hasSelected ?
+ result[ filterItem.getName() ] = groupMap[ filterItem.getGroupName() ].hasSelected ?
// Flip the definition between the parameter
// state and the filter state
// This is what the 'toggleSelected' value of the filter is
- !Number( params[ filterItem.getName() ] ) :
+ !Number( params[ filterItem.getParamName() ] ) :
// Otherwise, there are no selected items in the
// group, which means the state is false
false;
}
} else if ( model.groups[ group ].getType() === 'string_options' ) {
- paramValues = model.sanitizeStringOptionGroup( group, params[ group ].split( model.groups[ group ].getSeparator() ) );
+ paramValues = model.sanitizeStringOptionGroup(
+ group,
+ params[ group ].split(
+ model.groups[ group ].getSeparator()
+ )
+ );
for ( i = 0; i < allItemsInGroup.length; i++ ) {
filterItem = allItemsInGroup[ i ];
// 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;
+ paramValues.indexOf( filterItem.getParamName() ) > -1;
}
}
} );
+
return result;
};
* @param {boolean} [isSelected] Filter selected state
*/
mw.rcfilters.dm.FiltersViewModel.prototype.toggleFilterSelected = function ( name, isSelected ) {
- this.getItemByName( name ).toggleSelected( isSelected );
+ var item = this.getItemByName( name );
+
+ if ( item ) {
+ item.toggleSelected( isSelected );
+ }
};
/**