All files / src/ui/actions ve.ui.FormatAction.js

95.83% Statements 23/24
90% Branches 9/10
100% Functions 4/4
95.83% Lines 23/24

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                                1x   9x         1x       1x   1x                             1x 9x 9x 9x   9x       9x       9x 16x   16x     9x 16x     9x 9x             2x   9x   9x   9x         1x  
/*!
 * VisualEditor UserInterface FormatAction class.
 *
 * @copyright See AUTHORS.txt
 */
 
/**
 * Format action.
 *
 * @class
 * @extends ve.ui.Action
 *
 * @constructor
 * @param {ve.ui.Surface} surface Surface to act on
 * @param {string} [source]
 */
ve.ui.FormatAction = function VeUiFormatAction() {
	// Parent constructor
	ve.ui.FormatAction.super.apply( this, arguments );
};
 
/* Inheritance */
 
OO.inheritClass( ve.ui.FormatAction, ve.ui.Action );
 
/* Static Properties */
 
ve.ui.FormatAction.static.name = 'format';
 
ve.ui.FormatAction.static.methods = [ 'convert' ];
 
/* Methods */
 
/**
 * Convert the format of content.
 *
 * Conversion splits and unwraps all lists and replaces content branch nodes.
 *
 * TODO: Refactor functionality into {ve.dm.SurfaceFragment}.
 *
 * @param {string} type
 * @param {Object} attributes
 * @return {boolean} Action was executed
 */
ve.ui.FormatAction.prototype.convert = function ( type, attributes ) {
	var surfaceModel = this.surface.getModel(),
		fragment = surfaceModel.getFragment(),
		fragmentSelection = fragment.getSelection();
 
	Iif ( !( fragmentSelection instanceof ve.dm.LinearSelection ) ) {
		return;
	}
 
	var fragments = [];
 
	// We can't have headings or pre's in a list, so if we're trying to convert
	// things that are in lists to a heading or a pre, split the list
	fragment.getSelectedLeafNodes().forEach( function ( node ) {
		var contentBranch = node.isContent() ? node.getParent() : node;
 
		fragments.push( surfaceModel.getLinearFragment( contentBranch.getOuterRange(), true ) );
	} );
 
	fragments.forEach( function ( f ) {
		f.isolateAndUnwrap( type );
	} );
 
	fragment.convertNodes( type, attributes );
	if ( fragmentSelection.isCollapsed() ) {
		// Converting an empty node needs a small selection fixup afterwards,
		// otherwise the selection will be displayed outside the new empty
		// node. This causes issues with the display of the current format in
		// the toolbar, and with hitting enter if no content is entered. Don't
		// always reapply the selection, because the automatic behavior is
		// better if isolateAndUnwrap has actually acted. (T151594)
		surfaceModel.setSelection( fragmentSelection );
	}
	this.surface.getView().focus();
 
	ve.track( 'activity.format', { action: type + ( attributes && attributes.level ? ( '-' + attributes.level ) : '' ) } );
 
	return true;
};
 
/* Registration */
 
ve.ui.actionFactory.register( ve.ui.FormatAction );