diff options
Diffstat (limited to 'www/wiki/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js')
-rw-r--r-- | www/wiki/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/www/wiki/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js b/www/wiki/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js new file mode 100644 index 00000000..d7f7b021 --- /dev/null +++ b/www/wiki/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js @@ -0,0 +1,398 @@ +( function ( mw ) { + /** + * Filter item model + * + * @extends mw.rcfilters.dm.ItemModel + * + * @constructor + * @param {string} param Filter param name + * @param {mw.rcfilters.dm.FilterGroup} groupModel Filter group model + * @param {Object} config Configuration object + * @cfg {string[]} [excludes=[]] A list of filter names this filter, if + * selected, makes inactive. + * @cfg {string[]} [subset] Defining the names of filters that are a subset of this filter + * @cfg {Object} [conflicts] Defines the conflicts for this filter + * @cfg {boolean} [visible=true] The visibility of the group + */ + mw.rcfilters.dm.FilterItem = function MwRcfiltersDmFilterItem( param, groupModel, config ) { + config = config || {}; + + this.groupModel = groupModel; + + // Parent + mw.rcfilters.dm.FilterItem.parent.call( this, param, $.extend( { + namePrefix: this.groupModel.getNamePrefix() + }, config ) ); + // Mixin constructor + OO.EventEmitter.call( this ); + + // Interaction definitions + this.subset = config.subset || []; + this.conflicts = config.conflicts || {}; + this.superset = []; + this.visible = config.visible === undefined ? true : !!config.visible; + + // Interaction states + this.included = false; + this.conflicted = false; + this.fullyCovered = false; + }; + + /* Initialization */ + + OO.inheritClass( mw.rcfilters.dm.FilterItem, mw.rcfilters.dm.ItemModel ); + + /* Methods */ + + /** + * Return the representation of the state of this item. + * + * @return {Object} State of the object + */ + mw.rcfilters.dm.FilterItem.prototype.getState = function () { + return { + selected: this.isSelected(), + included: this.isIncluded(), + conflicted: this.isConflicted(), + fullyCovered: this.isFullyCovered() + }; + }; + + /** + * Get the message for the display area for the currently active conflict + * + * @private + * @return {string} Conflict result message key + */ + mw.rcfilters.dm.FilterItem.prototype.getCurrentConflictResultMessage = function () { + var details = {}; + + // First look in filter's own conflicts + details = this.getConflictDetails( this.getOwnConflicts(), 'globalDescription' ); + if ( !details.message ) { + // Fall back onto conflicts in the group + details = this.getConflictDetails( this.getGroupModel().getConflicts(), 'globalDescription' ); + } + + return details.message; + }; + + /** + * Get the details of the active conflict on this filter + * + * @private + * @param {Object} conflicts Conflicts to examine + * @param {string} [key='contextDescription'] Message key + * @return {Object} Object with conflict message and conflict items + * @return {string} return.message Conflict message + * @return {string[]} return.names Conflicting item labels + */ + mw.rcfilters.dm.FilterItem.prototype.getConflictDetails = function ( conflicts, key ) { + var group, + conflictMessage = '', + itemLabels = []; + + key = key || 'contextDescription'; + + $.each( conflicts, function ( filterName, conflict ) { + if ( !conflict.item.isSelected() ) { + return; + } + + if ( !conflictMessage ) { + conflictMessage = conflict[ key ]; + group = conflict.group; + } + + if ( group === conflict.group ) { + itemLabels.push( mw.msg( 'quotation-marks', conflict.item.getLabel() ) ); + } + } ); + + return { + message: conflictMessage, + names: itemLabels + }; + + }; + + /** + * @inheritdoc + */ + mw.rcfilters.dm.FilterItem.prototype.getStateMessage = function () { + var messageKey, details, superset, + affectingItems = []; + + if ( this.isSelected() ) { + if ( this.isConflicted() ) { + // First look in filter's own conflicts + details = this.getConflictDetails( this.getOwnConflicts() ); + if ( !details.message ) { + // Fall back onto conflicts in the group + details = this.getConflictDetails( this.getGroupModel().getConflicts() ); + } + + messageKey = details.message; + affectingItems = details.names; + } else if ( this.isIncluded() && !this.isHighlighted() ) { + // We only show the 'no effect' full-coverage message + // if the item is also not highlighted. See T161273 + superset = this.getSuperset(); + // For this message we need to collect the affecting superset + affectingItems = this.getGroupModel().findSelectedItems( this ) + .filter( function ( item ) { + return superset.indexOf( item.getName() ) !== -1; + } ) + .map( function ( item ) { + return mw.msg( 'quotation-marks', item.getLabel() ); + } ); + + messageKey = 'rcfilters-state-message-subset'; + } else if ( this.isFullyCovered() && !this.isHighlighted() ) { + affectingItems = this.getGroupModel().findSelectedItems( this ) + .map( function ( item ) { + return mw.msg( 'quotation-marks', item.getLabel() ); + } ); + + messageKey = 'rcfilters-state-message-fullcoverage'; + } + } + + if ( messageKey ) { + // Build message + return mw.msg( + messageKey, + mw.language.listToText( affectingItems ), + affectingItems.length + ); + } + + // Display description + return this.getDescription(); + }; + + /** + * Get the model of the group this filter belongs to + * + * @return {mw.rcfilters.dm.FilterGroup} Filter group model + */ + mw.rcfilters.dm.FilterItem.prototype.getGroupModel = function () { + return this.groupModel; + }; + + /** + * Get the group name this filter belongs to + * + * @return {string} Filter group name + */ + mw.rcfilters.dm.FilterItem.prototype.getGroupName = function () { + return this.groupModel.getName(); + }; + + /** + * Get filter subset + * This is a list of filter names that are defined to be included + * when this filter is selected. + * + * @return {string[]} Filter subset + */ + mw.rcfilters.dm.FilterItem.prototype.getSubset = function () { + return this.subset; + }; + + /** + * Get filter superset + * This is a generated list of filters that define this filter + * to be included when either of them is selected. + * + * @return {string[]} Filter superset + */ + mw.rcfilters.dm.FilterItem.prototype.getSuperset = function () { + return this.superset; + }; + + /** + * Check whether the filter is currently in a conflict state + * + * @return {boolean} Filter is in conflict state + */ + mw.rcfilters.dm.FilterItem.prototype.isConflicted = function () { + return this.conflicted; + }; + + /** + * Check whether the filter is currently in an already included subset + * + * @return {boolean} Filter is in an already-included subset + */ + mw.rcfilters.dm.FilterItem.prototype.isIncluded = function () { + return this.included; + }; + + /** + * Check whether the filter is currently fully covered + * + * @return {boolean} Filter is in fully-covered state + */ + mw.rcfilters.dm.FilterItem.prototype.isFullyCovered = function () { + return this.fullyCovered; + }; + + /** + * Get all conflicts associated with this filter or its group + * + * Conflict object is set up by filter name keys and conflict + * definition. For example: + * { + * filterName: { + * filter: filterName, + * group: group1, + * label: itemLabel, + * item: itemModel + * } + * filterName2: { + * filter: filterName2, + * group: group2 + * label: itemLabel2, + * item: itemModel2 + * } + * } + * + * @return {Object} Filter conflicts + */ + mw.rcfilters.dm.FilterItem.prototype.getConflicts = function () { + return $.extend( {}, this.conflicts, this.getGroupModel().getConflicts() ); + }; + + /** + * Get the conflicts associated with this filter + * + * @return {Object} Filter conflicts + */ + mw.rcfilters.dm.FilterItem.prototype.getOwnConflicts = function () { + return this.conflicts; + }; + + /** + * Set conflicts for this filter. See #getConflicts for the expected + * structure of the definition. + * + * @param {Object} conflicts Conflicts for this filter + */ + mw.rcfilters.dm.FilterItem.prototype.setConflicts = function ( conflicts ) { + this.conflicts = conflicts || {}; + }; + + /** + * Set filter superset + * + * @param {string[]} superset Filter superset + */ + mw.rcfilters.dm.FilterItem.prototype.setSuperset = function ( superset ) { + this.superset = superset || []; + }; + + /** + * Set filter subset + * + * @param {string[]} subset Filter subset + */ + mw.rcfilters.dm.FilterItem.prototype.setSubset = function ( subset ) { + this.subset = subset || []; + }; + + /** + * Check whether a filter exists in the subset list for this filter + * + * @param {string} filterName Filter name + * @return {boolean} Filter name is in the subset list + */ + mw.rcfilters.dm.FilterItem.prototype.existsInSubset = function ( filterName ) { + return this.subset.indexOf( filterName ) > -1; + }; + + /** + * Check whether this item has a potential conflict with the given item + * + * This checks whether the given item is in the list of conflicts of + * the current item, but makes no judgment about whether the conflict + * is currently at play (either one of the items may not be selected) + * + * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item + * @return {boolean} This item has a conflict with the given item + */ + mw.rcfilters.dm.FilterItem.prototype.existsInConflicts = function ( filterItem ) { + return Object.prototype.hasOwnProperty.call( this.getConflicts(), filterItem.getName() ); + }; + + /** + * Set the state of this filter as being conflicted + * (This means any filters in its conflicts are selected) + * + * @param {boolean} [conflicted] Filter is in conflict state + * @fires update + */ + mw.rcfilters.dm.FilterItem.prototype.toggleConflicted = function ( conflicted ) { + conflicted = conflicted === undefined ? !this.conflicted : conflicted; + + if ( this.conflicted !== conflicted ) { + this.conflicted = conflicted; + this.emit( 'update' ); + } + }; + + /** + * Set the state of this filter as being already included + * (This means any filters in its superset are selected) + * + * @param {boolean} [included] Filter is included as part of a subset + * @fires update + */ + mw.rcfilters.dm.FilterItem.prototype.toggleIncluded = function ( included ) { + included = included === undefined ? !this.included : included; + + if ( this.included !== included ) { + this.included = included; + this.emit( 'update' ); + } + }; + + /** + * Toggle the fully covered state of the item + * + * @param {boolean} [isFullyCovered] Filter is fully covered + * @fires update + */ + mw.rcfilters.dm.FilterItem.prototype.toggleFullyCovered = function ( isFullyCovered ) { + isFullyCovered = isFullyCovered === undefined ? !this.fullycovered : isFullyCovered; + + if ( this.fullyCovered !== isFullyCovered ) { + this.fullyCovered = isFullyCovered; + this.emit( 'update' ); + } + }; + + /** + * Toggle the visibility of this item + * + * @param {boolean} [isVisible] Item is visible + */ + mw.rcfilters.dm.FilterItem.prototype.toggleVisible = function ( isVisible ) { + isVisible = isVisible === undefined ? !this.visible : !!isVisible; + + if ( this.visible !== isVisible ) { + this.visible = isVisible; + this.emit( 'update' ); + } + }; + + /** + * Check whether the item is visible + * + * @return {boolean} Item is visible + */ + mw.rcfilters.dm.FilterItem.prototype.isVisible = function () { + return this.visible; + }; + +}( mediaWiki ) ); |