8
0
Piotrek Koszuliński 6 лет назад
Родитель
Сommit
f1555771ce

+ 48 - 44
packages/ckeditor5-widget/src/widgetresize/resizer.js

@@ -95,37 +95,44 @@ export default class Resizer {
 	begin( domResizeHandle ) {
 		this.state = new ResizeState( this._options );
 
-		this.sizeUI.bindToState( this.state );
+		this.sizeUI.bindToState( this._options, this.state );
 
-		this.state.begin( domResizeHandle, this._getHandleHost() );
+		this.state.begin( domResizeHandle, this._getHandleHost(), this._getResizeHost() );
 
 		this.redraw();
 	}
 
-	_newGetResizeHost() {
-		return this._getResizeHost().parentElement;
-	}
-
 	updateSize( domEventData ) {
-		const resizeHost = this._getResizeHost();
-		const newResizeHost = this._newGetResizeHost();
+		const domHandleHost = this._getHandleHost();
+		const domResizeHost = this._getResizeHost();
+		const unit = this._options.unit;
 		const newSize = this._proposeNewSize( domEventData );
 
-		resizeHost.style.width = null;
-		newResizeHost.style.width = newSize.width + 'px';
+		domResizeHost.style.width = ( unit === '%' ? newSize.widthPercents : newSize.width ) + this._options.unit;
+
+		const domHandleHostRect = new Rect( domHandleHost );
+
+		newSize.handleHostWidth = Math.round( domHandleHostRect.width );
+		newSize.handleHostHeight = Math.round( domHandleHostRect.height );
+
+		const domResizeHostRect = new Rect( domHandleHost );
+
+		newSize.width = Math.round( domResizeHostRect.width );
+		newSize.height = Math.round( domResizeHostRect.height );
 
-		this.state.fetchSizeFromElement( resizeHost, newResizeHost );
+		this.state.update( newSize );
 
 		// Refresh values based on the real image. Real image might be limited by max-width, and thus fetching it
 		// here will reflect this limitation.
-		this._domResizerWrapper.style.width = this.state.proposedWidth + 'px';
-		this._domResizerWrapper.style.height = this.state.proposedHeight + 'px';
+		this._domResizerWrapper.style.width = newSize.handleHostWidth + 'px';
+		this._domResizerWrapper.style.height = newSize.handleHostHeight + 'px';
 	}
 
 	commit() {
-		this.state.fetchSizeFromElement( this._getResizeHost(), this._newGetResizeHost() );
+		const unit = this._options.unit;
+		const newValue = ( unit === '%' ? this.state.proposedWidthPercents : this.state.proposedWidth ) + this._options.unit;
 
-		this._options.onCommit( this.state );
+		this._options.onCommit( newValue );
 
 		this._cleanup();
 	}
@@ -141,14 +148,15 @@ export default class Resizer {
 		this.cancel();
 	}
 
+	// TODO review this
 	redraw() {
 		const domWrapper = this._domResizerWrapper;
 
 		if ( existsInDom( domWrapper ) ) {
 			// Refresh only if resizer exists in the DOM.
 			const widgetWrapper = domWrapper.parentElement;
-			const resizingHost = this._getResizeHost();
-			const clientRect = new Rect( resizingHost );
+			const handleHost = this._getHandleHost();
+			const clientRect = new Rect( handleHost );
 
 			domWrapper.style.width = clientRect.width + 'px';
 			domWrapper.style.height = clientRect.height + 'px';
@@ -157,12 +165,12 @@ export default class Resizer {
 			// for any additional offsets the resize host might have. E.g. wrapper padding
 			// or simply another editable. By doing that the border and resizers are shown
 			// only around the resize host.
-			if ( !widgetWrapper.isSameNode( resizingHost ) ) {
-				domWrapper.style.left = resizingHost.offsetLeft + 'px';
-				domWrapper.style.top = resizingHost.offsetTop + 'px';
+			if ( !widgetWrapper.isSameNode( handleHost ) ) {
+				domWrapper.style.left = handleHost.offsetLeft + 'px';
+				domWrapper.style.top = handleHost.offsetTop + 'px';
 
-				domWrapper.style.height = resizingHost.offsetHeight + 'px';
-				domWrapper.style.width = resizingHost.offsetWidth + 'px';
+				domWrapper.style.height = handleHost.offsetHeight + 'px';
+				domWrapper.style.width = handleHost.offsetWidth + 'px';
 			}
 		}
 
@@ -195,14 +203,13 @@ export default class Resizer {
 	 * @private
 	 * @param {Event} domEventData Event data that caused the size update request. It should be used to calculate the proposed size.
 	 * @returns {Object} return
-	 * @returns {Number} return.x Proposed width.
-	 * @returns {Number} return.y Proposed height.
+	 * @returns {Number} return.width Proposed width.
+	 * @returns {Number} return.height Proposed height.
 	 */
 	_proposeNewSize( domEventData ) {
 		const state = this.state;
 		const currentCoordinates = extractCoordinates( domEventData );
 		const isCentered = this._options.isCentered ? this._options.isCentered( this ) : true;
-		const originalSize = state.originalSize;
 
 		// Enlargement defines how much the resize host has changed in a given axis. Naturally it could be a negative number
 		// meaning that it has been shrunk.
@@ -217,12 +224,12 @@ export default class Resizer {
 		// 					<-->
 		// 					 enlarge x
 		const enlargement = {
-			x: state._referenceCoordinates.x - ( currentCoordinates.x + originalSize.width ),
-			y: ( currentCoordinates.y - originalSize.height ) - state._referenceCoordinates.y
+			x: state._referenceCoordinates.x - ( currentCoordinates.x + state.originalWidth ),
+			y: ( currentCoordinates.y - state.originalHeight ) - state._referenceCoordinates.y
 		};
 
 		if ( isCentered && state.activeHandlePosition.endsWith( '-right' ) ) {
-			enlargement.x = currentCoordinates.x - ( state._referenceCoordinates.x + originalSize.width );
+			enlargement.x = currentCoordinates.x - ( state._referenceCoordinates.x + state.originalWidth );
 		}
 
 		// Objects needs to be resized twice as much in horizontal axis if centered, since enlargement is counted from
@@ -235,8 +242,8 @@ export default class Resizer {
 
 		// The size proposed by the user. It does not consider the aspect ratio.
 		const proposedSize = {
-			width: Math.abs( originalSize.width + enlargement.x ),
-			height: Math.abs( originalSize.height + enlargement.y )
+			width: Math.abs( state.originalWidth + enlargement.x ),
+			height: Math.abs( state.originalHeight + enlargement.y )
 		};
 
 		// Dominant determination must take the ratio into account.
@@ -256,10 +263,9 @@ export default class Resizer {
 		}
 
 		return {
-			// TODO I couldn't find an automated TC for that, but rounding must be done here.
-			// Do not move it above.
 			width: Math.round( targetSize.width ),
-			height: Math.round( targetSize.height )
+			height: Math.round( targetSize.height ),
+			widthPercents: Math.min( Math.round( state.originalWidthPercents / state.originalWidth * targetSize.width * 100 ) / 100, 100 )
 		};
 	}
 
@@ -274,12 +280,11 @@ export default class Resizer {
 	_getResizeHost() {
 		const widgetWrapper = this._domResizerWrapper.parentElement;
 
-		return this._options.getResizeHost ?
-			this._options.getResizeHost( widgetWrapper ) : widgetWrapper;
+		return this._options.getResizeHost( widgetWrapper );
 	}
 
 	/**
-	 * Method used to obtain the resize host.
+	 * Method used to obtain the handle host.
 	 *
 	 * Handle host is an object to which the handles are aligned to.
 	 *
@@ -292,8 +297,7 @@ export default class Resizer {
 	_getHandleHost() {
 		const widgetWrapper = this._domResizerWrapper.parentElement;
 
-		return this._options.getHandleHost ?
-			this._options.getHandleHost( widgetWrapper ) : widgetWrapper;
+		return this._options.getHandleHost( widgetWrapper );
 	}
 
 	/**
@@ -374,19 +378,19 @@ class SizeView extends View {
 		} );
 	}
 
-	bindToState( resizerState ) {
+	bindToState( options, resizerState ) {
 		this.bind( 'isVisible' ).to( resizerState, 'proposedWidth', resizerState, 'proposedHeight', ( width, height ) =>
 			width !== null && height !== null );
 
 		this.bind( 'label' ).to(
-			resizerState, 'proposedWidth',
-			resizerState, 'proposedHeight',
+			resizerState, 'proposedHandleHostWidth',
+			resizerState, 'proposedHandleHostHeight',
 			resizerState, 'proposedWidthPercents',
 			( width, height, widthPercents ) => {
-				if ( widthPercents ) {
-					return `${ widthPercents }%`;
-				} else {
+				if ( options.unit === 'px' ) {
 					return `${ width }×${ height }`;
+				} else {
+					return `${ widthPercents }%`;
 				}
 			}
 		);

+ 50 - 50
packages/ckeditor5-widget/src/widgetresize/resizerstate.js

@@ -23,14 +23,24 @@ export default class ResizeState {
 	 */
 	constructor( options ) {
 		/**
-		 * The size of resize host before current resize process.
+		 * TODO
 		 *
-		 * This information is only known after DOM was rendered, so it will be updated later.
+		 * @readonly
+		 * @member {Number} #originalWidth
+		 */
+
+		/**
+		 * TODO
 		 *
-		 * It contains an object with `width` and `height` properties.
+		 * @readonly
+		 * @member {Number} #originalHeight
+		 */
+
+		/**
+		 * TODO
 		 *
 		 * @readonly
-		 * @member {Object} #originalSize
+		 * @member {Number} #originalWidthPercents
 		 */
 
 		/**
@@ -44,35 +54,34 @@ export default class ResizeState {
 		this.set( 'activeHandlePosition', null );
 
 		/**
-		 * Width proposed (but not yet accepted) using the widget resizer.
-		 *
-		 * It goes back to `null` once the resizer is dismissed or accepted.
+		 * TODO
 		 *
 		 * @readonly
 		 * @observable
-		 * @member {Number|null} #proposedWidth
+		 * @member {Number|null} #proposedWidthPercents
 		 */
-		this.set( 'proposedWidth', null );
+		this.set( 'proposedWidthPercents', null );
 
 		/**
-		 * Height proposed (but not yet accepted) using the widget resizer.
-		 *
-		 * It goes back to `null` once the resizer is dismissed or accepted.
+		 * TODO
 		 *
 		 * @readonly
 		 * @observable
-		 * @member {Number|null} #proposedHeight
+		 * @member {Number|null} #proposedWidthPixels
 		 */
-		this.set( 'proposedHeight', null );
+		this.set( 'proposedWidth', null );
 
 		/**
 		 * TODO
 		 *
 		 * @readonly
 		 * @observable
-		 * @member {Number|null} #proposedWidthPercents
+		 * @member {Number|null} #proposedHeightPixels
 		 */
-		this.set( 'proposedWidthPercents', null );
+		this.set( 'proposedHeight', null );
+
+		this.set( 'proposedHandleHostWidth', null );
+		this.set( 'proposedHandleHostHeight', null );
 
 		/**
 		 * TODO
@@ -101,51 +110,42 @@ export default class ResizeState {
 	/**
 	 *
 	 * @param {HTMLElement} domResizeHandle The handle used to calculate the reference point.
+	 * @param {HTMLElement} domHandleHost
+	 * @param {HTMLElement} domResizeHost
 	 */
-	begin( domResizeHandle, handleHost ) {
-		const clientRect = new Rect( handleHost );
+	begin( domResizeHandle, domHandleHost, domResizeHost ) {
+		const clientRect = new Rect( domHandleHost );
 
 		this.activeHandlePosition = getHandlePosition( domResizeHandle );
 
-		this._referenceCoordinates = getAbsoluteBoundaryPoint( handleHost, getOppositePosition( this.activeHandlePosition ) );
+		this._referenceCoordinates = getAbsoluteBoundaryPoint( domHandleHost, getOppositePosition( this.activeHandlePosition ) );
 
-		this.originalSize = {
-			width: clientRect.width,
-			height: clientRect.height
-		};
+		this.originalWidth = clientRect.width;
+		this.originalHeight = clientRect.height;
 
-		this.aspectRatio = this._options.getAspectRatio ?
-			this._options.getAspectRatio( handleHost ) : clientRect.width / clientRect.height;
-	}
+		this.aspectRatio = clientRect.width / clientRect.height;
 
-	/**
-	 * Sets `proposedWidth` / `proposedHeight` properties based on provided element.
-	 *
-	 * @param {HTMLElement} domHandleHost
-	 * @param {HTMLElement} domResizeHost
-	 */
-	fetchSizeFromElement( domHandleHost, domResizeHost ) {
-		// TODO the logic from this method should be moved to resizer.js.
-		// Search for other places where we do rounding – it's all in resizer.js.
-		// TODO this needs an automated test – currently it only affects the SizeView
-		// which we don't test.
-		const rect = new Rect( domHandleHost );
-
-		this.proposedWidth = Math.round( rect.width );
-		this.proposedHeight = Math.round( rect.height );
-
-		if ( [ 'percent', '%' ].includes( this._options.unit ) ) {
-			this._proposePercents( new Rect( domResizeHost ), domResizeHost );
+		const widthStyle = domResizeHost.style.width;
+
+		if ( widthStyle ) {
+			if ( widthStyle.match( /^\d+\.?\d*%$/ ) ) {
+				this.originalWidthPercents = parseFloat( widthStyle );
+			} else {
+				// TODO we need to check it via comparing to the parent's width.
+				this.originalWidthPercents = 50;
+			}
+		} else {
+			this.originalWidthPercents = 100;
 		}
 	}
 
-	_proposePercents( rect, domResizeHost ) {
-		const hostParentElement = domResizeHost.parentElement;
-		// We need to use getComputedStyle instead of bounding rect, as rect width also include parent's padding, that **can not**
-		// be occupied by the resized object. Computed width does not include it.
-		const hostParentInnerWith = parseFloat( hostParentElement.ownerDocument.defaultView.getComputedStyle( hostParentElement ).width );
+	update( newSize ) {
+		this.proposedWidth = newSize.width;
+		this.proposedHeight = newSize.height;
+		this.proposedWidthPercents = newSize.widthPercents;
 
-		this.proposedWidthPercents = Math.min( Math.round( rect.width / hostParentInnerWith * 100 ), 100 );
+		this.proposedHandleHostWidth = newSize.handleHostWidth;
+		this.proposedHandleHostHeight = newSize.handleHostHeight;
 	}
 }