3 * View model for the filters selection and display
5 * @mixins OO.EventEmitter
6 * @mixins OO.EmitterList
10 mw
.rcfilters
.dm
.FiltersViewModel
= function MwRcfiltersDmFiltersViewModel() {
12 OO
.EventEmitter
.call( this );
13 OO
.EmitterList
.call( this );
18 this.aggregate( { update
: 'itemUpdate' } );
22 OO
.initClass( mw
.rcfilters
.dm
.FiltersViewModel
);
23 OO
.mixinClass( mw
.rcfilters
.dm
.FiltersViewModel
, OO
.EventEmitter
);
24 OO
.mixinClass( mw
.rcfilters
.dm
.FiltersViewModel
, OO
.EmitterList
);
31 * Filter list is initialized
36 * @param {mw.rcfilters.dm.FilterItem} item Filter item updated
38 * Filter item has changed
44 * Set filters and preserve a group relationship based on
45 * the definition given by an object
47 * @param {Object} filters Filter group definition
49 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.initializeFilters = function ( filters
) {
58 $.each( filters
, function ( group
, data
) {
59 model
.groups
[ group
] = model
.groups
[ group
] || {};
60 model
.groups
[ group
].filters
= model
.groups
[ group
].filters
|| [];
62 model
.groups
[ group
].title
= data
.title
;
63 model
.groups
[ group
].type
= data
.type
;
65 for ( i
= 0; i
< data
.filters
.length
; i
++ ) {
66 filterItem
= new mw
.rcfilters
.dm
.FilterItem( data
.filters
[ i
].name
, {
68 label
: data
.filters
[ i
].label
,
69 description
: data
.filters
[ i
].description
,
70 selected
: data
.filters
[ i
].selected
73 model
.groups
[ group
].filters
.push( filterItem
);
74 items
.push( filterItem
);
78 this.addItems( items
);
79 this.emit( 'initialize' );
83 * Get the names of all available filters
85 * @return {string[]} An array of filter names
87 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.getFilterNames = function () {
88 return this.getItems().map( function ( item
) { return item
.getName(); } );
92 * Get the object that defines groups and their filter items.
93 * The structure of this response:
96 * title: {string} Group title
97 * type: {string} Group type
98 * filters: {string[]} Filters in the group
102 * @return {Object} Filter groups
104 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.getFilterGroups = function () {
109 * Get the current state of the filters
111 * @return {Object} Filters current state
113 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.getState = function () {
115 items
= this.getItems(),
118 for ( i
= 0; i
< items
.length
; i
++ ) {
119 result
[ items
[ i
].getName() ] = items
[ i
].isSelected();
126 * Analyze the groups and their filters and output an object representing
127 * the state of the parameters they represent.
129 * @return {Object} Parameter state object
131 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.getParametersFromFilters = function () {
132 var i
, filterItems
, anySelected
,
134 groupItems
= this.getFilterGroups();
136 $.each( groupItems
, function ( group
, data
) {
137 if ( data
.type
=== 'send_unselected_if_any' ) {
138 filterItems
= data
.filters
;
140 // First, check if any of the items are selected at all.
141 // If none is selected, we're treating it as if they are
143 anySelected
= filterItems
.some( function ( filterItem
) {
144 return filterItem
.isSelected();
147 // Go over the items and define the correct values
148 for ( i
= 0; i
< filterItems
.length
; i
++ ) {
149 result
[ filterItems
[ i
].getName() ] = anySelected
?
150 Number( !filterItems
[ i
].isSelected() ) : 0;
159 * This is the opposite of the #getParametersFromFilters method; this goes over
160 * the parameters and translates into a selected/unselected value in the filters.
162 * @param {Object} params Parameters query object
163 * @return {Object} Filter state object
165 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.getFiltersFromParameters = function ( params
) {
166 var i
, filterItem
, allItemsInGroup
,
169 base
= this.getParametersFromFilters(),
170 // Start with current state
171 result
= this.getState();
173 params
= $.extend( {}, base
, params
);
175 $.each( params
, function ( paramName
, paramValue
) {
176 // Find the filter item
177 filterItem
= model
.getItemByName( paramName
);
179 // Ignore if no filter item exists
181 groupMap
[ filterItem
.getGroup() ] = groupMap
[ filterItem
.getGroup() ] || {};
183 // Mark the group if it has any items that are selected
184 groupMap
[ filterItem
.getGroup() ].hasSelected
= (
185 groupMap
[ filterItem
.getGroup() ].hasSelected
||
186 !!Number( paramValue
)
189 // Add the relevant filter into the group map
190 groupMap
[ filterItem
.getGroup() ].filters
= groupMap
[ filterItem
.getGroup() ].filters
|| [];
191 groupMap
[ filterItem
.getGroup() ].filters
.push( filterItem
);
195 // Now that we know the groups' selection states, we need to go over
196 // the filters in the groups and mark their selected states appropriately
197 $.each( groupMap
, function ( group
, data
) {
198 if ( model
.groups
[ group
].type
=== 'send_unselected_if_any' ) {
199 allItemsInGroup
= model
.groups
[ group
].filters
;
201 for ( i
= 0; i
< allItemsInGroup
.length
; i
++ ) {
202 filterItem
= allItemsInGroup
[ i
];
204 result
[ filterItem
.getName() ] = data
.hasSelected
?
205 // Flip the definition between the parameter
206 // state and the filter state
207 // This is what the 'toggleSelected' value of the filter is
208 !Number( params
[ filterItem
.getName() ] ) :
209 // Otherwise, there are no selected items in the
210 // group, which means the state is false
219 * Get the item that matches the given name
221 * @param {string} name Filter name
222 * @return {mw.rcfilters.dm.FilterItem} Filter item
224 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.getItemByName = function ( name
) {
225 return this.getItems().filter( function ( item
) {
226 return name
=== item
.getName();
231 * Toggle selected state of items by their names
233 * @param {Object} filterDef Filter definitions
235 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.updateFilters = function ( filterDef
) {
236 var name
, filterItem
;
238 for ( name
in filterDef
) {
239 filterItem
= this.getItemByName( name
);
240 filterItem
.toggleSelected( filterDef
[ name
] );
245 * Find items whose labels match the given string
247 * @param {string} str Search string
248 * @return {Object} An object of items to show
249 * arranged by their group names
251 mw
.rcfilters
.dm
.FiltersViewModel
.prototype.findMatches = function ( str
) {
254 items
= this.getItems();
256 // Normalize so we can search strings regardless of case
257 str
= str
.toLowerCase();
258 for ( i
= 0; i
< items
.length
; i
++ ) {
259 if ( items
[ i
].getLabel().toLowerCase().indexOf( str
) > -1 ) {
260 result
[ items
[ i
].getGroup() ] = result
[ items
[ i
].getGroup() ] || [];
261 result
[ items
[ i
].getGroup() ].push( items
[ i
] );
267 }( mediaWiki
, jQuery
) );