* is a part of.
* @cfg {boolean} [isSticky] This group is using a 'sticky' default; meaning
* that every time a value is changed, it becomes the new default
+ * @cfg {boolean} [excludedFromSavedQueries] A specific requirement to exclude
+ * this filter from saved queries. This is always true if the filter is 'sticky'
+ * but can be used for non-sticky filters as an additional requirement. Similarly
+ * to 'sticky' it works for the entire group as a whole.
* @cfg {string} [title] Group title
* @cfg {boolean} [hidden] This group is hidden from the regular menu views
* @cfg {boolean} [allowArbitrary] Allows for an arbitrary value to be added to the
* group from the URL, even if it wasn't initially set up.
+ * @cfg {number} [range] An object defining minimum and maximum values for numeric
+ * groups. { min: x, max: y }
+ * @cfg {number} [minValue] Minimum value for numeric groups
* @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
this.type = config.type || 'send_unselected_if_any';
this.view = config.view || 'default';
this.sticky = !!config.isSticky;
+ this.excludedFromSavedQueries = this.sticky || !!config.excludedFromSavedQueries;
this.title = config.title || name;
this.hidden = !!config.hidden;
this.allowArbitrary = !!config.allowArbitrary;
+ this.numericRange = config.range;
this.separator = config.separator || '|';
this.labelPrefixKey = config.labelPrefixKey;
// Store the default parameter state
// For this group type, parameter values are direct
// We need to convert from a boolean to a string ('1' and '0')
- model.defaultParams[ filter.name ] = String( Number( !!filter.default ) );
+ model.defaultParams[ filter.name ] = String( Number( filter.default || 0 ) );
}
} );
mw.rcfilters.dm.FilterGroup.prototype.onFilterItemUpdate = function ( item ) {
// Update state
var changed = false,
- active = this.areAnySelected();
-
- if (
- item.isSelected() &&
- this.getType() === 'single_option' &&
- this.currSelected &&
- this.currSelected !== item
- ) {
- this.currSelected.toggleSelected( false );
- }
-
- // For 'single_option' groups, check if we just unselected all
- // items. This should never be the result. If we did unselect
- // all (like resetting all filters to false) then this group
- // must choose its default item or the first item in the group
- if (
- this.getType() === 'single_option' &&
- !this.getItems().some( function ( filterItem ) {
- return filterItem.isSelected();
- } )
- ) {
- // Single option means there must be a single option
- // selected, so we have to either select the default
- // or select the first option
- this.currSelected = this.getItemByParamName( this.defaultParams[ this.getName() ] ) ||
- this.getItems()[ 0 ];
- this.currSelected.toggleSelected( true );
- changed = true;
+ active = this.areAnySelected(),
+ model = this;
+
+ if ( this.getType() === 'single_option' ) {
+ // This group must have one item selected always
+ // and must never have more than one item selected at a time
+ if ( this.getSelectedItems().length === 0 ) {
+ // Nothing is selected anymore
+ // Select the default or the first item
+ this.currSelected = this.getItemByParamName( this.defaultParams[ this.getName() ] ) ||
+ this.getItems()[ 0 ];
+ this.currSelected.toggleSelected( true );
+ changed = true;
+ } else if ( this.getSelectedItems().length > 1 ) {
+ // There is more than one item selected
+ // This should only happen if the item given
+ // is the one that is selected, so unselect
+ // all items that is not it
+ this.getSelectedItems().forEach( function ( itemModel ) {
+ // Note that in case the given item is actually
+ // not selected, this loop will end up unselecting
+ // all items, which would trigger the case above
+ // when the last item is unselected anyways
+ var selected = itemModel.getName() === item.getName() &&
+ item.isSelected();
+
+ itemModel.toggleSelected( selected );
+ if ( selected ) {
+ model.currSelected = itemModel;
+ }
+ } );
+ changed = true;
+ }
}
if (
return this.allowArbitrary;
};
+ /**
+ * Get group maximum value for numeric groups
+ *
+ * @return {number|null} Group max value
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.getMaxValue = function () {
+ return this.numericRange && this.numericRange.max !== undefined ?
+ this.numericRange.max : null;
+ };
+
+ /**
+ * Get group minimum value for numeric groups
+ *
+ * @return {number|null} Group max value
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.getMinValue = function () {
+ return this.numericRange && this.numericRange.min !== undefined ?
+ this.numericRange.min : null;
+ };
+
/**
* Get group name
*
this.getType() === 'single_option' &&
!oneWasSelected
) {
+ item = this.getItems()[ 0 ];
if ( defaultParams[ this.getName() ] ) {
item = this.getItemByParamName( defaultParams[ this.getName() ] );
- } else {
- item = this.getItems()[ 0 ];
}
+
result[ item.getName() ] = true;
}
mw.rcfilters.dm.FilterGroup.prototype.isSticky = function () {
return this.sticky;
};
+
+ /**
+ * Check whether the group value is excluded from saved queries
+ *
+ * @return {boolean} Group value is excluded from saved queries
+ */
+ mw.rcfilters.dm.FilterGroup.prototype.isExcludedFromSavedQueries = function () {
+ return this.excludedFromSavedQueries;
+ };
}( mediaWiki ) );