Add 3D filetype for STL files
[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 * @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
22 */
23 mw.rcfilters.dm.FilterGroup = function MwRcfiltersDmFilterGroup( name, config ) {
24 config = config || {};
25
26 // Mixin constructor
27 OO.EventEmitter.call( this );
28 OO.EmitterList.call( this );
29
30 this.name = name;
31 this.type = config.type || 'send_unselected_if_any';
32 this.title = config.title;
33 this.separator = config.separator || '|';
34
35 this.active = !!config.active;
36 this.fullCoverage = !!config.fullCoverage;
37
38 this.whatsThis = config.whatsThis || {};
39
40 this.conflicts = config.conflicts || {};
41
42 this.aggregate( { update: 'filterItemUpdate' } );
43 this.connect( this, { filterItemUpdate: 'onFilterItemUpdate' } );
44 };
45
46 /* Initialization */
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 );
50
51 /* Events */
52
53 /**
54 * @event update
55 *
56 * Group state has been updated
57 */
58
59 /* Methods */
60
61 /**
62 * Respond to filterItem update event
63 *
64 * @fires update
65 */
66 mw.rcfilters.dm.FilterGroup.prototype.onFilterItemUpdate = function () {
67 // Update state
68 var active = this.areAnySelected();
69
70 if ( this.active !== active ) {
71 this.active = active;
72 this.emit( 'update' );
73 }
74 };
75
76 /**
77 * Get group active state
78 *
79 * @return {boolean} Active state
80 */
81 mw.rcfilters.dm.FilterGroup.prototype.isActive = function () {
82 return this.active;
83 };
84
85 /**
86 * Get group name
87 *
88 * @return {string} Group name
89 */
90 mw.rcfilters.dm.FilterGroup.prototype.getName = function () {
91 return this.name;
92 };
93
94 /**
95 * Get the messags defining the 'whats this' popup for this group
96 *
97 * @return {Object} What's this messages
98 */
99 mw.rcfilters.dm.FilterGroup.prototype.getWhatsThis = function () {
100 return this.whatsThis;
101 };
102
103 /**
104 * Check whether this group has a 'what's this' message
105 *
106 * @return {boolean} This group has a what's this message
107 */
108 mw.rcfilters.dm.FilterGroup.prototype.hasWhatsThis = function () {
109 return !!this.whatsThis.body;
110 };
111
112 /**
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:
116 * [
117 * {
118 * filterName: {
119 * filter: filterName,
120 * group: group1
121 * }
122 * },
123 * {
124 * filterName2: {
125 * filter: filterName2,
126 * group: group2
127 * }
128 * }
129 * ]
130 * @return {Object} Conflict definition
131 */
132 mw.rcfilters.dm.FilterGroup.prototype.getConflicts = function () {
133 return this.conflicts;
134 };
135
136 /**
137 * Set conflicts for this group. See #getConflicts for the expected
138 * structure of the definition.
139 *
140 * @param {Object} conflicts Conflicts for this group
141 */
142 mw.rcfilters.dm.FilterGroup.prototype.setConflicts = function ( conflicts ) {
143 this.conflicts = conflicts;
144 };
145
146 /**
147 * Check whether this item has a potential conflict with the given item
148 *
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)
152 *
153 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
154 * @return {boolean} This item has a conflict with the given item
155 */
156 mw.rcfilters.dm.FilterGroup.prototype.existsInConflicts = function ( filterItem ) {
157 return Object.prototype.hasOwnProperty.call( this.getConflicts(), filterItem.getName() );
158 };
159
160 /**
161 * Check whether there are any items selected
162 *
163 * @return {boolean} Any items in the group are selected
164 */
165 mw.rcfilters.dm.FilterGroup.prototype.areAnySelected = function () {
166 return this.getItems().some( function ( filterItem ) {
167 return filterItem.isSelected();
168 } );
169 };
170
171 /**
172 * Check whether all items selected
173 *
174 * @return {boolean} All items are selected
175 */
176 mw.rcfilters.dm.FilterGroup.prototype.areAllSelected = function () {
177 return this.getItems().every( function ( filterItem ) {
178 return filterItem.isSelected();
179 } );
180 };
181
182 /**
183 * Get all selected items in this group
184 *
185 * @param {mw.rcfilters.dm.FilterItem} [excludeItem] Item to exclude from the list
186 * @return {mw.rcfilters.dm.FilterItem[]} Selected items
187 */
188 mw.rcfilters.dm.FilterGroup.prototype.getSelectedItems = function ( excludeItem ) {
189 var excludeName = ( excludeItem && excludeItem.getName() ) || '';
190
191 return this.getItems().filter( function ( item ) {
192 return item.getName() !== excludeName && item.isSelected();
193 } );
194 };
195
196 /**
197 * Check whether all selected items are in conflict with the given item
198 *
199 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
200 * @return {boolean} All selected items are in conflict with this item
201 */
202 mw.rcfilters.dm.FilterGroup.prototype.areAllSelectedInConflictWith = function ( filterItem ) {
203 var selectedItems = this.getSelectedItems( filterItem );
204
205 return selectedItems.length > 0 &&
206 (
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 );
212 } )
213 );
214 };
215
216 /**
217 * Check whether any of the selected items are in conflict with the given item
218 *
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
221 */
222 mw.rcfilters.dm.FilterGroup.prototype.areAnySelectedInConflictWith = function ( filterItem ) {
223 var selectedItems = this.getSelectedItems( filterItem );
224
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 );
231 } )
232 );
233 };
234
235 /**
236 * Get the parameter representation from this group
237 *
238 * @return {Object} Parameter representation
239 */
240 mw.rcfilters.dm.FilterGroup.prototype.getParamRepresentation = function () {
241 var i, values,
242 result = {},
243 filterItems = this.getItems();
244
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
248 // all false
249
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;
254 }
255
256 } else if ( this.getType() === 'string_options' ) {
257 values = [];
258 for ( i = 0; i < filterItems.length; i++ ) {
259 if ( filterItems[ i ].isSelected() ) {
260 values.push( filterItems[ i ].getParamName() );
261 }
262 }
263
264 result[ this.getName() ] = ( values.length === filterItems.length ) ?
265 'all' : values.join( this.getSeparator() );
266 }
267
268 return result;
269 };
270
271 /**
272 * Get group type
273 *
274 * @return {string} Group type
275 */
276 mw.rcfilters.dm.FilterGroup.prototype.getType = function () {
277 return this.type;
278 };
279
280 /**
281 * Get the prefix used for the filter names inside this group
282 *
283 * @return {string} Group prefix
284 */
285 mw.rcfilters.dm.FilterGroup.prototype.getNamePrefix = function () {
286 return this.getName() + '__';
287 };
288
289 /**
290 * Get group's title
291 *
292 * @return {string} Title
293 */
294 mw.rcfilters.dm.FilterGroup.prototype.getTitle = function () {
295 return this.title;
296 };
297
298 /**
299 * Get group's values separator
300 *
301 * @return {string} Values separator
302 */
303 mw.rcfilters.dm.FilterGroup.prototype.getSeparator = function () {
304 return this.separator;
305 };
306
307 /**
308 * Check whether the group is defined as full coverage
309 *
310 * @return {boolean} Group is full coverage
311 */
312 mw.rcfilters.dm.FilterGroup.prototype.isFullCoverage = function () {
313 return this.fullCoverage;
314 };
315 }( mediaWiki ) );