Răsfoiți Sursa

Internal: Added generic support for percent-based resizing.

Marek Lewandowski 6 ani în urmă
părinte
comite
36f6aa70f6

+ 43 - 11
packages/ckeditor5-widget/src/widgetresize/resizer.js

@@ -97,18 +97,24 @@ export default class Resizer {
 
 		this.sizeUI.bindToState( this.state );
 
-		this.state.begin( domResizeHandle, this._getResizeHost() );
+		this.state.begin( domResizeHandle, this._getHandleHost() );
 
 		this.redraw();
 	}
 
+	_newGetResizeHost() {
+		return this._getResizeHost().parentElement;
+	}
+
 	updateSize( domEventData ) {
 		const resizeHost = this._getResizeHost();
+		const newResizeHost = this._newGetResizeHost();
 		const newSize = this._proposeNewSize( domEventData );
 
-		resizeHost.style.width = newSize.width + 'px';
+		resizeHost.style.width = null;
+		newResizeHost.style.width = newSize.width + 'px';
 
-		this.state.fetchSizeFromElement( resizeHost );
+		this.state.fetchSizeFromElement( resizeHost, newResizeHost );
 
 		// Refresh values based on the real image. Real image might be limited by max-width, and thus fetching it
 		// here will reflect this limitation.
@@ -117,6 +123,8 @@ export default class Resizer {
 	}
 
 	commit() {
+		this.state.fetchSizeFromElement( this._getResizeHost(), this._newGetResizeHost() );
+
 		this._options.onCommit( this.state );
 
 		this._cleanup();
@@ -202,7 +210,7 @@ export default class Resizer {
 		// +----------------+--+
 		// |                |  |
 		// |       img      |  |
-		// |                |  |
+		// |  /handle host  |  |
 		// +----------------+  | ^
 		// |                   | | - enlarge y
 		// +-------------------+ v
@@ -258,11 +266,7 @@ export default class Resizer {
 	/**
 	 * Method used to obtain the resize host.
 	 *
-	 * Resize host is an object that is actually resized.
-	 *
-	 * Resize host will not always be an entire widget itself. Take an image as an example. Image widget
-	 * contains an image and caption. Only the image should be used to resize the widget, while the caption
-	 * will simply follow the image size.
+	 * Resize host is an object that receives dimensions that are result of resizing.
 	 *
 	 * @protected
 	 * @returns {HTMLElement}
@@ -274,6 +278,24 @@ export default class Resizer {
 			this._options.getResizeHost( widgetWrapper ) : widgetWrapper;
 	}
 
+	/**
+	 * Method used to obtain the resize host.
+	 *
+	 * Handle host is an object to which the handles are aligned to.
+	 *
+	 * Handle host will not always be an entire widget itself. Take an image as an example. Image widget
+	 * contains an image and a caption. Only image should be surrounded with handles.
+	 *
+	 * @protected
+	 * @returns {HTMLElement}
+	 */
+	_getHandleHost() {
+		const widgetWrapper = this._domResizerWrapper.parentElement;
+
+		return this._options.getHandleHost ?
+			this._options.getHandleHost( widgetWrapper ) : widgetWrapper;
+	}
+
 	/**
 	 * Renders the resize handles in DOM.
 	 *
@@ -356,8 +378,18 @@ class SizeView extends View {
 		this.bind( 'isVisible' ).to( resizerState, 'proposedWidth', resizerState, 'proposedHeight', ( width, height ) =>
 			width !== null && height !== null );
 
-		this.bind( 'label' ).to( resizerState, 'proposedWidth', resizerState, 'proposedHeight', ( width, height ) =>
-			`${ width }×${ height }` );
+		this.bind( 'label' ).to(
+			resizerState, 'proposedWidth',
+			resizerState, 'proposedHeight',
+			resizerState, 'proposedWidthPercents',
+			( width, height, widthPercents ) => {
+				if ( widthPercents ) {
+					return `${ widthPercents }%`;
+				} else {
+					return `${ width }×${ height }`;
+				}
+			}
+		);
 
 		this.bind( 'activeHandlePosition' ).to( resizerState );
 	}

+ 30 - 7
packages/ckeditor5-widget/src/widgetresize/resizerstate.js

@@ -65,6 +65,15 @@ export default class ResizeState {
 		 */
 		this.set( 'proposedHeight', null );
 
+		/**
+		 * TODO
+		 *
+		 * @readonly
+		 * @observable
+		 * @member {Number|null} #proposedWidthPercents
+		 */
+		this.set( 'proposedWidthPercents', null );
+
 		/**
 		 * TODO
 		 *
@@ -93,12 +102,12 @@ export default class ResizeState {
 	 *
 	 * @param {HTMLElement} domResizeHandle The handle used to calculate the reference point.
 	 */
-	begin( domResizeHandle, resizeHost ) {
-		const clientRect = new Rect( resizeHost );
+	begin( domResizeHandle, handleHost ) {
+		const clientRect = new Rect( handleHost );
 
 		this.activeHandlePosition = getHandlePosition( domResizeHandle );
 
-		this._referenceCoordinates = getAbsoluteBoundaryPoint( resizeHost, getOppositePosition( this.activeHandlePosition ) );
+		this._referenceCoordinates = getAbsoluteBoundaryPoint( handleHost, getOppositePosition( this.activeHandlePosition ) );
 
 		this.originalSize = {
 			width: clientRect.width,
@@ -106,23 +115,37 @@ export default class ResizeState {
 		};
 
 		this.aspectRatio = this._options.getAspectRatio ?
-			this._options.getAspectRatio( resizeHost ) : clientRect.width / clientRect.height;
+			this._options.getAspectRatio( handleHost ) : clientRect.width / clientRect.height;
 	}
 
 	/**
 	 * Sets `proposedWidth` / `proposedHeight` properties based on provided element.
 	 *
-	 * @param {HTMLElement} domElement
+	 * @param {HTMLElement} domHandleHost
+	 * @param {HTMLElement} domResizeHost
 	 */
-	fetchSizeFromElement( domElement ) {
+	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( domElement );
+		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 );
+		}
+	}
+
+	_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 );
+
+		this.proposedWidthPercents = Math.min( Math.round( rect.width / hostParentInnerWith * 100 ), 100 );
 	}
 }