All files / src/ui ve.ui.Tool.js

32.35% Statements 11/34
0% Branches 0/20
0% Functions 0/7
32.35% Lines 11/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159                                  1x                   1x                     1x                       1x                 1x                 1x               1x                     1x                               1x                                 1x                                                                     1x      
/*!
 * VisualEditor UserInterface Tool classes.
 *
 * @copyright See AUTHORS.txt
 */
 
/**
 * UserInterface tool.
 *
 * @class
 * @abstract
 * @extends OO.ui.Tool
 *
 * @constructor
 * @param {OO.ui.ToolGroup} toolGroup
 * @param {Object} [config] Configuration options
 */
ve.ui.Tool = function VeUiTool() {
	// Parent constructor
	ve.ui.Tool.super.apply( this, arguments );
 
	// Disable initially
	this.setDisabled( true );
};
 
/* Inheritance */
 
OO.inheritClass( ve.ui.Tool, OO.ui.Tool );
 
/* Static Properties */
 
/**
 * Command to execute when tool is selected.
 *
 * @static
 * @property {string|null}
 * @inheritable
 */
ve.ui.Tool.static.commandName = null;
 
/**
 * Deactivate tool after it's been selected.
 *
 * Use this for tools which don't display as active when relevant content is selected, such as
 * insertion-only tools.
 *
 * @static
 * @property {boolean}
 * @inheritable
 */
ve.ui.Tool.static.deactivateOnSelect = true;
 
/**
 * If this tool is used to create a ve.ui.ToolContextItem, should that item be embeddable
 *
 * @static
 * @property {boolean}
 * @inheritable
 */
ve.ui.Tool.static.makesEmbeddableContextItem = true;
 
/**
 * Icon to use when this tool is shown in a non-toolbar context
 *
 * @static
 * @property {string|null}
 * @inheritable
 */
ve.ui.Tool.static.fallbackIcon = null;
 
/**
 * Get the symbolic command name for this tool.
 *
 * @static
 * @return {string|null}
 */
ve.ui.Tool.static.getCommandName = function () {
	return this.commandName;
};
 
/**
 * Get the command for this tool in a given surface context
 *
 * @static
 * @param {ve.ui.Surface} surface
 * @return {ve.ui.Command|null|undefined} Undefined means command not found, null means no command set
 */
ve.ui.Tool.static.getCommand = function ( surface ) {
	const commandName = this.getCommandName();
	if ( commandName === null ) {
		return null;
	}
	return surface.commandRegistry.lookup( commandName );
};
 
/* Methods */
 
/**
 * Handle the toolbar state being updated.
 *
 * @param {ve.dm.SurfaceFragment|null} fragment Surface fragment
 * @param {Object|null} direction Context direction with 'inline' & 'block' properties
 */
ve.ui.Tool.prototype.onUpdateState = function ( fragment ) {
	const command = this.getCommand();
	if ( command !== null ) {
		this.setDisabled(
			!command || !fragment || !command.isExecutable( fragment ) ||
			// Show command as disabled if a selection is required and the surface
			// is read-only. Don't do this in Command as some are actually allowed
			// to run, e.g. selectAll
			// TODO: Add an allowedInReadOnly flag to some commands
			( command.supportedSelections && fragment.getSurface() && fragment.getSurface().isReadOnly() )
		);
	}
};
 
/**
 * @inheritdoc
 */
ve.ui.Tool.prototype.onSelect = function () {
	const command = this.getCommand(),
		surface = this.toolbar.getSurface();
 
	let contextClosePromise;
	if ( command instanceof ve.ui.Command ) {
		if ( surface.context.inspector ) {
			contextClosePromise = surface.context.inspector.close().closed;
		} else {
			contextClosePromise = ve.createDeferred().resolve().promise();
		}
	}
	if ( this.constructor.static.deactivateOnSelect ) {
		// It's fine to call setActive here before the promise resolves; it
		// just disables the button, stopping double-clicks and making it feel more responsive
		// if the promise is slow.
		this.setActive( false );
	}
	if ( contextClosePromise ) {
		// N.B. If contextClosePromise is already resolved, then the handler is called
		// before the call to .done returns
		contextClosePromise.done( () => {
			if ( !command.execute( surface, undefined, 'tool' ) ) {
				// If the command fails, ensure the tool is not active
				this.setActive( false );
			}
		} );
	}
};
 
/**
 * Get the command for this tool.
 *
 * @return {ve.ui.Command|null|undefined} Undefined means command not found, null means no command set
 */
ve.ui.Tool.prototype.getCommand = function () {
	return this.constructor.static.getCommand( this.toolbar.getSurface() );
};