/** * Generic toolbar tool. * * @abstract * @class * @extends OO.ui.Widget * @mixins OO.ui.IconElement * @mixins OO.ui.FlaggedElement * @mixins OO.ui.TabIndexedElement * * @constructor * @param {OO.ui.ToolGroup} toolGroup * @param {Object} [config] Configuration options * @cfg {string|Function} [title] Title text or a function that returns text */ OO.ui.Tool = function OoUiTool( toolGroup, config ) { // Allow passing positional parameters inside the config object if ( OO.isPlainObject( toolGroup ) && config === undefined ) { config = toolGroup; toolGroup = config.toolGroup; } // Configuration initialization config = config || {}; // Parent constructor OO.ui.Tool.super.call( this, config ); // Properties this.toolGroup = toolGroup; this.toolbar = this.toolGroup.getToolbar(); this.active = false; this.$title = $( '' ); this.$accel = $( '' ); this.$link = $( '' ); this.title = null; // Mixin constructors OO.ui.IconElement.call( this, config ); OO.ui.FlaggedElement.call( this, config ); OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$link } ) ); // Events this.toolbar.connect( this, { updateState: 'onUpdateState' } ); // Initialization this.$title.addClass( 'oo-ui-tool-title' ); this.$accel .addClass( 'oo-ui-tool-accel' ) .prop( { // This may need to be changed if the key names are ever localized, // but for now they are essentially written in English dir: 'ltr', lang: 'en' } ); this.$link .addClass( 'oo-ui-tool-link' ) .append( this.$icon, this.$title, this.$accel ) .attr( 'role', 'button' ); this.$element .data( 'oo-ui-tool', this ) .addClass( 'oo-ui-tool ' + 'oo-ui-tool-name-' + this.constructor.static.name.replace( /^([^\/]+)\/([^\/]+).*$/, '$1-$2' ) ) .toggleClass( 'oo-ui-tool-with-label', this.constructor.static.displayBothIconAndLabel ) .append( this.$link ); this.setTitle( config.title || this.constructor.static.title ); }; /* Setup */ OO.inheritClass( OO.ui.Tool, OO.ui.Widget ); OO.mixinClass( OO.ui.Tool, OO.ui.IconElement ); OO.mixinClass( OO.ui.Tool, OO.ui.FlaggedElement ); OO.mixinClass( OO.ui.Tool, OO.ui.TabIndexedElement ); /* Events */ /** * @event select */ /* Static Properties */ /** * @static * @inheritdoc */ OO.ui.Tool.static.tagName = 'span'; /** * Symbolic name of tool. * * @abstract * @static * @inheritable * @property {string} */ OO.ui.Tool.static.name = ''; /** * Tool group. * * @abstract * @static * @inheritable * @property {string} */ OO.ui.Tool.static.group = ''; /** * Tool title. * * Title is used as a tooltip when the tool is part of a bar tool group, or a label when the tool * is part of a list or menu tool group. If a trigger is associated with an action by the same name * as the tool, a description of its keyboard shortcut for the appropriate platform will be * appended to the title if the tool is part of a bar tool group. * * @abstract * @static * @inheritable * @property {string|Function} Title text or a function that returns text */ OO.ui.Tool.static.title = ''; /** * Whether this tool should be displayed with both title and label when used in a bar tool group. * Normally only the icon is displayed, or only the label if no icon is given. * * @static * @inheritable * @property {boolean} */ OO.ui.Tool.static.displayBothIconAndLabel = false; /** * Tool can be automatically added to catch-all groups. * * @static * @inheritable * @property {boolean} */ OO.ui.Tool.static.autoAddToCatchall = true; /** * Tool can be automatically added to named groups. * * @static * @property {boolean} * @inheritable */ OO.ui.Tool.static.autoAddToGroup = true; /** * Check if this tool is compatible with given data. * * @static * @inheritable * @param {Mixed} data Data to check * @return {boolean} Tool can be used with data */ OO.ui.Tool.static.isCompatibleWith = function () { return false; }; /* Methods */ /** * Handle the toolbar state being updated. * * This is an abstract method that must be overridden in a concrete subclass. * * @abstract */ OO.ui.Tool.prototype.onUpdateState = function () { throw new Error( 'OO.ui.Tool.onUpdateState not implemented in this subclass:' + this.constructor ); }; /** * Handle the tool being selected. * * This is an abstract method that must be overridden in a concrete subclass. * * @abstract */ OO.ui.Tool.prototype.onSelect = function () { throw new Error( 'OO.ui.Tool.onSelect not implemented in this subclass:' + this.constructor ); }; /** * Check if the button is active. * * @return {boolean} Button is active */ OO.ui.Tool.prototype.isActive = function () { return this.active; }; /** * Make the button appear active or inactive. * * @param {boolean} state Make button appear active */ OO.ui.Tool.prototype.setActive = function ( state ) { this.active = !!state; if ( this.active ) { this.$element.addClass( 'oo-ui-tool-active' ); } else { this.$element.removeClass( 'oo-ui-tool-active' ); } }; /** * Get the tool title. * * @param {string|Function} title Title text or a function that returns text * @chainable */ OO.ui.Tool.prototype.setTitle = function ( title ) { this.title = OO.ui.resolveMsg( title ); this.updateTitle(); return this; }; /** * Get the tool title. * * @return {string} Title text */ OO.ui.Tool.prototype.getTitle = function () { return this.title; }; /** * Get the tool's symbolic name. * * @return {string} Symbolic name of tool */ OO.ui.Tool.prototype.getName = function () { return this.constructor.static.name; }; /** * Update the title. */ OO.ui.Tool.prototype.updateTitle = function () { var titleTooltips = this.toolGroup.constructor.static.titleTooltips, accelTooltips = this.toolGroup.constructor.static.accelTooltips, accel = this.toolbar.getToolAccelerator( this.constructor.static.name ), tooltipParts = []; this.$title.text( this.title ); this.$accel.text( accel ); if ( titleTooltips && typeof this.title === 'string' && this.title.length ) { tooltipParts.push( this.title ); } if ( accelTooltips && typeof accel === 'string' && accel.length ) { tooltipParts.push( accel ); } if ( tooltipParts.length ) { this.$link.attr( 'title', tooltipParts.join( ' ' ) ); } else { this.$link.removeAttr( 'title' ); } }; /** * Destroy tool. */ OO.ui.Tool.prototype.destroy = function () { this.toolbar.disconnect( this ); this.$element.remove(); };