All files / src/ce/nodes ve.ce.ImageNode.js

91.3% Statements 21/23
77.77% Branches 7/9
100% Functions 4/4
91.3% Lines 21/23

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                                      1x 94x           94x 94x     94x 94x     94x 94x     94x         1x   1x               1x 20x                         1x 2x             2x 2x                 1x 24x     3x   21x          
/*!
 * VisualEditor ContentEditable ImageNode class.
 *
 * @copyright See AUTHORS.txt
 */
 
/**
 * ContentEditable image node.
 *
 * @class
 * @abstract
 * @mixes ve.ce.FocusableNode
 * @mixes ve.ce.ResizableNode
 *
 * @constructor
 * @param {jQuery} $figure Image or figure element
 * @param {jQuery} [$image] Actual image element, if $figure is just a container
 * @param {Object} [config] Configuration options
 */
ve.ce.ImageNode = function VeCeImageNode( $figure, $image, config ) {
	config = ve.extendObject( {
		enforceMax: false,
		minDimensions: { width: 1, height: 1 },
		$bounding: this.$element
	}, config );
 
	this.$figure = $figure;
	this.$image = $image || $figure;
 
	// Mixin constructors
	ve.ce.FocusableNode.call( this, this.$figure, config );
	ve.ce.ResizableNode.call( this, this.$image, config );
 
	// Events
	this.$image.on( 'load', this.onLoad.bind( this ) );
	this.model.connect( this, { attributeChange: 'onAttributeChange' } );
 
	// Initialization
	this.$element.addClass( 've-ce-imageNode' );
};
 
/* Inheritance */
 
OO.mixinClass( ve.ce.ImageNode, ve.ce.FocusableNode );
 
OO.mixinClass( ve.ce.ImageNode, ve.ce.ResizableNode );
 
/* Static Methods */
 
// eslint-disable-next-line jsdoc/require-param, jsdoc/require-returns
/**
 * @see ve.ce.Node
 */
ve.ce.ImageNode.static.getDescription = function ( model ) {
	return model.getAttribute( 'src' );
};
 
/* Methods */
 
/**
 * Update the rendering of the 'align', src', 'width' and 'height' attributes
 * when they change in the model.
 *
 * @param {string} key Attribute key
 * @param {string} from Old value
 * @param {string} to New value
 */
ve.ce.ImageNode.prototype.onAttributeChange = function ( key, from, to ) {
	switch ( key ) {
		case 'src':
			this.$image.prop( 'src', this.getResolvedAttribute( 'src' ) );
			break;
 
		case 'width':
		case 'height':
			this.$image.css( key, to !== null ? to : '' );
			break;
	}
};
 
/**
 * Handle the image load
 *
 * @param {jQuery.Event} e Load event
 */
ve.ce.ImageNode.prototype.onLoad = function () {
	if ( !this.model ) {
		// This node has probably been destroyed. (Currently there's no easy way for
		// a mixin class to disconnect listeners on destroy)
		return;
	}
	this.setOriginalDimensions( {
		width: this.$image.prop( 'naturalWidth' ),
		height: this.$image.prop( 'naturalHeight' )
	} );
};