3 * View model for saved queries
6 * @mixins OO.EventEmitter
7 * @mixins OO.EmitterList
10 * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters model
11 * @param {Object} [config] Configuration options
12 * @cfg {string} [default] Default query ID
14 mw
.rcfilters
.dm
.SavedQueriesModel
= function MwRcfiltersDmSavedQueriesModel( filtersModel
, config
) {
15 config
= config
|| {};
18 OO
.EventEmitter
.call( this );
19 OO
.EmitterList
.call( this );
21 this.default = config
.default;
22 this.filtersModel
= filtersModel
;
23 this.converted
= false;
26 this.aggregate( { update
: 'itemUpdate' } );
31 OO
.initClass( mw
.rcfilters
.dm
.SavedQueriesModel
);
32 OO
.mixinClass( mw
.rcfilters
.dm
.SavedQueriesModel
, OO
.EventEmitter
);
33 OO
.mixinClass( mw
.rcfilters
.dm
.SavedQueriesModel
, OO
.EmitterList
);
40 * Model is initialized
45 * @param {mw.rcfilters.dm.SavedQueryItemModel} Changed item
52 * @param {string} New default ID
54 * The default has changed
60 * Initialize the saved queries model by reading it from the user's settings.
61 * The structure of the saved queries is:
63 * version: (string) Version number; if version 2, the query represents
64 * parameters. Otherwise, the older version represented filters
65 * and needs to be readjusted,
66 * default: (string) Query ID
70 * filters: (Object) Minimal definition of the filters
71 * highlights: (Object) Definition of the highlights
73 * label: (optional) Name of this query
78 * @param {Object} [savedQueries] An object with the saved queries with
79 * the above structure.
82 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.initialize = function ( savedQueries
) {
85 savedQueries
= savedQueries
|| {};
89 this.converted
= false;
91 if ( savedQueries
.version
!== '2' ) {
92 // Old version dealt with filter names. We need to migrate to the new structure
95 // version: (string) '2',
96 // default: (string) Query ID,
99 // label: (string) Name of the query
101 // params: (object) Representing all the parameter states
102 // highlights: (object) Representing all the filter highlight states
106 $.each( savedQueries
.queries
|| {}, function ( id
, obj
) {
107 if ( obj
.data
&& obj
.data
.filters
) {
108 obj
.data
= model
.convertToParameters( obj
.data
);
112 this.converted
= true;
113 savedQueries
.version
= '2';
116 // Initialize the query items
117 $.each( savedQueries
.queries
|| {}, function ( id
, obj
) {
118 var normalizedData
= obj
.data
,
119 isDefault
= String( savedQueries
.default ) === String( id
);
121 if ( normalizedData
&& normalizedData
.params
) {
122 // Backwards-compat fix: Remove excluded parameters from
123 // the given data, if they exist
124 normalizedData
.params
= model
.filtersModel
.removeExcludedParams( normalizedData
.params
);
128 // Skip the addNewQuery method because we don't want to unnecessarily manipulate
129 // the given saved queries unless we literally intend to (like in backwards compat fixes)
130 // And the addNewQuery method also uses a minimization routine that checks for the
131 // validity of items and minimizes the query. This isn't necessary for queries loaded
132 // from the backend, and has the risk of removing values if they're temporarily
133 // invalid (example: if we temporarily removed a cssClass from a filter in the backend)
135 new mw
.rcfilters
.dm
.SavedQueryItemModel(
139 { 'default': isDefault
}
149 this.emit( 'initialize' );
153 * Convert from representation of filters to representation of parameters
155 * @param {Object} data Query data
156 * @return {Object} New converted query data
158 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.convertToParameters = function ( data
) {
160 defaultFilters
= this.filtersModel
.getFiltersFromParameters( this.filtersModel
.getDefaultParams() ),
161 fullFilterRepresentation
= $.extend( true, {}, defaultFilters
, data
.filters
),
162 highlightEnabled
= data
.highlights
.highlight
;
164 delete data
.highlights
.highlight
;
167 newData
.params
= this.filtersModel
.getMinimizedParamRepresentation(
168 this.filtersModel
.getParametersFromFilters( fullFilterRepresentation
)
171 // Highlights (taking out 'highlight' itself, appending _color to keys)
172 newData
.highlights
= {};
173 $.each( data
.highlights
, function ( highlightedFilterName
, value
) {
175 newData
.highlights
[ highlightedFilterName
+ '_color' ] = data
.highlights
[ highlightedFilterName
];
180 newData
.params
.highlight
= String( Number( highlightEnabled
|| 0 ) );
188 * @param {string} label Label for the new query
189 * @param {Object} fulldata Full data representation for the new query, combining highlights and filters
190 * @param {boolean} isDefault Item is default
191 * @param {string} [id] Query ID, if exists. If this isn't given, a random
192 * new ID will be created.
193 * @return {string} ID of the newly added query
195 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.addNewQuery = function ( label
, fulldata
, isDefault
, id
) {
196 var normalizedData
= { params
: {}, highlights
: {} },
197 highlightParamNames
= Object
.keys( this.filtersModel
.getEmptyHighlightParameters() ),
198 randomID
= String( id
|| ( new Date() ).getTime() ),
199 data
= this.filtersModel
.getMinimizedParamRepresentation( fulldata
);
201 // Split highlight/params
202 $.each( data
, function ( param
, value
) {
203 if ( param
!== 'highlight' && highlightParamNames
.indexOf( param
) > -1 ) {
204 normalizedData
.highlights
[ param
] = value
;
206 normalizedData
.params
[ param
] = value
;
212 new mw
.rcfilters
.dm
.SavedQueryItemModel(
216 { 'default': isDefault
}
221 this.setDefault( randomID
);
228 * Remove query from model
230 * @param {string} queryID Query ID
232 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.removeQuery = function ( queryID
) {
233 var query
= this.getItemByID( queryID
);
236 // Check if this item was the default
237 if ( String( this.getDefault() ) === String( queryID
) ) {
238 // Nulify the default
239 this.setDefault( null );
242 this.removeItems( [ query
] );
247 * Get an item that matches the requested query
249 * @param {Object} fullQueryComparison Object representing all filters and highlights to compare
250 * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model
252 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.findMatchingQuery = function ( fullQueryComparison
) {
253 // Minimize before comparison
254 fullQueryComparison
= this.filtersModel
.getMinimizedParamRepresentation( fullQueryComparison
);
256 return this.getItems().filter( function ( item
) {
258 item
.getCombinedData(),
265 * Get query by its identifier
267 * @param {string} queryID Query identifier
268 * @return {mw.rcfilters.dm.SavedQueryItemModel|undefined} Item matching
269 * the search. Undefined if not found.
271 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.getItemByID = function ( queryID
) {
272 return this.getItems().filter( function ( item
) {
273 return item
.getID() === queryID
;
278 * Get the full data representation of the default query, if it exists
280 * @param {boolean} [excludeHiddenParams] Exclude hidden parameters in the result
281 * @return {Object|null} Representation of the default params if exists.
282 * Null if default doesn't exist or if the user is not logged in.
284 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.getDefaultParams = function ( excludeHiddenParams
) {
285 var data
= ( !mw
.user
.isAnon() && this.getItemParams( this.getDefault() ) ) || {};
287 if ( excludeHiddenParams
) {
288 Object
.keys( this.filtersModel
.getDefaultHiddenParams() ).forEach( function ( paramName
) {
289 delete data
[ paramName
];
297 * Get a full parameter representation of an item data
299 * @param {Object} queryID Query ID
300 * @return {Object} Parameter representation
302 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.getItemParams = function ( queryID
) {
303 var item
= this.getItemByID( queryID
),
304 data
= item
? item
.getData() : {};
306 return !$.isEmptyObject( data
) ? this.buildParamsFromData( data
) : {};
310 * Build a full parameter representation given item data and model sticky values state
312 * @param {Object} data Item data
313 * @return {Object} Full param representation
315 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.buildParamsFromData = function ( data
) {
316 // Merge saved filter state with sticky filter values
321 // In order to merge sticky filters with the data, we have to
322 // transform this to filters first, merge, and then back to
324 savedFilters
= $.extend(
326 this.filtersModel
.getFiltersFromParameters( data
.params
),
327 this.filtersModel
.getStickyFiltersState()
330 // Return parameter representation
331 return this.filtersModel
.getMinimizedParamRepresentation( $.extend( true, {},
332 this.filtersModel
.getParametersFromFilters( savedFilters
),
334 { highlight
: data
.params
.highlight
}
339 * Get the object representing the state of the entire model and items
341 * @return {Object} Object representing the state of the model and items
343 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.getState = function () {
344 var obj
= { queries
: {}, version
: '2' };
346 // Translate the items to the saved object
347 this.getItems().forEach( function ( item
) {
348 obj
.queries
[ item
.getID() ] = item
.getState();
351 if ( this.getDefault() ) {
352 obj
.default = this.getDefault();
359 * Set a default query. Null to unset default.
361 * @param {string} itemID Query identifier
364 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.setDefault = function ( itemID
) {
365 if ( this.default !== itemID
) {
366 this.default = itemID
;
368 // Set for individual itens
369 this.getItems().forEach( function ( item
) {
370 item
.toggleDefault( item
.getID() === itemID
);
373 this.emit( 'default', itemID
);
378 * Get the default query ID
380 * @return {string} Default query identifier
382 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.getDefault = function () {
387 * Check if the saved queries were converted
389 * @return {boolean} Saved queries were converted from the previous
390 * version to the new version
392 mw
.rcfilters
.dm
.SavedQueriesModel
.prototype.isConverted = function () {
393 return this.converted
;
395 }( mediaWiki
, jQuery
) );