* @param {string} name Group name
* @param {Object} [config] Configuration options
* @cfg {string} [type='send_unselected_if_any'] Group type
+ * @cfg {string} [view='default'] Name of the display group this group
+ * is a part of.
* @cfg {string} [title] Group title
+ * @cfg {boolean} [hidden] This group is hidden from the regular menu views
* @cfg {string} [separator='|'] Value separator for 'string_options' groups
* @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 {string|Object} [labelPrefixKey] An i18n key defining the prefix label for this
+ * group. If the prefix has 'invert' state, the parameter is expected to be an object
+ * with 'default' and 'inverted' as keys.
* @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
this.name = name;
this.type = config.type || 'send_unselected_if_any';
- this.title = config.title;
+ this.view = config.view || 'default';
+ this.title = config.title || name;
+ this.hidden = !!config.hidden;
this.separator = config.separator || '|';
+ this.labelPrefixKey = config.labelPrefixKey;
this.active = !!config.active;
this.fullCoverage = !!config.fullCoverage;
var subsetNames = [],
filterItem = new mw.rcfilters.dm.FilterItem( filter.name, model, {
group: model.getName(),
- label: mw.msg( filter.label ),
- description: mw.msg( filter.description ),
- cssClass: filter.cssClass
+ label: filter.label || filter.name,
+ description: filter.description || '',
+ labelPrefixKey: model.labelPrefixKey,
+ cssClass: filter.cssClass,
+ identifiers: filter.identifiers
} );
- filter.subset = filter.subset || [];
- filter.subset = filter.subset.map( function ( el ) {
- return el.filter;
- } );
-
if ( filter.subset ) {
+ filter.subset = filter.subset.map( function ( el ) {
+ return el.filter;
+ } );
+
subsetNames = [];
+
filter.subset.forEach( function ( subsetFilterName ) { // eslint-disable-line no-loop-func
// Subsets (unlike conflicts) are always inside the same group
// We can re-map the names of the filters we are getting from
if ( model.getType() === 'send_unselected_if_any' ) {
// Store the default parameter state
// For this group type, parameter values are direct
- model.defaultParams[ filter.name ] = Number( !!filter.default );
+ // We need to convert from a boolean to a string ('1' and '0')
+ model.defaultParams[ filter.name ] = String( Number( !!filter.default ) );
}
} );
return item.getParamName();
} )
).join( this.getSeparator() );
+ } else if ( this.getType() === 'single_option' ) {
+ // For this group, the parameter is the group name,
+ // and a single item can be selected, or none at all
+ // The item also must be recognized or none is set as
+ // default
+ model.defaultParams[ this.getName() ] = this.getItemByParamName( groupDefault ) ? groupDefault : '';
}
};
/**
* Respond to filterItem update event
*
+ * @param {mw.rcfilters.dm.FilterItem} item Updated filter item
* @fires update
*/
- mw.rcfilters.dm.FilterGroup.prototype.onFilterItemUpdate = function () {
+ mw.rcfilters.dm.FilterGroup.prototype.onFilterItemUpdate = function ( item ) {
// Update state
- var active = this.areAnySelected();
+ var active = this.areAnySelected(),
+ itemName = item && item.getName();
+
+ if ( item.isSelected() && this.getType() === 'single_option' ) {
+ // Change the selection to only be the newly selected item
+ this.getItems().forEach( function ( filterItem ) {
+ if ( filterItem.getName() !== itemName ) {
+ filterItem.toggleSelected( false );
+ }
+ } );
+ }
if ( this.active !== active ) {
this.active = active;
return this.active;
};
+ /**
+ * Get group hidden state
+ *
+ * @return {boolean} Hidden state
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.isHidden = function () {
+ return this.hidden;
+ };
+
/**
* Get group name
*
areAnySelected = false,
buildFromCurrentState = !filterRepresentation,
result = {},
- filterParamNames = {};
+ model = this,
+ filterParamNames = {},
+ getSelectedParameter = function ( filters ) {
+ var item,
+ selected = [];
+
+ // Find if any are selected
+ $.each( filters, function ( name, value ) {
+ if ( value ) {
+ selected.push( name );
+ }
+ } );
+
+ item = model.getItemByName( selected[ 0 ] );
+ return ( item && item.getParamName() ) || '';
+ };
filterRepresentation = filterRepresentation || {};
// Go over the items and define the correct values
$.each( filterRepresentation, function ( name, value ) {
+ // We must store all parameter values as strings '0' or '1'
result[ filterParamNames[ name ] ] = areAnySelected ?
- Number( !value ) : 0;
+ String( Number( !value ) ) :
+ '0';
} );
} else if ( this.getType() === 'string_options' ) {
values = [];
result[ this.getName() ] = ( values.length === Object.keys( filterRepresentation ).length ) ?
'all' : values.join( this.getSeparator() );
+ } else if ( this.getType() === 'single_option' ) {
+ result[ this.getName() ] = getSelectedParameter( filterRepresentation );
}
return result;
paramRepresentation = paramRepresentation || {};
// Expand param representation to include all filters in the group
this.getItems().forEach( function ( filterItem ) {
- paramRepresentation[ filterItem.getParamName() ] = !!paramRepresentation[ filterItem.getParamName() ];
- paramToFilterMap[ filterItem.getParamName() ] = filterItem;
+ var paramName = filterItem.getParamName();
+
+ paramRepresentation[ paramName ] = paramRepresentation[ paramName ] || '0';
+ paramToFilterMap[ paramName ] = filterItem;
- if ( paramRepresentation[ filterItem.getParamName() ] ) {
+ if ( Number( paramRepresentation[ filterItem.getParamName() ] ) ) {
areAnySelected = true;
}
} );
$.each( paramRepresentation, function ( paramName, paramValue ) {
var filterItem = paramToFilterMap[ paramName ];
+ // Flip the definition between the parameter
+ // state and the filter state
+ // This is what the 'toggleSelected' value of the filter is
result[ filterItem.getName() ] = areAnySelected ?
- // Flip the definition between the parameter
- // state and the filter state
- // This is what the 'toggleSelected' value of the filter is
!Number( paramValue ) :
// Otherwise, there are no selected items in the
// group, which means the state is false
);
// Translate the parameter values into a filter selection state
this.getItems().forEach( function ( filterItem ) {
+ // All true (either because all values are written or the term 'all' is written)
+ // is the same as all filters set to true
result[ filterItem.getName() ] = (
- // If it is the word 'all'
- paramValues.length === 1 && paramValues[ 0 ] === 'all' ||
- // All values are written
- paramValues.length === model.getItemCount()
- ) ?
- // All true (either because all values are written or the term 'all' is written)
- // is the same as all filters set to true
+ // If it is the word 'all'
+ paramValues.length === 1 && paramValues[ 0 ] === 'all' ||
+ // All values are written
+ paramValues.length === model.getItemCount()
+ ) ?
true :
// Otherwise, the filter is selected only if it appears in the parameter values
paramValues.indexOf( filterItem.getParamName() ) > -1;
} );
+ } else if ( this.getType() === 'single_option' ) {
+ // There is parameter that fits a single filter, or none at all
+ this.getItems().forEach( function ( filterItem ) {
+ result[ filterItem.getName() ] = filterItem.getParamName() === paramRepresentation;
+ } );
}
// Go over result and make sure all filters are represented.
return result;
};
+ /**
+ * Get item by its filter name
+ *
+ * @param {string} filterName Filter name
+ * @return {mw.rcfilters.dm.FilterItem} Filter item
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.getItemByName = function ( filterName ) {
+ return this.getItems().filter( function ( item ) {
+ return item.getName() === filterName;
+ } )[ 0 ];
+ };
+
/**
* Get item by its parameter name
*
return this.type;
};
+ /**
+ * Get display group
+ *
+ * @return {string} Display group
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.getView = function () {
+ return this.view;
+ };
+
/**
* Get the prefix used for the filter names inside this group.
*