/** * 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. * - **constructive**: Constructive styling is applied to convey that the widget will create 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: 'Constructive', * flags: 'constructive' * } ); * var button2 = new OO.ui.ButtonWidget( { * label: 'Destructive', * flags: 'destructive' * } ); * var button3 = new OO.ui.ButtonWidget( { * label: 'Progressive', * flags: 'progressive' * } ); * $( 'body' ).append( button1.$element, button2.$element, button3.$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 * * @abstract * @class * * @constructor * @param {Object} [config] Configuration options * @cfg {string|string[]} [flags] The name or names of the flags (e.g., 'constructive' 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 * @cfg {jQuery} [$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.FlaggedElement = function OoUiFlaggedElement( 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.} 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.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.FlaggedElement.prototype.hasFlag = function ( flag ) { return flag in this.flags; }; /** * Get the names of all flags set. * * @return {string[]} Flag names */ OO.ui.FlaggedElement.prototype.getFlags = function () { return Object.keys( this.flags ); }; /** * Clear all flags. * * @chainable * @fires flag */ OO.ui.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.} 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.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; };