3 * View model for a filter group
5 * @mixins OO.EventEmitter
6 * @mixins OO.EmitterList
9 * @param {string} name Group name
10 * @param {Object} [config] Configuration options
11 * @cfg {string} [type='send_unselected_if_any'] Group type
12 * @cfg {string} [title] Group title
13 * @cfg {string} [separator='|'] Value separator for 'string_options' groups
14 * @cfg {boolean} [active] Group is active
15 * @cfg {boolean} [fullCoverage] This filters in this group collectively cover all results
16 * @cfg {Object} [conflicts] Defines the conflicts for this filter group
17 * @cfg {Object} [whatsThis] Defines the messages that should appear for the 'what's this' popup
18 * @cfg {string} [whatsThis.header] The header of the whatsThis popup message
19 * @cfg {string} [whatsThis.body] The body of the whatsThis popup message
20 * @cfg {string} [whatsThis.url] The url for the link in the whatsThis popup message
21 * @cfg {string} [whatsThis.linkMessage] The text for the link in the whatsThis popup message
23 mw
.rcfilters
.dm
.FilterGroup
= function MwRcfiltersDmFilterGroup( name
, config
) {
24 config
= config
|| {};
27 OO
.EventEmitter
.call( this );
28 OO
.EmitterList
.call( this );
31 this.type
= config
.type
|| 'send_unselected_if_any';
32 this.title
= config
.title
;
33 this.separator
= config
.separator
|| '|';
35 this.active
= !!config
.active
;
36 this.fullCoverage
= !!config
.fullCoverage
;
38 this.whatsThis
= config
.whatsThis
|| {};
40 this.conflicts
= config
.conflicts
|| {};
42 this.aggregate( { update
: 'filterItemUpdate' } );
43 this.connect( this, { filterItemUpdate
: 'onFilterItemUpdate' } );
47 OO
.initClass( mw
.rcfilters
.dm
.FilterGroup
);
48 OO
.mixinClass( mw
.rcfilters
.dm
.FilterGroup
, OO
.EventEmitter
);
49 OO
.mixinClass( mw
.rcfilters
.dm
.FilterGroup
, OO
.EmitterList
);
56 * Group state has been updated
62 * Respond to filterItem update event
66 mw
.rcfilters
.dm
.FilterGroup
.prototype.onFilterItemUpdate = function () {
68 var active
= this.areAnySelected();
70 if ( this.active
!== active
) {
72 this.emit( 'update' );
77 * Get group active state
79 * @return {boolean} Active state
81 mw
.rcfilters
.dm
.FilterGroup
.prototype.isActive = function () {
88 * @return {string} Group name
90 mw
.rcfilters
.dm
.FilterGroup
.prototype.getName = function () {
95 * Get the messags defining the 'whats this' popup for this group
97 * @return {Object} What's this messages
99 mw
.rcfilters
.dm
.FilterGroup
.prototype.getWhatsThis = function () {
100 return this.whatsThis
;
104 * Check whether this group has a 'what's this' message
106 * @return {boolean} This group has a what's this message
108 mw
.rcfilters
.dm
.FilterGroup
.prototype.hasWhatsThis = function () {
109 return !!this.whatsThis
.body
;
113 * Get the conflicts associated with the entire group.
114 * Conflict object is set up by filter name keys and conflict
115 * definition. For example:
119 * filter: filterName,
125 * filter: filterName2,
130 * @return {Object} Conflict definition
132 mw
.rcfilters
.dm
.FilterGroup
.prototype.getConflicts = function () {
133 return this.conflicts
;
137 * Set conflicts for this group. See #getConflicts for the expected
138 * structure of the definition.
140 * @param {Object} conflicts Conflicts for this group
142 mw
.rcfilters
.dm
.FilterGroup
.prototype.setConflicts = function ( conflicts
) {
143 this.conflicts
= conflicts
;
147 * Check whether this item has a potential conflict with the given item
149 * This checks whether the given item is in the list of conflicts of
150 * the current item, but makes no judgment about whether the conflict
151 * is currently at play (either one of the items may not be selected)
153 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
154 * @return {boolean} This item has a conflict with the given item
156 mw
.rcfilters
.dm
.FilterGroup
.prototype.existsInConflicts = function ( filterItem
) {
157 return Object
.prototype.hasOwnProperty
.call( this.getConflicts(), filterItem
.getName() );
161 * Check whether there are any items selected
163 * @return {boolean} Any items in the group are selected
165 mw
.rcfilters
.dm
.FilterGroup
.prototype.areAnySelected = function () {
166 return this.getItems().some( function ( filterItem
) {
167 return filterItem
.isSelected();
172 * Check whether all items selected
174 * @return {boolean} All items are selected
176 mw
.rcfilters
.dm
.FilterGroup
.prototype.areAllSelected = function () {
177 return this.getItems().every( function ( filterItem
) {
178 return filterItem
.isSelected();
183 * Get all selected items in this group
185 * @param {mw.rcfilters.dm.FilterItem} [excludeItem] Item to exclude from the list
186 * @return {mw.rcfilters.dm.FilterItem[]} Selected items
188 mw
.rcfilters
.dm
.FilterGroup
.prototype.getSelectedItems = function ( excludeItem
) {
189 var excludeName
= ( excludeItem
&& excludeItem
.getName() ) || '';
191 return this.getItems().filter( function ( item
) {
192 return item
.getName() !== excludeName
&& item
.isSelected();
197 * Check whether all selected items are in conflict with the given item
199 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
200 * @return {boolean} All selected items are in conflict with this item
202 mw
.rcfilters
.dm
.FilterGroup
.prototype.areAllSelectedInConflictWith = function ( filterItem
) {
203 var selectedItems
= this.getSelectedItems( filterItem
);
205 return selectedItems
.length
> 0 &&
207 // The group as a whole is in conflict with this item
208 this.existsInConflicts( filterItem
) ||
209 // All selected items are in conflict individually
210 selectedItems
.every( function ( selectedFilter
) {
211 return selectedFilter
.existsInConflicts( filterItem
);
217 * Check whether any of the selected items are in conflict with the given item
219 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
220 * @return {boolean} Any of the selected items are in conflict with this item
222 mw
.rcfilters
.dm
.FilterGroup
.prototype.areAnySelectedInConflictWith = function ( filterItem
) {
223 var selectedItems
= this.getSelectedItems( filterItem
);
225 return selectedItems
.length
> 0 && (
226 // The group as a whole is in conflict with this item
227 this.existsInConflicts( filterItem
) ||
228 // Any selected items are in conflict individually
229 selectedItems
.some( function ( selectedFilter
) {
230 return selectedFilter
.existsInConflicts( filterItem
);
236 * Get the parameter representation from this group
238 * @return {Object} Parameter representation
240 mw
.rcfilters
.dm
.FilterGroup
.prototype.getParamRepresentation = function () {
243 filterItems
= this.getItems();
245 if ( this.getType() === 'send_unselected_if_any' ) {
246 // First, check if any of the items are selected at all.
247 // If none is selected, we're treating it as if they are
250 // Go over the items and define the correct values
251 for ( i
= 0; i
< filterItems
.length
; i
++ ) {
252 result
[ filterItems
[ i
].getParamName() ] = this.areAnySelected() ?
253 Number( !filterItems
[ i
].isSelected() ) : 0;
256 } else if ( this.getType() === 'string_options' ) {
258 for ( i
= 0; i
< filterItems
.length
; i
++ ) {
259 if ( filterItems
[ i
].isSelected() ) {
260 values
.push( filterItems
[ i
].getParamName() );
264 result
[ this.getName() ] = ( values
.length
=== filterItems
.length
) ?
265 'all' : values
.join( this.getSeparator() );
274 * @return {string} Group type
276 mw
.rcfilters
.dm
.FilterGroup
.prototype.getType = function () {
281 * Get the prefix used for the filter names inside this group
283 * @return {string} Group prefix
285 mw
.rcfilters
.dm
.FilterGroup
.prototype.getNamePrefix = function () {
286 return this.getName() + '__';
292 * @return {string} Title
294 mw
.rcfilters
.dm
.FilterGroup
.prototype.getTitle = function () {
299 * Get group's values separator
301 * @return {string} Values separator
303 mw
.rcfilters
.dm
.FilterGroup
.prototype.getSeparator = function () {
304 return this.separator
;
308 * Check whether the group is defined as full coverage
310 * @return {boolean} Group is full coverage
312 mw
.rcfilters
.dm
.FilterGroup
.prototype.isFullCoverage = function () {
313 return this.fullCoverage
;