Replace deprecated Context::getStats() with MWServices::getStatsdDataFactory()
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / dm / mw.rcfilters.dm.FilterGroup.js
1 ( function ( mw ) {
2 /**
3 * View model for a filter group
4 *
5 * @mixins OO.EventEmitter
6 * @mixins OO.EmitterList
7 *
8 * @constructor
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 */
18 mw.rcfilters.dm.FilterGroup = function MwRcfiltersDmFilterGroup( name, config ) {
19 config = config || {};
20
21 // Mixin constructor
22 OO.EventEmitter.call( this );
23 OO.EmitterList.call( this );
24
25 this.name = name;
26 this.type = config.type || 'send_unselected_if_any';
27 this.title = config.title;
28 this.separator = config.separator || '|';
29
30 this.active = !!config.active;
31 this.fullCoverage = !!config.fullCoverage;
32
33 this.conflicts = config.conflicts || {};
34
35 this.aggregate( { update: 'filterItemUpdate' } );
36 this.connect( this, { filterItemUpdate: 'onFilterItemUpdate' } );
37 };
38
39 /* Initialization */
40 OO.initClass( mw.rcfilters.dm.FilterGroup );
41 OO.mixinClass( mw.rcfilters.dm.FilterGroup, OO.EventEmitter );
42 OO.mixinClass( mw.rcfilters.dm.FilterGroup, OO.EmitterList );
43
44 /* Events */
45
46 /**
47 * @event update
48 *
49 * Group state has been updated
50 */
51
52 /* Methods */
53
54 /**
55 * Respond to filterItem update event
56 *
57 * @fires update
58 */
59 mw.rcfilters.dm.FilterGroup.prototype.onFilterItemUpdate = function () {
60 // Update state
61 var active = this.areAnySelected();
62
63 if ( this.active !== active ) {
64 this.active = active;
65 this.emit( 'update' );
66 }
67 };
68
69 /**
70 * Get group active state
71 *
72 * @return {boolean} Active state
73 */
74 mw.rcfilters.dm.FilterGroup.prototype.isActive = function () {
75 return this.active;
76 };
77
78 /**
79 * Get group name
80 *
81 * @return {string} Group name
82 */
83 mw.rcfilters.dm.FilterGroup.prototype.getName = function () {
84 return this.name;
85 };
86
87 /**
88 * Get the conflicts associated with the entire group.
89 * Conflict object is set up by filter name keys and conflict
90 * definition. For example:
91 * [
92 * {
93 * filterName: {
94 * filter: filterName,
95 * group: group1
96 * }
97 * },
98 * {
99 * filterName2: {
100 * filter: filterName2,
101 * group: group2
102 * }
103 * }
104 * ]
105 * @return {Object} Conflict definition
106 */
107 mw.rcfilters.dm.FilterGroup.prototype.getConflicts = function () {
108 return this.conflicts;
109 };
110
111 /**
112 * Set conflicts for this group. See #getConflicts for the expected
113 * structure of the definition.
114 *
115 * @param {Object} conflicts Conflicts for this group
116 */
117 mw.rcfilters.dm.FilterGroup.prototype.setConflicts = function ( conflicts ) {
118 this.conflicts = conflicts;
119 };
120
121 /**
122 * Check whether this item has a potential conflict with the given item
123 *
124 * This checks whether the given item is in the list of conflicts of
125 * the current item, but makes no judgment about whether the conflict
126 * is currently at play (either one of the items may not be selected)
127 *
128 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
129 * @return {boolean} This item has a conflict with the given item
130 */
131 mw.rcfilters.dm.FilterGroup.prototype.existsInConflicts = function ( filterItem ) {
132 return Object.prototype.hasOwnProperty.call( this.getConflicts(), filterItem.getName() );
133 };
134
135 /**
136 * Check whether there are any items selected
137 *
138 * @return {boolean} Any items in the group are selected
139 */
140 mw.rcfilters.dm.FilterGroup.prototype.areAnySelected = function () {
141 return this.getItems().some( function ( filterItem ) {
142 return filterItem.isSelected();
143 } );
144 };
145
146 /**
147 * Check whether all items selected
148 *
149 * @return {boolean} All items are selected
150 */
151 mw.rcfilters.dm.FilterGroup.prototype.areAllSelected = function () {
152 return this.getItems().every( function ( filterItem ) {
153 return filterItem.isSelected();
154 } );
155 };
156
157 /**
158 * Get all selected items in this group
159 *
160 * @param {mw.rcfilters.dm.FilterItem} [excludeItem] Item to exclude from the list
161 * @return {mw.rcfilters.dm.FilterItem[]} Selected items
162 */
163 mw.rcfilters.dm.FilterGroup.prototype.getSelectedItems = function ( excludeItem ) {
164 var excludeName = ( excludeItem && excludeItem.getName() ) || '';
165
166 return this.getItems().filter( function ( item ) {
167 return item.getName() !== excludeName && item.isSelected();
168 } );
169 };
170
171 /**
172 * Check whether all selected items are in conflict with the given item
173 *
174 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
175 * @return {boolean} All selected items are in conflict with this item
176 */
177 mw.rcfilters.dm.FilterGroup.prototype.areAllSelectedInConflictWith = function ( filterItem ) {
178 var selectedItems = this.getSelectedItems( filterItem );
179
180 return selectedItems.length > 0 &&
181 (
182 // The group as a whole is in conflict with this item
183 this.existsInConflicts( filterItem ) ||
184 // All selected items are in conflict individually
185 selectedItems.every( function ( selectedFilter ) {
186 return selectedFilter.existsInConflicts( filterItem );
187 } )
188 );
189 };
190
191 /**
192 * Check whether any of the selected items are in conflict with the given item
193 *
194 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
195 * @return {boolean} Any of the selected items are in conflict with this item
196 */
197 mw.rcfilters.dm.FilterGroup.prototype.areAnySelectedInConflictWith = function ( filterItem ) {
198 var selectedItems = this.getSelectedItems( filterItem );
199
200 return selectedItems.length > 0 && (
201 // The group as a whole is in conflict with this item
202 this.existsInConflicts( filterItem ) ||
203 // Any selected items are in conflict individually
204 selectedItems.some( function ( selectedFilter ) {
205 return selectedFilter.existsInConflicts( filterItem );
206 } )
207 );
208 };
209
210 /**
211 * Get the parameter representation from this group
212 *
213 * @return {Object} Parameter representation
214 */
215 mw.rcfilters.dm.FilterGroup.prototype.getParamRepresentation = function () {
216 var i, values,
217 result = {},
218 filterItems = this.getItems();
219
220 if ( this.getType() === 'send_unselected_if_any' ) {
221 // First, check if any of the items are selected at all.
222 // If none is selected, we're treating it as if they are
223 // all false
224
225 // Go over the items and define the correct values
226 for ( i = 0; i < filterItems.length; i++ ) {
227 result[ filterItems[ i ].getParamName() ] = this.areAnySelected() ?
228 Number( !filterItems[ i ].isSelected() ) : 0;
229 }
230
231 } else if ( this.getType() === 'string_options' ) {
232 values = [];
233 for ( i = 0; i < filterItems.length; i++ ) {
234 if ( filterItems[ i ].isSelected() ) {
235 values.push( filterItems[ i ].getParamName() );
236 }
237 }
238
239 result[ this.getName() ] = ( values.length === filterItems.length ) ?
240 'all' : values.join( this.getSeparator() );
241 }
242
243 return result;
244 };
245
246 /**
247 * Get group type
248 *
249 * @return {string} Group type
250 */
251 mw.rcfilters.dm.FilterGroup.prototype.getType = function () {
252 return this.type;
253 };
254
255 /**
256 * Get the prefix used for the filter names inside this group
257 *
258 * @return {string} Group prefix
259 */
260 mw.rcfilters.dm.FilterGroup.prototype.getNamePrefix = function () {
261 return this.getName() + '__';
262 };
263
264 /**
265 * Get group's title
266 *
267 * @return {string} Title
268 */
269 mw.rcfilters.dm.FilterGroup.prototype.getTitle = function () {
270 return this.title;
271 };
272
273 /**
274 * Get group's values separator
275 *
276 * @return {string} Values separator
277 */
278 mw.rcfilters.dm.FilterGroup.prototype.getSeparator = function () {
279 return this.separator;
280 };
281
282 /**
283 * Check whether the group is defined as full coverage
284 *
285 * @return {boolean} Group is full coverage
286 */
287 mw.rcfilters.dm.FilterGroup.prototype.isFullCoverage = function () {
288 return this.fullCoverage;
289 };
290 }( mediaWiki ) );