/**
* The FlaggedElement class is an attribute mixin, meaning that it is used to add
* additional functionality to an element created by another class. The class provides
* a ‘flags’ property assigned the name (or an array of names) of styling flags,
* which are used to customize the look and feel of a widget to better describe its
* importance and functionality.
*
* The library currently contains the following styling flags for general use:
*
* - **progressive**: Progressive styling is applied to convey that the widget will move the user forward in a process.
* - **destructive**: Destructive styling is applied to convey that the widget will remove something.
*
* The flags affect the appearance of the buttons:
*
* @example
* // FlaggedElement is mixed into ButtonWidget to provide styling flags
* var button1 = new OO.ui.ButtonWidget( {
* label: 'Progressive',
* flags: 'progressive'
* } );
* var button2 = new OO.ui.ButtonWidget( {
* label: 'Destructive',
* flags: 'destructive'
* } );
* $( 'body' ).append( button1.$element, button2.$element );
*
* {@link OO.ui.ActionWidget ActionWidgets}, which are a special kind of button that execute an action, use these flags: **primary** and **safe**.
* Please see the [OOjs UI documentation on MediaWiki] [1] for more information.
*
* [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
*
* @mixin
*
* @param {Object} [config] Configuration options
* @param {string|string[]} [config.flags] The name or names of the flags (e.g., 'progressive' or 'primary') to apply.
* Please see the [OOjs UI documentation on MediaWiki] [2] for more information about available flags.
* [2]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
* @param {jQuery} [config.$flagged] The flagged element. By default,
* the flagged functionality is applied to the element created by the class ($element).
* If a different element is specified, the flagged functionality will be applied to it instead.
*/
OO.ui.mixin.FlaggedElement = function OoUiMixinFlaggedElement( config ) {
// Configuration initialization
config = config || {};
// Properties
this.flags = {};
this.$flagged = null;
// Initialization
this.setFlags( config.flags );
this.setFlaggedElement( config.$flagged || this.$element );
};
/* Events */
/**
* @event flag
* A flag event is emitted when the #clearFlags or #setFlags methods are used. The `changes`
* parameter contains the name of each modified flag and indicates whether it was
* added or removed.
*
* @param {Object.<string,boolean>} changes Object keyed by flag name. A Boolean `true` indicates
* that the flag was added, `false` that the flag was removed.
*/
/* Methods */
/**
* Set the flagged element.
*
* This method is used to retarget a flagged mixin so that its functionality applies to the specified element.
* If an element is already set, the method will remove the mixin’s effect on that element.
*
* @param {jQuery} $flagged Element that should be flagged
*/
OO.ui.mixin.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {
var classNames = Object.keys( this.flags ).map( function ( flag ) {
return 'oo-ui-flaggedElement-' + flag;
} ).join( ' ' );
if ( this.$flagged ) {
this.$flagged.removeClass( classNames );
}
this.$flagged = $flagged.addClass( classNames );
};
/**
* Check if the specified flag is set.
*
* @param {string} flag Name of flag
* @return {boolean} The flag is set
*/
OO.ui.mixin.FlaggedElement.prototype.hasFlag = function ( flag ) {
// This may be called before the constructor, thus before this.flags is set
return this.flags && ( flag in this.flags );
};
/**
* Get the names of all flags set.
*
* @return {string[]} Flag names
*/
OO.ui.mixin.FlaggedElement.prototype.getFlags = function () {
// This may be called before the constructor, thus before this.flags is set
return Object.keys( this.flags || {} );
};
/**
* Clear all flags.
*
* @chainable
* @fires flag
*/
OO.ui.mixin.FlaggedElement.prototype.clearFlags = function () {
var flag, className,
changes = {},
remove = [],
classPrefix = 'oo-ui-flaggedElement-';
for ( flag in this.flags ) {
className = classPrefix + flag;
changes[ flag ] = false;
delete this.flags[ flag ];
remove.push( className );
}
if ( this.$flagged ) {
this.$flagged.removeClass( remove.join( ' ' ) );
}
this.updateThemeClasses();
this.emit( 'flag', changes );
return this;
};
/**
* Add one or more flags.
*
* @param {string|string[]|Object.<string, boolean>} flags A flag name, an array of flag names,
* or an object keyed by flag name with a boolean value that indicates whether the flag should
* be added (`true`) or removed (`false`).
* @chainable
* @fires flag
*/
OO.ui.mixin.FlaggedElement.prototype.setFlags = function ( flags ) {
var i, len, flag, className,
changes = {},
add = [],
remove = [],
classPrefix = 'oo-ui-flaggedElement-';
if ( typeof flags === 'string' ) {
className = classPrefix + flags;
// Set
if ( !this.flags[ flags ] ) {
this.flags[ flags ] = true;
add.push( className );
}
} else if ( Array.isArray( flags ) ) {
for ( i = 0, len = flags.length; i < len; i++ ) {
flag = flags[ i ];
className = classPrefix + flag;
// Set
if ( !this.flags[ flag ] ) {
changes[ flag ] = true;
this.flags[ flag ] = true;
add.push( className );
}
}
} else if ( OO.isPlainObject( flags ) ) {
for ( flag in flags ) {
className = classPrefix + flag;
if ( flags[ flag ] ) {
// Set
if ( !this.flags[ flag ] ) {
changes[ flag ] = true;
this.flags[ flag ] = true;
add.push( className );
}
} else {
// Remove
if ( this.flags[ flag ] ) {
changes[ flag ] = false;
delete this.flags[ flag ];
remove.push( className );
}
}
}
}
if ( this.$flagged ) {
this.$flagged
.addClass( add.join( ' ' ) )
.removeClass( remove.join( ' ' ) );
}
this.updateThemeClasses();
this.emit( 'flag', changes );
return this;
};