3e11d1eceac2e33f5028a575d2cd624737055c72
2 var ItemModel
= require( './ItemModel.js' ),
8 * @class mw.rcfilters.dm.FilterItem
9 * @extends mw.rcfilters.dm.ItemModel
12 * @param {string} param Filter param name
13 * @param {mw.rcfilters.dm.FilterGroup} groupModel Filter group model
14 * @param {Object} config Configuration object
15 * @cfg {string[]} [excludes=[]] A list of filter names this filter, if
16 * selected, makes inactive.
17 * @cfg {string[]} [subset] Defining the names of filters that are a subset of this filter
18 * @cfg {Object} [conflicts] Defines the conflicts for this filter
19 * @cfg {boolean} [visible=true] The visibility of the group
21 FilterItem
= function MwRcfiltersDmFilterItem( param
, groupModel
, config
) {
22 config
= config
|| {};
24 this.groupModel
= groupModel
;
27 FilterItem
.parent
.call( this, param
, $.extend( {
28 namePrefix
: this.groupModel
.getNamePrefix()
31 OO
.EventEmitter
.call( this );
33 // Interaction definitions
34 this.subset
= config
.subset
|| [];
35 this.conflicts
= config
.conflicts
|| {};
37 this.visible
= config
.visible
=== undefined ? true : !!config
.visible
;
40 this.included
= false;
41 this.conflicted
= false;
42 this.fullyCovered
= false;
47 OO
.inheritClass( FilterItem
, ItemModel
);
52 * Return the representation of the state of this item.
54 * @return {Object} State of the object
56 FilterItem
.prototype.getState = function () {
58 selected
: this.isSelected(),
59 included
: this.isIncluded(),
60 conflicted
: this.isConflicted(),
61 fullyCovered
: this.isFullyCovered()
66 * Get the message for the display area for the currently active conflict
69 * @return {string} Conflict result message key
71 FilterItem
.prototype.getCurrentConflictResultMessage = function () {
74 // First look in filter's own conflicts
75 details
= this.getConflictDetails( this.getOwnConflicts(), 'globalDescription' );
76 if ( !details
.message
) {
77 // Fall back onto conflicts in the group
78 details
= this.getConflictDetails( this.getGroupModel().getConflicts(), 'globalDescription' );
81 return details
.message
;
85 * Get the details of the active conflict on this filter
88 * @param {Object} conflicts Conflicts to examine
89 * @param {string} [key='contextDescription'] Message key
90 * @return {Object} Object with conflict message and conflict items
91 * @return {string} return.message Conflict message
92 * @return {string[]} return.names Conflicting item labels
94 FilterItem
.prototype.getConflictDetails = function ( conflicts
, key
) {
99 key
= key
|| 'contextDescription';
101 // eslint-disable-next-line jquery/no-each-util
102 $.each( conflicts
, function ( filterName
, conflict
) {
103 if ( !conflict
.item
.isSelected() ) {
107 if ( !conflictMessage
) {
108 conflictMessage
= conflict
[ key
];
109 group
= conflict
.group
;
112 if ( group
=== conflict
.group
) {
113 itemLabels
.push( mw
.msg( 'quotation-marks', conflict
.item
.getLabel() ) );
118 message
: conflictMessage
,
127 FilterItem
.prototype.getStateMessage = function () {
128 var messageKey
, details
, superset
,
131 if ( this.isSelected() ) {
132 if ( this.isConflicted() ) {
133 // First look in filter's own conflicts
134 details
= this.getConflictDetails( this.getOwnConflicts() );
135 if ( !details
.message
) {
136 // Fall back onto conflicts in the group
137 details
= this.getConflictDetails( this.getGroupModel().getConflicts() );
140 messageKey
= details
.message
;
141 affectingItems
= details
.names
;
142 } else if ( this.isIncluded() && !this.isHighlighted() ) {
143 // We only show the 'no effect' full-coverage message
144 // if the item is also not highlighted. See T161273
145 superset
= this.getSuperset();
146 // For this message we need to collect the affecting superset
147 affectingItems
= this.getGroupModel().findSelectedItems( this )
148 .filter( function ( item
) {
149 return superset
.indexOf( item
.getName() ) !== -1;
151 .map( function ( item
) {
152 return mw
.msg( 'quotation-marks', item
.getLabel() );
155 messageKey
= 'rcfilters-state-message-subset';
156 } else if ( this.isFullyCovered() && !this.isHighlighted() ) {
157 affectingItems
= this.getGroupModel().findSelectedItems( this )
158 .map( function ( item
) {
159 return mw
.msg( 'quotation-marks', item
.getLabel() );
162 messageKey
= 'rcfilters-state-message-fullcoverage';
170 mw
.language
.listToText( affectingItems
),
171 affectingItems
.length
175 // Display description
176 return this.getDescription();
180 * Get the model of the group this filter belongs to
182 * @return {mw.rcfilters.dm.FilterGroup} Filter group model
184 FilterItem
.prototype.getGroupModel = function () {
185 return this.groupModel
;
189 * Get the group name this filter belongs to
191 * @return {string} Filter group name
193 FilterItem
.prototype.getGroupName = function () {
194 return this.groupModel
.getName();
199 * This is a list of filter names that are defined to be included
200 * when this filter is selected.
202 * @return {string[]} Filter subset
204 FilterItem
.prototype.getSubset = function () {
209 * Get filter superset
210 * This is a generated list of filters that define this filter
211 * to be included when either of them is selected.
213 * @return {string[]} Filter superset
215 FilterItem
.prototype.getSuperset = function () {
216 return this.superset
;
220 * Check whether the filter is currently in a conflict state
222 * @return {boolean} Filter is in conflict state
224 FilterItem
.prototype.isConflicted = function () {
225 return this.conflicted
;
229 * Check whether the filter is currently in an already included subset
231 * @return {boolean} Filter is in an already-included subset
233 FilterItem
.prototype.isIncluded = function () {
234 return this.included
;
238 * Check whether the filter is currently fully covered
240 * @return {boolean} Filter is in fully-covered state
242 FilterItem
.prototype.isFullyCovered = function () {
243 return this.fullyCovered
;
247 * Get all conflicts associated with this filter or its group
249 * Conflict object is set up by filter name keys and conflict
250 * definition. For example:
254 * filter: filterName,
260 * filter: filterName2,
267 * @return {Object} Filter conflicts
269 FilterItem
.prototype.getConflicts = function () {
270 return $.extend( {}, this.conflicts
, this.getGroupModel().getConflicts() );
274 * Get the conflicts associated with this filter
276 * @return {Object} Filter conflicts
278 FilterItem
.prototype.getOwnConflicts = function () {
279 return this.conflicts
;
283 * Set conflicts for this filter. See #getConflicts for the expected
284 * structure of the definition.
286 * @param {Object} conflicts Conflicts for this filter
288 FilterItem
.prototype.setConflicts = function ( conflicts
) {
289 this.conflicts
= conflicts
|| {};
293 * Set filter superset
295 * @param {string[]} superset Filter superset
297 FilterItem
.prototype.setSuperset = function ( superset
) {
298 this.superset
= superset
|| [];
304 * @param {string[]} subset Filter subset
306 FilterItem
.prototype.setSubset = function ( subset
) {
307 this.subset
= subset
|| [];
311 * Check whether a filter exists in the subset list for this filter
313 * @param {string} filterName Filter name
314 * @return {boolean} Filter name is in the subset list
316 FilterItem
.prototype.existsInSubset = function ( filterName
) {
317 return this.subset
.indexOf( filterName
) > -1;
321 * Check whether this item has a potential conflict with the given item
323 * This checks whether the given item is in the list of conflicts of
324 * the current item, but makes no judgment about whether the conflict
325 * is currently at play (either one of the items may not be selected)
327 * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
328 * @return {boolean} This item has a conflict with the given item
330 FilterItem
.prototype.existsInConflicts = function ( filterItem
) {
331 return Object
.prototype.hasOwnProperty
.call( this.getConflicts(), filterItem
.getName() );
335 * Set the state of this filter as being conflicted
336 * (This means any filters in its conflicts are selected)
338 * @param {boolean} [conflicted] Filter is in conflict state
341 FilterItem
.prototype.toggleConflicted = function ( conflicted
) {
342 conflicted
= conflicted
=== undefined ? !this.conflicted
: conflicted
;
344 if ( this.conflicted
!== conflicted
) {
345 this.conflicted
= conflicted
;
346 this.emit( 'update' );
351 * Set the state of this filter as being already included
352 * (This means any filters in its superset are selected)
354 * @param {boolean} [included] Filter is included as part of a subset
357 FilterItem
.prototype.toggleIncluded = function ( included
) {
358 included
= included
=== undefined ? !this.included
: included
;
360 if ( this.included
!== included
) {
361 this.included
= included
;
362 this.emit( 'update' );
367 * Toggle the fully covered state of the item
369 * @param {boolean} [isFullyCovered] Filter is fully covered
372 FilterItem
.prototype.toggleFullyCovered = function ( isFullyCovered
) {
373 isFullyCovered
= isFullyCovered
=== undefined ? !this.fullycovered
: isFullyCovered
;
375 if ( this.fullyCovered
!== isFullyCovered
) {
376 this.fullyCovered
= isFullyCovered
;
377 this.emit( 'update' );
382 * Toggle the visibility of this item
384 * @param {boolean} [isVisible] Item is visible
386 FilterItem
.prototype.toggleVisible = function ( isVisible
) {
387 isVisible
= isVisible
=== undefined ? !this.visible
: !!isVisible
;
389 if ( this.visible
!== isVisible
) {
390 this.visible
= isVisible
;
391 this.emit( 'update' );
396 * Check whether the item is visible
398 * @return {boolean} Item is visible
400 FilterItem
.prototype.isVisible = function () {
404 module
.exports
= FilterItem
;