Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Fixed image resize flashing unexpected size #112

Merged
merged 16 commits into from
Jan 3, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions src/widgetresize.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
} );

resizer.on( 'cancel', () => {
widgetToolbarRepository.clearForceDisabled( 'resize' );
} );

resizer.on( 'commit', () => {
widgetToolbarRepository.clearForceDisabled( 'resize' );
} );
}

this._resizers.set( options.viewElement, resizer );

return resizer;
Expand Down Expand Up @@ -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
*/

/**
Expand All @@ -200,9 +221,9 @@ mix( WidgetResize, ObservableMixin );
*
* ```js
* {
* editor,
* modelElement: data.item,
* viewElement: widget,
* downcastWriter: conversionApi.writer,
*
* onCommit( newValue ) {
* editor.execute( 'imageResize', { width: newValue } );
Expand Down
123 changes: 76 additions & 47 deletions src/widgetresize/resizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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' } );
}

/**
Expand All @@ -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 );
}

/**
Expand All @@ -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 );
Expand Down Expand Up @@ -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 ) {
Expand Down