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

Commit

Permalink
Merge pull request #94 from ckeditor/t/ckeditor5-image/241
Browse files Browse the repository at this point in the history
Feature: Introduced image widget resizer. See ckeditor/ckeditor5-image#241.
  • Loading branch information
Reinmar authored Aug 19, 2019
2 parents aec5888 + 1a31082 commit c84cd73
Show file tree
Hide file tree
Showing 5 changed files with 983 additions and 13 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"@ckeditor/ckeditor5-core": "^12.2.1",
"@ckeditor/ckeditor5-engine": "^13.2.1",
"@ckeditor/ckeditor5-ui": "^13.0.2",
"@ckeditor/ckeditor5-utils": "^13.0.1"
"@ckeditor/ckeditor5-utils": "^13.0.1",
"lodash-es": "^4.17.10"
},
"devDependencies": {
"@ckeditor/ckeditor5-basic-styles": "^11.1.3",
Expand Down
162 changes: 162 additions & 0 deletions src/widgetresize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/**
* @module widget/widgetresize
*/

import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import Resizer from './widgetresize/resizer';
import DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
import global from '@ckeditor/ckeditor5-utils/src/dom/global';
import { throttle } from 'lodash-es';

/**
* Widget resize feature plugin.
*
* Use the {@link module:widget/widgetresize~WidgetResize#attachTo} method to create a resizer for the specified widget.
*
* @extends module:core/plugin~Plugin
*/
export default class WidgetResize extends Plugin {
/**
* @inheritDoc
*/
static get pluginName() {
return 'WidgetResize';
}

init() {
this.resizers = [];
this.activeResizer = null;

const domDocument = global.window.document;
const THROTTLE_THRESHOLD = 16; // 16ms = ~60fps

this.editor.model.schema.setAttributeProperties( 'width', {
isFormatting: true
} );

this._observer = Object.create( DomEmitterMixin );

this._observer.listenTo( domDocument, 'mousedown', ( event, domEventData ) => {
if ( !Resizer.isResizeHandle( domEventData.target ) ) {
return;
}

const resizeHandle = domEventData.target;

this.activeResizer = this._getResizerByHandle( resizeHandle );

if ( this.activeResizer ) {
this.activeResizer.begin( resizeHandle );
}
} );

this._observer.listenTo( domDocument, 'mousemove', throttle( ( event, domEventData ) => {
if ( this.activeResizer ) {
this.activeResizer.updateSize( domEventData );
}
}, THROTTLE_THRESHOLD ) );

this._observer.listenTo( domDocument, 'mouseup', () => {
if ( this.activeResizer ) {
this.activeResizer.commit();

this.activeResizer = null;
}
} );

const redrawResizers = throttle( () => {
for ( const context of this.resizers ) {
context.redraw();
}
}, THROTTLE_THRESHOLD );

// Redrawing on any change of the UI of the editor (including content changes).
this.editor.ui.on( 'update', redrawResizers );

// Resizers need to be redrawn upon window resize, because new window might shrink resize host.
this._observer.listenTo( global.window, 'resize', redrawResizers );
}

destroy() {
this._observer.stopListening();
}

/**
* @param {module:widget/widgetresize~ResizerOptions} [options] Resizer options.
* @returns {module:widget/widgetresize/resizer~Resizer}
*/
attachTo( options ) {
const resizer = new Resizer( options );

resizer.attach();

this.editor.editing.view.once( 'render', () => resizer.redraw() );

this.resizers.push( resizer );

return resizer;
}

_getResizerByHandle( domResizeHandle ) {
for ( const resizer of this.resizers ) {
if ( resizer.containsHandle( domResizeHandle ) ) {
return resizer;
}
}
}
}

/**
* Interface describing a resizer. It allows to specify resizing host, custom logic for calculating aspect ratio etc.
*
* @interface ResizerOptions
*/

/**
* @member {module:engine/model/element~Element} module:widget/widgetresize~ResizerOptions#modelElement
*/

/**
* @member {module:engine/view/containerelement~ContainerElement} module:widget/widgetresize~ResizerOptions#viewElement
*/

/**
* @member {module:engine/view/downcastwriter~DowncastWriter} module:widget/widgetresize~ResizerOptions#downcastWriter
*/

/**
* A callback to be executed once resizing process is done.
*
* It receives a `Number` (`newValue`) as a parameter.
*
* For example, {@link module:image/imageresize~ImageResize} uses it to execute image resize command,
* which puts new value into the model.
*
* ```js
* {
* modelElement: data.item,
* viewElement: widget,
* downcastWriter: conversionApi.writer,
*
* onCommit( newValue ) {
* editor.execute( 'imageResize', { width: newValue } );
* }
* };
* ```
*
*
* @member {Function} module:widget/widgetresize~ResizerOptions#onCommit
*/

/**
* @member {Function} module:widget/widgetresize~ResizerOptions#getResizeHost
*/

/**
* @member {Function} module:widget/widgetresize~ResizerOptions#isCentered
*/
Loading

0 comments on commit c84cd73

Please sign in to comment.