diff --git a/src/widgetresize.js b/src/widgetresize.js index cd1ebae4..b72ad140 100644 --- a/src/widgetresize.js +++ b/src/widgetresize.js @@ -135,9 +135,28 @@ export default class WidgetResize extends Plugin { */ attachTo( options ) { const resizer = new Resizer( options ); + const plugins = this.editor.plugins; resizer.attach(); + if ( plugins.has( 'WidgetToolbarRepository' ) ) { + // Hiding widget toolbar to improve the performance + // (https://github.com/ckeditor/ckeditor5-widget/pull/112#issuecomment-564528765). + const widgetToolbarRepository = plugins.get( 'WidgetToolbarRepository' ); + + resizer.on( 'begin', () => { + widgetToolbarRepository.forceDisabled( 'resize' ); + }, { priority: 'lowest' } ); + + resizer.on( 'cancel', () => { + widgetToolbarRepository.clearForceDisabled( 'resize' ); + }, { priority: 'highest' } ); + + resizer.on( 'commit', () => { + widgetToolbarRepository.clearForceDisabled( 'resize' ); + }, { priority: 'highest' } ); + } + this._resizers.set( options.viewElement, resizer ); return resizer; @@ -179,15 +198,17 @@ mix( WidgetResize, ObservableMixin ); */ /** - * @member {module:engine/model/element~Element} module:widget/widgetresize~ResizerOptions#modelElement + * Editor instance associated with the resizer. + * + * @member {module:core/editor/editor~Editor} module:widget/widgetresize~ResizerOptions#editor */ /** - * @member {module:engine/view/containerelement~ContainerElement} module:widget/widgetresize~ResizerOptions#viewElement + * @member {module:engine/model/element~Element} module:widget/widgetresize~ResizerOptions#modelElement */ /** - * @member {module:engine/view/downcastwriter~DowncastWriter} module:widget/widgetresize~ResizerOptions#downcastWriter + * @member {module:engine/view/containerelement~ContainerElement} module:widget/widgetresize~ResizerOptions#viewElement */ /** @@ -200,9 +221,9 @@ mix( WidgetResize, ObservableMixin ); * * ```js * { + * editor, * modelElement: data.item, * viewElement: widget, - * downcastWriter: conversionApi.writer, * * onCommit( newValue ) { * editor.execute( 'imageResize', { width: newValue } ); diff --git a/src/widgetresize/resizer.js b/src/widgetresize/resizer.js index 91169731..858885b5 100644 --- a/src/widgetresize/resizer.js +++ b/src/widgetresize/resizer.js @@ -62,6 +62,14 @@ export default class Resizer { */ this._domResizerWrapper = null; + /** + * A wrapper that is controlled by the resizer. This is usually a widget element. + * + * @private + * @type {module:engine/view/element~Element|null} + */ + this._viewResizerWrapper = null; + /** * @observable */ @@ -71,6 +79,15 @@ export default class Resizer { this.decorate( 'cancel' ); this.decorate( 'commit' ); this.decorate( 'updateSize' ); + + this.on( 'commit', event => { + // State might not be initialized yet. In this case, prevent further handling and make sure that the resizer is + // cleaned up (#5195). + if ( !this.state.proposedWidth ) { + this._cleanup(); + event.stop(); + } + }, { priority: 'high' } ); } /** @@ -79,30 +96,34 @@ export default class Resizer { attach() { const that = this; const widgetElement = this._options.viewElement; - const writer = this._options.downcastWriter; + const editingView = this._options.editor.editing.view; + + editingView.change( writer => { + const viewResizerWrapper = writer.createUIElement( 'div', { + class: 'ck ck-reset_all ck-widget__resizer' + }, function( domDocument ) { + const domElement = this.toDomElement( domDocument ); + + that._appendHandles( domElement ); + that._appendSizeUI( domElement ); - const viewResizerWrapper = writer.createUIElement( 'div', { - class: 'ck ck-reset_all ck-widget__resizer' - }, function( domDocument ) { - const domElement = this.toDomElement( domDocument ); + that._domResizerWrapper = domElement; - that._appendHandles( domElement ); - that._appendSizeUI( domElement ); + that.on( 'change:isEnabled', ( evt, propName, newValue ) => { + domElement.style.display = newValue ? '' : 'none'; + } ); - that._domResizerWrapper = domElement; + domElement.style.display = that.isEnabled ? '' : 'none'; - that.on( 'change:isEnabled', ( evt, propName, newValue ) => { - domElement.style.display = newValue ? '' : 'none'; + return domElement; } ); - domElement.style.display = that.isEnabled ? '' : 'none'; + // Append the resizer wrapper to the widget's wrapper. + writer.insert( writer.createPositionAt( widgetElement, 'end' ), viewResizerWrapper ); + writer.addClass( 'ck-widget_with-resizer', widgetElement ); - return domElement; + this._viewResizerWrapper = viewResizerWrapper; } ); - - // Append the resizer wrapper to the widget's wrapper. - writer.insert( writer.createPositionAt( widgetElement, 'end' ), viewResizerWrapper ); - writer.addClass( 'ck-widget_with-resizer', widgetElement ); } /** @@ -128,13 +149,20 @@ export default class Resizer { * @param {Event} domEventData */ updateSize( domEventData ) { - const domHandleHost = this._getHandleHost(); - const domResizeHost = this._getResizeHost(); - const unit = this._options.unit; const newSize = this._proposeNewSize( domEventData ); + const editingView = this._options.editor.editing.view; - domResizeHost.style.width = ( unit === '%' ? newSize.widthPercents : newSize.width ) + this._options.unit; + editingView.change( writer => { + const unit = this._options.unit; + const newWidth = ( unit === '%' ? newSize.widthPercents : newSize.width ) + unit; + + writer.setStyle( 'width', newWidth, this._options.viewElement ); + } ); + // Get an actual image width, and: + // * reflect this size to the resize wrapper + // * apply this **real** size to the state + const domHandleHost = this._getHandleHost(); const domHandleHostRect = new Rect( domHandleHost ); newSize.handleHostWidth = Math.round( domHandleHostRect.width ); @@ -187,36 +215,37 @@ export default class Resizer { * @param {module:utils/dom/rect~Rect} [handleHostRect] Handle host rectangle might be given to improve performance. */ redraw( handleHostRect ) { - // TODO review this const domWrapper = this._domResizerWrapper; if ( existsInDom( domWrapper ) ) { - // Refresh only if resizer exists in the DOM. - const widgetWrapper = domWrapper.parentElement; - const handleHost = this._getHandleHost(); - const clientRect = handleHostRect || new Rect( handleHost ); - - domWrapper.style.width = clientRect.width + 'px'; - domWrapper.style.height = clientRect.height + 'px'; - - const offsets = { - left: handleHost.offsetLeft, - top: handleHost.offsetTop, - height: handleHost.offsetHeight, - width: handleHost.offsetWidth - }; - - // In case a resizing host is not a widget wrapper, we need to compensate - // 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( handleHost ) ) { - domWrapper.style.left = offsets.left + 'px'; - domWrapper.style.top = offsets.top + 'px'; - - domWrapper.style.height = offsets.height + 'px'; - domWrapper.style.width = offsets.width + 'px'; - } + this._options.editor.editing.view.change( writer => { + // Refresh only if resizer exists in the DOM. + const widgetWrapper = domWrapper.parentElement; + const handleHost = this._getHandleHost(); + const clientRect = handleHostRect || new Rect( handleHost ); + + writer.setStyle( 'width', clientRect.width + 'px', this._viewResizerWrapper ); + writer.setStyle( 'height', clientRect.height + 'px', this._viewResizerWrapper ); + + const offsets = { + left: handleHost.offsetLeft, + top: handleHost.offsetTop, + height: handleHost.offsetHeight, + width: handleHost.offsetWidth + }; + + // In case a resizing host is not a widget wrapper, we need to compensate + // 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( handleHost ) ) { + writer.setStyle( 'left', offsets.left + 'px', this._viewResizerWrapper ); + writer.setStyle( 'top', offsets.top + 'px', this._viewResizerWrapper ); + + writer.setStyle( 'height', offsets.height + 'px', this._viewResizerWrapper ); + writer.setStyle( 'width', offsets.width + 'px', this._viewResizerWrapper ); + } + } ); } function existsInDom( element ) {