* @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view model
*/
mw.rcfilters.UriProcessor = function MwRcfiltersController( filtersModel ) {
- this.emptyParameterState = {};
this.filtersModel = filtersModel;
-
- // Initialize
- this._buildEmptyParameterState();
};
/* Initialization */
};
/**
- * Update the filters model based on the URI query
- * This happens on initialization, and from this moment on,
- * we consider the system synchronized, and the model serves
- * as the source of truth for the URL.
- *
- * This methods should only be called once on initialiation.
- * After initialization, the model updates the URL, not the
- * other way around.
- *
- * @param {Object} [uriQuery] URI query
+ * Replace the current URI with an updated one from the model state
*/
- mw.rcfilters.UriProcessor.prototype.updateModelBasedOnQuery = function ( uriQuery ) {
- var parameters;
-
- uriQuery = uriQuery || new mw.Uri().query;
-
- // For arbitrary numeric single_option values, check the uri and see if it's beyond the limit
- $.each( this.filtersModel.getFilterGroups(), function ( groupName, groupModel ) {
- if (
- groupModel.getType() === 'single_option' &&
- groupModel.isAllowArbitrary()
- ) {
- if (
- groupModel.getMaxValue() !== null &&
- uriQuery[ groupName ] > groupModel.getMaxValue()
- ) {
- // Change the value to the actual max value
- uriQuery[ groupName ] = String( groupModel.getMaxValue() );
- } else if (
- groupModel.getMinValue() !== null &&
- uriQuery[ groupName ] < groupModel.getMinValue()
- ) {
- // Change the value to the actual min value
- uriQuery[ groupName ] = String( groupModel.getMinValue() );
- }
- }
- } );
-
- // Normalize
- parameters = this._getNormalizedQueryParams( uriQuery );
+ mw.rcfilters.UriProcessor.prototype.replaceUpdatedUri = function () {
+ this.constructor.static.replaceState( this.getUpdatedUri() );
+ };
- // Update filter states
- this.filtersModel.toggleFiltersSelected(
- this.filtersModel.getFiltersFromParameters(
- parameters
+ /**
+ * Get an updated mw.Uri object based on the model state
+ *
+ * @param {Object} [uriQuery] An external URI query to build the new uri
+ * with. This is mainly for tests, to be able to supply external parameters
+ * and make sure they are retained.
+ * @return {mw.Uri} Updated Uri
+ */
+ mw.rcfilters.UriProcessor.prototype.getUpdatedUri = function ( uriQuery ) {
+ var uri = new mw.Uri(),
+ unrecognizedParams = this.getUnrecognizedParams( uriQuery || uri.query );
+
+ if ( uriQuery ) {
+ // This is mainly for tests, to be able to give the method
+ // an initial URI Query and test that it retains parameters
+ uri.query = uriQuery;
+ }
+
+ uri.query = this.filtersModel.getMinimizedParamRepresentation(
+ $.extend(
+ true,
+ {},
+ uri.query,
+ // The representation must be expanded so it can
+ // override the uri query params but we then output
+ // a minimized version for the entire URI representation
+ // for the method
+ this.filtersModel.getExpandedParamRepresentation()
)
);
- this.filtersModel.toggleInvertedNamespaces( !!Number( parameters.invert ) );
+ // Reapply unrecognized params and url version
+ uri.query = $.extend( true, {}, uri.query, unrecognizedParams, { urlversion: '2' } );
+
+ return uri;
+ };
- // Update highlight state
- this.filtersModel.getItems().forEach( function ( filterItem ) {
- var color = parameters[ filterItem.getName() + '_color' ];
- if ( color ) {
- filterItem.setHighlightColor( color );
- } else {
- filterItem.clearHighlightColor();
+ /**
+ * Get an object representing given parameters that are unrecognized by the model
+ *
+ * @param {Object} params Full params object
+ * @return {Object} Unrecognized params
+ */
+ mw.rcfilters.UriProcessor.prototype.getUnrecognizedParams = function ( params ) {
+ // Start with full representation
+ var givenParamNames = Object.keys( params ),
+ unrecognizedParams = $.extend( true, {}, params );
+
+ // Extract unrecognized parameters
+ Object.keys( this.filtersModel.getEmptyParameterState() ).forEach( function ( paramName ) {
+ // Remove recognized params
+ if ( givenParamNames.indexOf( paramName ) > -1 ) {
+ delete unrecognizedParams[ paramName ];
}
} );
- this.filtersModel.toggleHighlight( !!Number( parameters.highlight ) );
- // Check all filter interactions
- this.filtersModel.reassessFilterInteractions();
+ return unrecognizedParams;
};
/**
- * Get parameters representing the current state of the model
+ * Update the URL of the page to reflect current filters
+ *
+ * This should not be called directly from outside the controller.
+ * If an action requires changing the URL, it should either use the
+ * highlighting actions below, or call #updateChangesList which does
+ * the uri corrections already.
*
- * @return {Object} Uri query parameters
+ * @param {Object} [params] Extra parameters to add to the API call
*/
- mw.rcfilters.UriProcessor.prototype.getUriParametersFromModel = function () {
- return $.extend(
- true,
- {},
- this.filtersModel.getParametersFromFilters(),
- this.filtersModel.getHighlightParameters(),
- {
- highlight: String( Number( this.filtersModel.isHighlightEnabled() ) ),
- invert: String( Number( this.filtersModel.areNamespacesInverted() ) )
- }
- );
+ mw.rcfilters.UriProcessor.prototype.updateURL = function ( params ) {
+ var currentUri = new mw.Uri(),
+ updatedUri = this.getUpdatedUri();
+
+ updatedUri.extend( params || {} );
+
+ if (
+ this.getVersion( currentUri.query ) !== 2 ||
+ this.isNewState( currentUri.query, updatedUri.query )
+ ) {
+ this.constructor.static.replaceState( updatedUri );
+ }
};
/**
- * Build the full parameter representation based on given query parameters
+ * Update the filters model based on the URI query
+ * This happens on initialization, and from this moment on,
+ * we consider the system synchronized, and the model serves
+ * as the source of truth for the URL.
*
- * @private
- * @param {Object} uriQuery Given URI query
- * @return {Object} Full parameter state representing the URI query
+ * This methods should only be called once on initialiation.
+ * After initialization, the model updates the URL, not the
+ * other way around.
+ *
+ * @param {Object} [uriQuery] URI query
*/
- mw.rcfilters.UriProcessor.prototype._expandModelParameters = function ( uriQuery ) {
- var filterRepresentation = this.filtersModel.getFiltersFromParameters( uriQuery );
-
- return $.extend( true,
- {},
- uriQuery,
- this.filtersModel.getParametersFromFilters( filterRepresentation ),
- this.filtersModel.extractHighlightValues( uriQuery ),
- {
- highlight: String( Number( uriQuery.highlight ) ),
- invert: String( Number( uriQuery.invert ) )
- }
+ mw.rcfilters.UriProcessor.prototype.updateModelBasedOnQuery = function ( uriQuery ) {
+ this.filtersModel.updateStateFromParams(
+ this._getNormalizedQueryParams( uriQuery || new mw.Uri().query )
);
};
// This will allow us to always have a proper check of whether
// the requested new url is one to change or not, regardless of
// actual parameter visibility/representation in the URL
- currentParamState = this._expandModelParameters( currentUriQuery );
- updatedParamState = this._expandModelParameters( updatedUriQuery );
+ currentParamState = $.extend(
+ true,
+ {},
+ this.filtersModel.getMinimizedParamRepresentation( currentUriQuery ),
+ this.getUnrecognizedParams( currentUriQuery )
+ );
+ updatedParamState = $.extend(
+ true,
+ {},
+ this.filtersModel.getMinimizedParamRepresentation( updatedUriQuery ),
+ this.getUnrecognizedParams( updatedUriQuery )
+ );
return notEquivalent( currentParamState, updatedParamState );
};
*/
mw.rcfilters.UriProcessor.prototype.doesQueryContainRecognizedParams = function ( uriQuery ) {
var anyValidInUrl,
- validParameterNames = Object.keys( this._getEmptyParameterState() )
+ validParameterNames = Object.keys( this.filtersModel.getEmptyParameterState() )
.filter( function ( param ) {
// Remove 'highlight' parameter from this check;
// if it's the only parameter in the URL we still
return anyValidInUrl || this.getVersion( uriQuery ) === 2;
};
- /**
- * Remove all parameters that have the same value as the base state
- * This method expects uri queries of the urlversion=2 format
- *
- * @private
- * @param {Object} uriQuery Current uri query
- * @return {Object} Minimized query
- */
- mw.rcfilters.UriProcessor.prototype.minimizeQuery = function ( uriQuery ) {
- var baseParams = this._getEmptyParameterState(),
- uriResult = $.extend( true, {}, uriQuery );
-
- $.each( uriResult, function ( paramName, paramValue ) {
- if (
- baseParams[ paramName ] !== undefined &&
- baseParams[ paramName ] === paramValue
- ) {
- // Remove parameter from query
- delete uriResult[ paramName ];
- }
- } );
-
- return uriResult;
- };
-
/**
* Get the adjusted URI params based on the url version
* If the urlversion is not 2, the parameters are merged with
* the model's defaults.
+ * Always merge in the hidden parameter defaults.
*
* @private
* @param {Object} uriQuery Current URI query
// wiki default.
// Any subsequent change of the URL through the RCFilters
// system will receive 'urlversion=2'
- var hiddenParamDefaults = {},
+ var hiddenParamDefaults = this.filtersModel.getDefaultHiddenParams(),
base = this.getVersion( uriQuery ) === 2 ?
{} :
this.filtersModel.getDefaultParams();
- // Go over the model and get all hidden parameters' defaults
- // These defaults should be applied regardless of the urlversion
- // but be overridden by the URL params if they exist
- $.each( this.filtersModel.getFilterGroups(), function ( groupName, groupModel ) {
- if ( groupModel.isHidden() ) {
- $.extend( true, hiddenParamDefaults, groupModel.getDefaultParams() );
- }
- } );
-
- return this.minimizeQuery(
- $.extend( true, {}, hiddenParamDefaults, base, uriQuery, { urlversion: '2' } )
- );
- };
-
- /**
- * Get the representation of an empty parameter state
- *
- * @private
- * @return {Object} Empty parameter state
- */
- mw.rcfilters.UriProcessor.prototype._getEmptyParameterState = function () {
- // Override empty parameter state with the sticky parameter values
- return $.extend( true, {}, this.emptyParameterState, this.filtersModel.getStickyParams() );
- };
-
- /**
- * Build an empty representation of the parameters, where all parameters
- * are either set to '0' or '' depending on their type.
- * This must run during initialization, before highlights are set.
- *
- * @private
- */
- mw.rcfilters.UriProcessor.prototype._buildEmptyParameterState = function () {
- var emptyParams = this.filtersModel.getParametersFromFilters( {} ),
- emptyHighlights = this.filtersModel.getEmptyHighlightParameters();
-
- this.emptyParameterState = $.extend(
+ return $.extend(
true,
{},
- emptyParams,
- emptyHighlights,
- { highlight: '0', invert: '0' }
+ this.filtersModel.getMinimizedParamRepresentation(
+ $.extend( true, {}, hiddenParamDefaults, base, uriQuery )
+ ),
+ { urlversion: '2' }
);
};
}( mediaWiki, jQuery ) );