this.groups = {};
this.defaultParams = {};
- this.defaultFiltersEmpty = null;
this.highlightEnabled = false;
this.parameterMap = {};
this.emptyParameterState = null;
this.views = {};
this.currentView = 'default';
+ this.searchQuery = null;
// Events
this.aggregate( { update: 'filterItemUpdate' } );
mw.rcfilters.dm.FiltersViewModel.prototype.getFirstConflictedItem = function () {
var conflictedItem;
- $.each( this.getItems(), function ( index, filterItem ) {
+ this.getItems().forEach( function ( filterItem ) {
if ( filterItem.isSelected() && filterItem.isConflicted() ) {
conflictedItem = filterItem;
return false;
$.each( this.groups, function ( group, groupModel ) {
if (
groupModel.getType() === 'send_unselected_if_any' ||
- groupModel.getType() === 'boolean'
+ groupModel.getType() === 'boolean' ||
+ groupModel.getType() === 'any_value'
) {
// Individual filters
groupModel.getItems().forEach( function ( filterItem ) {
}
} );
- this.currentView = 'default';
+ this.setSearch( '' );
this.updateHighlightedState();
* @param {Object} params Parameters object
*/
mw.rcfilters.dm.FiltersViewModel.prototype.updateStateFromParams = function ( params ) {
+ var filtersValue;
// For arbitrary numeric single_option values make sure the values
// are normalized to fit within the limits
$.each( this.getFilterGroups(), function ( groupName, groupModel ) {
params[ groupName ] = groupModel.normalizeArbitraryValue( params[ groupName ] );
} );
- // Update filter states
- this.toggleFiltersSelected(
- this.getFiltersFromParameters(
- params
- )
- );
+ // Update filter values
+ filtersValue = this.getFiltersFromParameters( params );
+ Object.keys( filtersValue ).forEach( function ( filterName ) {
+ this.getItemByName( filterName ).setValue( filtersValue[ filterName ] );
+ }.bind( this ) );
// Update highlight state
this.getItemsSupportingHighlights().forEach( function ( filterItem ) {
/**
* Get a representation of the full parameter list, including all base values
*
- * @param {Object} [parameters] A given parameter state to minimize. If not given the current
- * state of the system will be used.
- * @param {boolean} [removeExcluded] Remove excluded and sticky parameters
* @return {Object} Full parameter representation
*/
- mw.rcfilters.dm.FiltersViewModel.prototype.getExpandedParamRepresentation = function ( parameters, removeExcluded ) {
- var result = {};
-
- parameters = parameters ? $.extend( true, {}, parameters ) : this.getCurrentParameterState();
-
- result = $.extend(
+ mw.rcfilters.dm.FiltersViewModel.prototype.getExpandedParamRepresentation = function () {
+ return $.extend(
true,
{},
this.getEmptyParameterState(),
- parameters
+ this.getCurrentParameterState()
);
-
- if ( removeExcluded ) {
- result = this.removeExcludedParams( result );
- }
-
- return result;
};
/**
* Get a parameter representation of the current state of the model
*
- * @param {boolean} [removeExcludedParams] Remove excluded filters from final result
+ * @param {boolean} [removeStickyParams] Remove sticky filters from final result
* @return {Object} Parameter representation of the current state of the model
*/
- mw.rcfilters.dm.FiltersViewModel.prototype.getCurrentParameterState = function ( removeExcludedParams ) {
- var excludedParams,
- state = this.getMinimizedParamRepresentation( $.extend(
- true,
- {},
- this.getParametersFromFilters( this.getSelectedState() ),
- this.getHighlightParameters()
- ) );
-
- if ( removeExcludedParams ) {
- excludedParams = this.getExcludedParams();
- // Delete all excluded filters
- $.each( state, function ( param ) {
- if ( excludedParams.indexOf( param ) > -1 ) {
- delete state[ param ];
- }
- } );
+ mw.rcfilters.dm.FiltersViewModel.prototype.getCurrentParameterState = function ( removeStickyParams ) {
+ var state = this.getMinimizedParamRepresentation( $.extend(
+ true,
+ {},
+ this.getParametersFromFilters( this.getSelectedState() ),
+ this.getHighlightParameters()
+ ) );
+
+ if ( removeStickyParams ) {
+ state = this.removeStickyParams( state );
}
return state;
};
/**
- * Delete excluded and sticky filters from given object. If object isn't given, output
- * the current filter state without the excluded values
+ * Delete sticky parameters from given object.
*
- * @param {Object} [filterState] Filter state
- * @return {Object} Filter state without excluded filters
+ * @param {Object} paramState Parameter state
+ * @return {Object} Parameter state without sticky parameters
*/
- mw.rcfilters.dm.FiltersViewModel.prototype.removeExcludedFilters = function ( filterState ) {
- filterState = filterState !== undefined ?
- $.extend( true, {}, filterState ) :
- this.getFiltersFromParameters();
-
- // Remove excluded filters
- Object.keys( this.getExcludedFiltersState() ).forEach( function ( filterName ) {
- delete filterState[ filterName ];
- } );
-
- // Remove sticky filters
- Object.keys( this.getStickyFiltersState() ).forEach( function ( filterName ) {
- delete filterState[ filterName ];
- } );
-
- return filterState;
- };
- /**
- * Delete excluded and sticky parameters from given object. If object isn't given, output
- * the current param state without the excluded values
- *
- * @param {Object} [paramState] Parameter state
- * @return {Object} Parameter state without excluded filters
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.removeExcludedParams = function ( paramState ) {
- paramState = paramState !== undefined ?
- $.extend( true, {}, paramState ) :
- this.getCurrentParameterState();
-
- // Remove excluded filters
- this.getExcludedParams().forEach( function ( paramName ) {
- delete paramState[ paramName ];
- } );
-
- // Remove sticky filters
+ mw.rcfilters.dm.FiltersViewModel.prototype.removeStickyParams = function ( paramState ) {
this.getStickyParams().forEach( function ( paramName ) {
delete paramState[ paramName ];
} );
return paramState;
};
- /**
- * Get the names of all available filters
- *
- * @return {string[]} An array of filter names
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.getFilterNames = function () {
- return this.getItems().map( function ( item ) { return item.getName(); } );
- };
-
/**
* Turn the highlight feature on or off
*/
mw.rcfilters.dm.FiltersViewModel.prototype.getViewTrigger = function ( view ) {
return ( this.views[ view ] && this.views[ view ].trigger ) || '';
};
+
/**
* Get the value of a specific parameter
*
/**
* Get the current selected state of the filters
*
+ * @param {boolean} [onlySelected] return an object containing only the filters with a value
* @return {Object} Filters selected state
*/
- mw.rcfilters.dm.FiltersViewModel.prototype.getSelectedState = function () {
+ mw.rcfilters.dm.FiltersViewModel.prototype.getSelectedState = function ( onlySelected ) {
var i,
items = this.getItems(),
result = {};
for ( i = 0; i < items.length; i++ ) {
- result[ items[ i ].getName() ] = items[ i ].isSelected();
+ if ( !onlySelected || items[ i ].getValue() ) {
+ result[ items[ i ].getName() ] = items[ i ].getValue();
+ }
}
return result;
/**
* Get an object representing default parameters state
*
- * @param {boolean} [excludeHiddenParams] Exclude hidden and sticky params
* @return {Object} Default parameter values
*/
- mw.rcfilters.dm.FiltersViewModel.prototype.getDefaultParams = function ( excludeHiddenParams ) {
+ mw.rcfilters.dm.FiltersViewModel.prototype.getDefaultParams = function () {
var result = {};
// Get default filter state
$.each( this.groups, function ( name, model ) {
- $.extend( true, result, model.getDefaultParams() );
- } );
-
- if ( excludeHiddenParams ) {
- Object.keys( this.getDefaultHiddenParams() ).forEach( function ( paramName ) {
- delete result[ paramName ];
- } );
- }
-
- return result;
- };
-
- /**
- * Get an object representing defaults for the hidden parameters state
- *
- * @return {Object} Default values for hidden parameters
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.getDefaultHiddenParams = function () {
- var result = {};
-
- // Get default filter state
- $.each( this.groups, function ( name, model ) {
- if ( model.isHidden() ) {
+ if ( !model.isSticky() ) {
$.extend( true, result, model.getDefaultParams() );
}
} );
$.each( this.groups, function ( name, model ) {
if ( model.isSticky() ) {
- $.extend( true, result, model.getDefaultParams() );
- }
- } );
-
- return result;
- };
-
- /**
- * Get a filter representation of all sticky parameters
- *
- * @return {Object} Sticky filters values
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.getStickyFiltersState = function () {
- var result = {};
-
- $.each( this.groups, function ( name, model ) {
- if ( model.isSticky() ) {
- $.extend( true, result, model.getSelectedState() );
- }
- } );
-
- return result;
- };
-
- /**
- * Get a filter representation of all parameters that are marked
- * as being excluded from saved query.
- *
- * @return {Object} Excluded filters values
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.getExcludedFiltersState = function () {
- var result = {};
-
- $.each( this.groups, function ( name, model ) {
- if ( model.isExcludedFromSavedQueries() ) {
- $.extend( true, result, model.getSelectedState() );
- }
- } );
-
- return result;
- };
-
- /**
- * Get the parameter names that represent filters that are excluded
- * from saved queries.
- *
- * @return {string[]} Parameter names
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.getExcludedParams = function () {
- var result = [];
-
- $.each( this.groups, function ( name, model ) {
- if ( model.isExcludedFromSavedQueries() ) {
- if ( model.isPerGroupRequestParameter() ) {
- result.push( name );
- } else {
- // Each filter is its own param
- result = result.concat( model.getItems().map( function ( filterItem ) {
- return filterItem.getParamName();
- } ) );
- }
+ $.extend( true, result, model.getParamRepresentation() );
}
} );
// all filters (set to false)
this.getItems().forEach( function ( filterItem ) {
groupItemDefinition[ filterItem.getGroupName() ] = groupItemDefinition[ filterItem.getGroupName() ] || {};
- groupItemDefinition[ filterItem.getGroupName() ][ filterItem.getName() ] = !!filterDefinition[ filterItem.getName() ];
+ groupItemDefinition[ filterItem.getGroupName() ][ filterItem.getName() ] = filterItem.coerceValue( filterDefinition[ filterItem.getName() ] );
} );
}
};
/**
- * Check whether the current filter state is set to all false.
+ * Check whether no visible filter is selected.
+ *
+ * Filter groups that are hidden or sticky are not shown in the
+ * active filters area and therefore not included in this check.
*
- * @return {boolean} Current filters are all empty
+ * @return {boolean} No visible filter is selected
*/
- mw.rcfilters.dm.FiltersViewModel.prototype.areCurrentFiltersEmpty = function () {
+ mw.rcfilters.dm.FiltersViewModel.prototype.areVisibleFiltersEmpty = function () {
// Check if there are either any selected items or any items
// that have highlight enabled
return !this.getItems().some( function ( filterItem ) {
- return !filterItem.getGroupModel().isHidden() && ( filterItem.isSelected() || filterItem.isHighlighted() );
+ var visible = !filterItem.getGroupModel().isSticky() && !filterItem.getGroupModel().isHidden(),
+ active = ( filterItem.isSelected() || filterItem.isHighlighted() );
+ return visible && active;
} );
};
+ /**
+ * Check whether the invert state is a valid one. A valid invert state is one where
+ * there are actual namespaces selected.
+ *
+ * This is done to compare states to previous ones that may have had the invert model
+ * selected but effectively had no namespaces, so are not effectively different than
+ * ones where invert is not selected.
+ *
+ * @return {boolean} Invert is effectively selected
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.areNamespacesEffectivelyInverted = function () {
+ return this.getInvertModel().isSelected() &&
+ this.getSelectedItems().some( function ( itemModel ) {
+ return itemModel.getGroupModel().getName() === 'namespace';
+ } );
+ };
+
/**
* Get the item that matches the given name
*
return allSelected;
};
- /**
- * Switch the current view
- *
- * @param {string} view View name
- * @fires update
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.switchView = function ( view ) {
- if ( this.views[ view ] && this.currentView !== view ) {
- this.currentView = view;
- this.emit( 'update' );
- }
- };
/**
* Get the current view
return this.views[ viewName ] && this.views[ viewName ].title;
};
- /**
- * Get an array of all available view names
- *
- * @return {string} Available view names
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.getAvailableViews = function () {
- return Object.keys( this.views );
- };
-
/**
* Get the view that fits the given trigger
*
return result;
};
+ /**
+ * Return a version of the given string that is without any
+ * view triggers.
+ *
+ * @param {string} str Given string
+ * @return {string} Result
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.removeViewTriggers = function ( str ) {
+ if ( this.getViewFromString( str ) !== 'default' ) {
+ str = str.substr( 1 );
+ }
+
+ return str;
+ };
+
+ /**
+ * Get the view from the given string by a trigger, if it exists
+ *
+ * @param {string} str Given string
+ * @return {string} View name
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.getViewFromString = function ( str ) {
+ return this.getViewByTrigger( str.substr( 0, 1 ) );
+ };
+
+ /**
+ * Set the current search for the system.
+ * This also dictates what items and groups are visible according
+ * to the search in #findMatches
+ *
+ * @param {string} searchQuery Search query, including triggers
+ * @fires searchChange
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.setSearch = function ( searchQuery ) {
+ var visibleGroups, visibleGroupNames;
+
+ if ( this.searchQuery !== searchQuery ) {
+ // Check if the view changed
+ this.switchView( this.getViewFromString( searchQuery ) );
+
+ visibleGroups = this.findMatches( searchQuery );
+ visibleGroupNames = Object.keys( visibleGroups );
+
+ // Update visibility of items and groups
+ $.each( this.getFilterGroups(), function ( groupName, groupModel ) {
+ // Check if the group is visible at all
+ groupModel.toggleVisible( visibleGroupNames.indexOf( groupName ) !== -1 );
+ groupModel.setVisibleItems( visibleGroups[ groupName ] || [] );
+ } );
+
+ this.searchQuery = searchQuery;
+ this.emit( 'searchChange', this.searchQuery );
+ }
+ };
+
+ /**
+ * Get the current search
+ *
+ * @return {string} Current search query
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.getSearch = function () {
+ return this.searchQuery;
+ };
+
+ /**
+ * Switch the current view
+ *
+ * @private
+ * @param {string} view View name
+ */
+ mw.rcfilters.dm.FiltersViewModel.prototype.switchView = function ( view ) {
+ if ( this.views[ view ] && this.currentView !== view ) {
+ this.currentView = view;
+ }
+ };
+
/**
* Toggle the highlight feature on and off.
* Propagate the change to filter items.
this.getItemByName( filterName ).clearHighlightColor();
};
- /**
- * Return a version of the given string that is without any
- * view triggers.
- *
- * @param {string} str Given string
- * @return {string} Result
- */
- mw.rcfilters.dm.FiltersViewModel.prototype.removeViewTriggers = function ( str ) {
- if ( this.getViewByTrigger( str.substr( 0, 1 ) ) !== 'default' ) {
- str = str.substr( 1 );
- }
-
- return str;
- };
}( mediaWiki, jQuery ) );