8
0
Просмотр исходного кода

Align feature class naming to a new scheme.

Maciej Gołaszewski 8 лет назад
Родитель
Сommit
32882f444d
28 измененных файлов с 685 добавлено и 562 удалено
  1. 1 1
      packages/ckeditor5-image/docs/features/image.md
  2. 3 3
      packages/ckeditor5-image/src/image.js
  3. 2 2
      packages/ckeditor5-image/src/image/imageediting.js
  4. 2 2
      packages/ckeditor5-image/src/imagecaption.js
  5. 2 2
      packages/ckeditor5-image/src/imagecaption/imagecaptionediting.js
  6. 12 53
      packages/ckeditor5-image/src/imagestyle.js
  7. 4 4
      packages/ckeditor5-image/src/imagestyle/converters.js
  8. 2 2
      packages/ckeditor5-image/src/imagestyle/imagestylecommand.js
  9. 16 16
      packages/ckeditor5-image/src/imagestyle/imagestyleediting.js
  10. 61 0
      packages/ckeditor5-image/src/imagestyle/imagestyleui.js
  11. 5 170
      packages/ckeditor5-image/src/imagetextalternative.js
  12. 2 2
      packages/ckeditor5-image/src/imagetextalternative/imagetextalternativeediting.js
  13. 193 0
      packages/ckeditor5-image/src/imagetextalternative/imagetextalternativeui.js
  14. 3 3
      packages/ckeditor5-image/tests/image.js
  15. 1 1
      packages/ckeditor5-image/tests/image/converters.js
  16. 4 4
      packages/ckeditor5-image/tests/image/imageediting.js
  17. 3 3
      packages/ckeditor5-image/tests/imagecaption.js
  18. 6 6
      packages/ckeditor5-image/tests/imagecaption/imagecaptionediting.js
  19. 7 52
      packages/ckeditor5-image/tests/imagestyle.js
  20. 27 27
      packages/ckeditor5-image/tests/imagestyle/imagestyleediting.js
  21. 80 0
      packages/ckeditor5-image/tests/imagestyle/imagestyleui.js
  22. 7 197
      packages/ckeditor5-image/tests/imagetextalternative.js
  23. 5 4
      packages/ckeditor5-image/tests/imagetextalternative/imagetextalternativeediting.js
  24. 229 0
      packages/ckeditor5-image/tests/imagetextalternative/imagetextalternativeui.js
  25. 1 1
      packages/ckeditor5-image/tests/imageupload/imageuploadcommand.js
  26. 3 3
      packages/ckeditor5-image/tests/imageupload/imageuploadediting.js
  27. 2 2
      packages/ckeditor5-image/tests/imageupload/imageuploadprogress.js
  28. 2 2
      packages/ckeditor5-image/tests/manual/imageplaceholder.js

+ 1 - 1
packages/ckeditor5-image/docs/features/image.md

@@ -148,7 +148,7 @@ See the result below:
 
 ### Defining custom styles
 
-Besides using the {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine.defaultStyles 5 predefined styles}:
+Besides using the {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing.defaultStyles 5 predefined styles}:
 
 * `'imageStyleFull'`,
 * `'imageStyleSide'`,

+ 3 - 3
packages/ckeditor5-image/src/image.js

@@ -8,7 +8,7 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import ImageEngine from './image/imageengine';
+import ImageEditing from '../src/image/imageediting';
 import Widget from '@ckeditor/ckeditor5-widget/src/widget';
 import ImageTextAlternative from './imagetextalternative';
 import { isImageWidgetSelected } from './image/utils';
@@ -18,7 +18,7 @@ import '../theme/image.css';
 /**
  * The image plugin.
  *
- * Uses the {@link module:image/image/imageengine~ImageEngine}.
+ * Uses the {@link module:image/image/imageediting~ImageEditing}.
  *
  * @extends module:core/plugin~Plugin
  */
@@ -27,7 +27,7 @@ export default class Image extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ ImageEngine, Widget, ImageTextAlternative ];
+		return [ ImageEditing, Widget, ImageTextAlternative ];
 	}
 
 	/**

+ 2 - 2
packages/ckeditor5-image/src/image/imageengine.js → packages/ckeditor5-image/src/image/imageediting.js

@@ -4,7 +4,7 @@
  */
 
 /**
- * @module image/image/imageengine
+ * @module image/image/imageediting
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
@@ -30,7 +30,7 @@ import ViewEmptyElement from '@ckeditor/ckeditor5-engine/src/view/emptyelement';
  *
  * @extends module:core/plugin~Plugin
  */
-export default class ImageEngine extends Plugin {
+export default class ImageEditing extends Plugin {
 	/**
 	 * @inheritDoc
 	 */

+ 2 - 2
packages/ckeditor5-image/src/imagecaption.js

@@ -8,7 +8,7 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import ImageCaptionEngine from './imagecaption/imagecaptionengine';
+import ImageCaptionEditing from './imagecaption/imagecaptionediting';
 
 import '../theme/imagecaption.css';
 
@@ -22,7 +22,7 @@ export default class ImageCaption extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ ImageCaptionEngine ];
+		return [ ImageCaptionEditing ];
 	}
 
 	/**

+ 2 - 2
packages/ckeditor5-image/src/imagecaption/imagecaptionengine.js → packages/ckeditor5-image/src/imagecaption/imagecaptionediting.js

@@ -4,7 +4,7 @@
  */
 
 /**
- * @module image/imagecaption/imagecaptionengine
+ * @module image/imagecaption/imagecaptionediting
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
@@ -28,7 +28,7 @@ import {
  *
  * @extends module:core/plugin~Plugin
  */
-export default class ImageCaptionEngine extends Plugin {
+export default class ImageCaptionEditing extends Plugin {
 	/**
 	 * @inheritDoc
 	 */

+ 12 - 53
packages/ckeditor5-image/src/imagestyle.js

@@ -8,15 +8,14 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import ImageStyleEngine from './imagestyle/imagestyleengine';
-import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
-
-import '../theme/imagestyle.css';
+import ImageStyleEditing from './imagestyle/imagestyleediting';
+import ImageStyleUI from './imagestyle/imagestyleui';
 
 /**
  * The image style plugin.
  *
- * Uses the {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine}.
+ * It loads the {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing}
+ * and {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugins.
  *
  * @extends module:core/plugin~Plugin
  */
@@ -25,7 +24,7 @@ export default class ImageStyle extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ ImageStyleEngine ];
+		return [ ImageStyleEditing, ImageStyleUI ];
 	}
 
 	/**
@@ -34,55 +33,15 @@ export default class ImageStyle extends Plugin {
 	static get pluginName() {
 		return 'ImageStyle';
 	}
-
-	/**
-	 * @inheritDoc
-	 */
-	init() {
-		const editor = this.editor;
-		const styles = editor.plugins.get( ImageStyleEngine ).imageStyles;
-
-		for ( const style of styles ) {
-			this._createButton( style );
-		}
-	}
-
-	/**
-	 * Creates a button for each style and stores it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.
-	 *
-	 * @private
-	 * @param {module:image/imagestyle/imagestyleengine~ImageStyleFormat} style
-	 */
-	_createButton( style ) {
-		const editor = this.editor;
-		const command = editor.commands.get( style.name );
-
-		editor.ui.componentFactory.add( style.name, locale => {
-			const view = new ButtonView( locale );
-
-			view.set( {
-				label: style.title,
-				icon: style.icon,
-				tooltip: true
-			} );
-
-			view.bind( 'isEnabled' ).to( command, 'isEnabled' );
-			view.bind( 'isOn' ).to( command, 'value' );
-
-			this.listenTo( view, 'execute', () => editor.execute( style.name ) );
-
-			return view;
-		} );
-	}
 }
 
 /**
  * Available image styles.
- * The option is used by the {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine} feature.
+ * The option is used by the {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing} feature.
  *
  * The default value is:
  *
- * 		const imageConfig = {
+ *		const imageConfig = {
  *			styles: [ 'imageStyleFull', 'imageStyleSide' ]
  *		};
  *
@@ -91,12 +50,12 @@ export default class ImageStyle extends Plugin {
  *  * the "full" style which doesn't apply any class, e.g. for images styled to span 100% width of the content,
  *  * the "side" style with the `.image-style-side` CSS class.
  *
- * See {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine.defaultStyles} to learn more about default
+ * See {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing.defaultStyles} to learn more about default
  * styles provided by the image feature.
  *
- * The {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine.defaultStyles default styles} can be customized,
+ * The {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing.defaultStyles default styles} can be customized,
  * e.g. to change the icon, title or CSS class of the style. The feature also provides several
- * {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine.defaultIcons default icons} to chose from.
+ * {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing.defaultIcons default icons} to chose from.
  *
  *		import customIcon from 'custom-icon.svg';
  *
@@ -129,7 +88,7 @@ export default class ImageStyle extends Plugin {
  *			]
  *		};
  *
- * Note: Setting `title` to one of {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine#localizedDefaultStylesTitles}
+ * Note: Setting `title` to one of {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing#localizedDefaultStylesTitles}
  * will automatically translate it to the language of the editor.
  *
  * Read more about styling images in the {@glink features/image#Image-styles Image styles guide}.
@@ -147,5 +106,5 @@ export default class ImageStyle extends Plugin {
  *			toolbar: [ 'imageStyleFull', 'imageStyleSide' ]
  *		};
  *
- * @member {Array.<module:image/imagestyle/imagestyleengine~ImageStyleFormat>} module:image/image~ImageConfig#styles
+ * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} module:image/image~ImageConfig#styles
  */

+ 4 - 4
packages/ckeditor5-image/src/imagestyle/converters.js

@@ -12,7 +12,7 @@ import first from '@ckeditor/ckeditor5-utils/src/first';
 /**
  * Returns a converter for the `imageStyle` attribute. It can be used for adding, changing and removing the attribute.
  *
- * @param {Object} styles An object containing available styles. See {@link module:image/imagestyle/imagestyleengine~ImageStyleFormat}
+ * @param {Object} styles An object containing available styles. See {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}
  * for more details.
  * @returns {Function} A model-to-view attribute converter.
  */
@@ -41,7 +41,7 @@ export function modelToViewStyleAttribute( styles ) {
 /**
  * Returns a view-to-model converter converting image CSS classes to a proper value in the model.
  *
- * @param {Array.<module:image/imagestyle/imagestyleengine~ImageStyleFormat>} styles Styles for which the converter is created.
+ * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles Styles for which the converter is created.
  * @returns {Function} A view-to-model converter.
  */
 export function viewToModelStyleAttribute( styles ) {
@@ -75,8 +75,8 @@ export function viewToModelStyleAttribute( styles ) {
 // Returns style with given `name` from array of styles.
 //
 // @param {String} name
-// @param {Array.<module:image/imagestyle/imagestyleengine~ImageStyleFormat> } styles
-// @return {module:image/imagestyle/imagestyleengine~ImageStyleFormat|undefined}
+// @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat> } styles
+// @return {module:image/imagestyle/imagestyleediting~ImageStyleFormat|undefined}
 function getStyleByName( name, styles ) {
 	for ( const style of styles ) {
 		if ( style.name === name ) {

+ 2 - 2
packages/ckeditor5-image/src/imagestyle/imagestylecommand.js

@@ -20,7 +20,7 @@ export default class ImageStyleCommand extends Command {
 	 * Creates an instance of the image style command. Each command instance is handling one style.
 	 *
 	 * @param {module:core/editor/editor~Editor} editor The editor instance.
-	 * @param {module:image/imagestyle/imagestyleengine~ImageStyleFormat} style A style to be applied by this command.
+	 * @param {module:image/imagestyle/imagestyleediting~ImageStyleFormat} style A style to be applied by this command.
 	 */
 	constructor( editor, style ) {
 		super( editor );
@@ -38,7 +38,7 @@ export default class ImageStyleCommand extends Command {
 		 * A style handled by this command.
 		 *
 		 * @readonly
-		 * @member {module:image/imagestyle/imagestyleengine~ImageStyleFormat} #style
+		 * @member {module:image/imagestyle/imagestyleediting~ImageStyleFormat} #style
 		 */
 		this.style = style;
 	}

+ 16 - 16
packages/ckeditor5-image/src/imagestyle/imagestyleengine.js → packages/ckeditor5-image/src/imagestyle/imagestyleediting.js

@@ -4,12 +4,12 @@
  */
 
 /**
- * @module image/imagestyle/imagestyleengine
+ * @module image/imagestyle/imagestyleediting
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import ImageStyleCommand from './imagestylecommand';
-import ImageEngine from '../image/imageengine';
+import ImageEditing from '../image/imageediting';
 import { viewToModelStyleAttribute, modelToViewStyleAttribute } from './converters';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 
@@ -24,19 +24,19 @@ import rightIcon from '@ckeditor/ckeditor5-core/theme/icons/object-right.svg';
  *
  * @extends {module:core/plugin~Plugin}
  */
-export default class ImageStyleEngine extends Plugin {
+export default class ImageStyleEditing extends Plugin {
 	/**
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ ImageEngine ];
+		return [ ImageEditing ];
 	}
 
 	/**
 	 * @inheritDoc
 	 */
 	static get pluginName() {
-		return 'ImageStyleEngine';
+		return 'ImageStyleEditing';
 	}
 
 	/**
@@ -74,11 +74,11 @@ export default class ImageStyleEngine extends Plugin {
 
 	/**
 	 * Returns {@link module:image/image~ImageConfig#styles} array with items normalized in the
-	 * {@link module:image/imagestyle/imagestyleengine~ImageStyleFormat} format, translated
+	 * {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat} format, translated
 	 * `title` and a complete `icon` markup for each style.
 	 *
 	 * @readonly
-	 * @type {Array.<module:image/imagestyle/imagestyleengine~ImageStyleFormat>}
+	 * @type {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}
 	 */
 	get imageStyles() {
 		// Return cached value if there is one to improve the performance.
@@ -112,7 +112,7 @@ export default class ImageStyleEngine extends Plugin {
 	 * use in the {@link #imageStyles}.
 	 *
 	 * The following localized titles corresponding with
-	 * {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine.defaultStyles} are available:
+	 * {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing.defaultStyles} are available:
 	 *
 	 * * `'Full size image'`,
 	 * * `'Side image'`,
@@ -153,7 +153,7 @@ export default class ImageStyleEngine extends Plugin {
  *
  * @member {Object.<String,Object>}
  */
-ImageStyleEngine.defaultStyles = {
+ImageStyleEditing.defaultStyles = {
 	// This option is equal to situation when no style is applied.
 	imageStyleFull: {
 		name: 'imageStyleFull',
@@ -203,7 +203,7 @@ ImageStyleEngine.defaultStyles = {
  *
  * @member {Object.<String, String>}
  */
-ImageStyleEngine.defaultIcons = {
+ImageStyleEditing.defaultIcons = {
 	full: fullWidthIcon,
 	left: leftIcon,
 	right: rightIcon,
@@ -211,14 +211,14 @@ ImageStyleEngine.defaultIcons = {
 };
 
 // Normalizes an image style provided in the {@link module:image/image~ImageConfig#styles}
-// and returns it in a {@link module:image/imagestyle/imagestyleengine~ImageStyleFormat}.
+// and returns it in a {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}.
 //
 // @private
 // @param {Object} style
-// @returns {@link module:image/imagestyle/imagestyleengine~ImageStyleFormat}
+// @returns {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}
 function normalizeStyle( style ) {
-	const defaultStyles = ImageStyleEngine.defaultStyles;
-	const defaultIcons = ImageStyleEngine.defaultIcons;
+	const defaultStyles = ImageStyleEditing.defaultStyles;
+	const defaultIcons = ImageStyleEditing.defaultIcons;
 
 	// Just the name of the style has been passed.
 	if ( typeof style == 'string' ) {
@@ -278,7 +278,7 @@ function normalizeStyle( style ) {
  *			className: 'image-full-size'
  *		}
  *
- * @typedef {Object} module:image/imagestyle/imagestyleengine~ImageStyleFormat
+ * @typedef {Object} module:image/imagestyle/imagestyleediting~ImageStyleFormat
  * @property {String} name The unique name of the style. It will be used to:
  * * register the {@link module:core/command~Command command} which will apply this style,
  * * store the style's button in the editor {@link module:ui/componentfactory~ComponentFactory},
@@ -287,7 +287,7 @@ function normalizeStyle( style ) {
  * A default style does not apply any CSS class to the view element.
  * @property {String} icon One of the following to be used when creating the style's button:
  *  * An SVG icon source (as an XML string),
- *  * One of {@link module:image/imagestyle/imagestyleengine~ImageStyleEngine.defaultIcons} to use a default icon provided by the plugin.
+ *  * One of {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing.defaultIcons} to use a default icon provided by the plugin.
  * @property {String} title The style's title.
  * @property {String} className The CSS class used to represent the style in view.
  */

+ 61 - 0
packages/ckeditor5-image/src/imagestyle/imagestyleui.js

@@ -0,0 +1,61 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module image/imagestyle/imagestyleui
+ */
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import ImageStyleEditing from './imagestyleediting';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+
+import '../../theme/imagestyle.css';
+
+/**
+ * The image style UI plugin.
+ *
+ * @extends module:core/plugin~Plugin
+ */
+export default class ImageStyleUI extends Plugin {
+	/**
+	 * @inheritDoc
+	 */
+	init() {
+		const editor = this.editor;
+		const styles = editor.plugins.get( ImageStyleEditing ).imageStyles;
+
+		for ( const style of styles ) {
+			this._createButton( style );
+		}
+	}
+
+	/**
+	 * Creates a button for each style and stores it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.
+	 *
+	 * @private
+	 * @param {module:image/imagestyle/imagestyleediting~ImageStyleFormat} style
+	 */
+	_createButton( style ) {
+		const editor = this.editor;
+
+		editor.ui.componentFactory.add( style.name, locale => {
+			const command = editor.commands.get( style.name );
+			const view = new ButtonView( locale );
+
+			view.set( {
+				label: style.title,
+				icon: style.icon,
+				tooltip: true
+			} );
+
+			view.bind( 'isEnabled' ).to( command, 'isEnabled' );
+			view.bind( 'isOn' ).to( command, 'value' );
+
+			this.listenTo( view, 'execute', () => editor.execute( style.name ) );
+
+			return view;
+		} );
+	}
+}

+ 5 - 170
packages/ckeditor5-image/src/imagetextalternative.js

@@ -8,19 +8,14 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
-import ImageTextAlternativeEngine from './imagetextalternative/imagetextalternativeengine';
-import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';
-import TextAlternativeFormView from './imagetextalternative/ui/textalternativeformview';
-import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';
-import textAlternativeIcon from '@ckeditor/ckeditor5-core/theme/icons/low-vision.svg';
-import { repositionContextualBalloon, getBalloonPositionData } from './image/ui/utils';
-import { isImageWidgetSelected } from './image/utils';
+import ImageTextAlternativeEditing from './imagetextalternative/imagetextalternativeediting';
+import ImageTextAlternativeUI from './imagetextalternative/imagetextalternativeui';
 
 /**
  * The image text alternative plugin.
  *
- * The plugin uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.
+ * It loads the {@link module:image/imagetextalternative/imagetextalternativeediting~ImageTextAlternativeEditing}
+ * and {@link module:image/imagetextalternative/imagetextalternativeui~ImageTextAlternativeUI} plugins.
  *
  * @extends module:core/plugin~Plugin
  */
@@ -29,7 +24,7 @@ export default class ImageTextAlternative extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ ImageTextAlternativeEngine, ContextualBalloon ];
+		return [ ImageTextAlternativeEditing, ImageTextAlternativeUI ];
 	}
 
 	/**
@@ -38,164 +33,4 @@ export default class ImageTextAlternative extends Plugin {
 	static get pluginName() {
 		return 'ImageTextAlternative';
 	}
-
-	/**
-	 * @inheritDoc
-	 */
-	init() {
-		this._createButton();
-		this._createForm();
-	}
-
-	/**
-	 * Creates a button showing the balloon panel for changing the image text alternative and
-	 * registers it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.
-	 *
-	 * @private
-	 */
-	_createButton() {
-		const editor = this.editor;
-		const command = editor.commands.get( 'imageTextAlternative' );
-		const t = editor.t;
-
-		editor.ui.componentFactory.add( 'imageTextAlternative', locale => {
-			const view = new ButtonView( locale );
-
-			view.set( {
-				label: t( 'Change image text alternative' ),
-				icon: textAlternativeIcon,
-				tooltip: true
-			} );
-
-			view.bind( 'isEnabled' ).to( command, 'isEnabled' );
-
-			this.listenTo( view, 'execute', () => this._showForm() );
-
-			return view;
-		} );
-	}
-
-	/**
-	 * Creates the {@link module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}
-	 * form.
-	 *
-	 * @private
-	 */
-	_createForm() {
-		const editor = this.editor;
-		const editingView = editor.editing.view;
-
-		/**
-		 * The contextual balloon plugin instance.
-		 *
-		 * @private
-		 * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}
-		 */
-		this._balloon = this.editor.plugins.get( 'ContextualBalloon' );
-
-		/**
-		 * A form containing a textarea and buttons, used to change the `alt` text value.
-		 *
-		 * @member {module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView} #form
-		 */
-		this._form = new TextAlternativeFormView( editor.locale );
-
-		// Render the form so its #element is available for clickOutsideHandler.
-		this._form.render();
-
-		this.listenTo( this._form, 'submit', () => {
-			editor.execute( 'imageTextAlternative', {
-				newValue: this._form.labeledInput.inputView.element.value
-			} );
-
-			this._hideForm( true );
-		} );
-
-		this.listenTo( this._form, 'cancel', () => {
-			this._hideForm( true );
-		} );
-
-		// Close the form on Esc key press.
-		this._form.keystrokes.set( 'Esc', ( data, cancel ) => {
-			this._hideForm( true );
-			cancel();
-		} );
-
-		// Reposition the balloon or hide the form if an image widget is no longer selected.
-		this.listenTo( editingView, 'render', () => {
-			if ( !isImageWidgetSelected( editingView.selection ) ) {
-				this._hideForm( true );
-			} else if ( this._isVisible ) {
-				repositionContextualBalloon( editor );
-			}
-		}, { priority: 'low' } );
-
-		// Close on click outside of balloon panel element.
-		clickOutsideHandler( {
-			emitter: this._form,
-			activator: () => this._isVisible,
-			contextElements: [ this._form.element ],
-			callback: () => this._hideForm()
-		} );
-	}
-
-	/**
-	 * Shows the {@link #_form} in the {@link #_balloon}.
-	 *
-	 * @private
-	 */
-	_showForm() {
-		if ( this._isVisible ) {
-			return;
-		}
-
-		const editor = this.editor;
-		const command = editor.commands.get( 'imageTextAlternative' );
-		const labeledInput = this._form.labeledInput;
-
-		if ( !this._balloon.hasView( this._form ) ) {
-			this._balloon.add( {
-				view: this._form,
-				position: getBalloonPositionData( editor )
-			} );
-		}
-
-		// Make sure that each time the panel shows up, the field remains in sync with the value of
-		// the command. If the user typed in the input, then canceled the balloon (`labeledInput#value`
-		// stays unaltered) and re-opened it without changing the value of the command, they would see the
-		// old value instead of the actual value of the command.
-		// https://github.com/ckeditor/ckeditor5-image/issues/114
-		labeledInput.value = labeledInput.inputView.element.value = command.value || '';
-
-		this._form.labeledInput.select();
-	}
-
-	/**
-	 * Removes the {@link #_form} from the {@link #_balloon}.
-	 *
-	 * @param {Boolean} [focusEditable=false] Controls whether the editing view is focused afterwards.
-	 * @private
-	 */
-	_hideForm( focusEditable ) {
-		if ( !this._isVisible ) {
-			return;
-		}
-
-		this._balloon.remove( this._form );
-
-		if ( focusEditable ) {
-			this.editor.editing.view.focus();
-		}
-	}
-
-	/**
-	 * Returns `true` when the {@link #_form} is the visible view
-	 * in the {@link #_balloon}.
-	 *
-	 * @private
-	 * @type {Boolean}
-	 */
-	get _isVisible() {
-		return this._balloon.visibleView == this._form;
-	}
 }

+ 2 - 2
packages/ckeditor5-image/src/imagetextalternative/imagetextalternativeengine.js → packages/ckeditor5-image/src/imagetextalternative/imagetextalternativeediting.js

@@ -4,7 +4,7 @@
  */
 
 /**
- * @module image/imagetextalternative/imagetextalternativeengine
+ * @module image/imagetextalternative/imagetextalternativeediting
  */
 
 import ImageTextAlternativeCommand from './imagetextalternativecommand';
@@ -16,7 +16,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
  *
  * @extends module:core/plugin~Plugin
  */
-export default class ImageTextAlternativeEngine extends Plugin {
+export default class ImageTextAlternativeEditing extends Plugin {
 	/**
 	 * @inheritDoc
 	 */

+ 193 - 0
packages/ckeditor5-image/src/imagetextalternative/imagetextalternativeui.js

@@ -0,0 +1,193 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module image/imagetextalternative/imagetextalternativeui
+ */
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';
+import TextAlternativeFormView from './ui/textalternativeformview';
+import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';
+import textAlternativeIcon from '@ckeditor/ckeditor5-core/theme/icons/low-vision.svg';
+import { repositionContextualBalloon, getBalloonPositionData } from '../image/ui/utils';
+import { isImageWidgetSelected } from '../image/utils';
+
+/**
+ * The image text alternative UI plugin.
+ *
+ * The plugin uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.
+ *
+ * @extends module:core/plugin~Plugin
+ */
+export default class ImageTextAlternativeUI extends Plugin {
+	/**
+	 * @inheritDoc
+	 */
+	static get requires() {
+		return [ ContextualBalloon ];
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	init() {
+		this._createButton();
+		this._createForm();
+	}
+
+	/**
+	 * Creates a button showing the balloon panel for changing the image text alternative and
+	 * registers it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.
+	 *
+	 * @private
+	 */
+	_createButton() {
+		const editor = this.editor;
+		const t = editor.t;
+
+		editor.ui.componentFactory.add( 'imageTextAlternative', locale => {
+			const command = editor.commands.get( 'imageTextAlternative' );
+			const view = new ButtonView( locale );
+
+			view.set( {
+				label: t( 'Change image text alternative' ),
+				icon: textAlternativeIcon,
+				tooltip: true
+			} );
+
+			view.bind( 'isEnabled' ).to( command, 'isEnabled' );
+
+			this.listenTo( view, 'execute', () => this._showForm() );
+
+			return view;
+		} );
+	}
+
+	/**
+	 * Creates the {@link module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}
+	 * form.
+	 *
+	 * @private
+	 */
+	_createForm() {
+		const editor = this.editor;
+		const editingView = editor.editing.view;
+
+		/**
+		 * The contextual balloon plugin instance.
+		 *
+		 * @private
+		 * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}
+		 */
+		this._balloon = this.editor.plugins.get( 'ContextualBalloon' );
+
+		/**
+		 * A form containing a textarea and buttons, used to change the `alt` text value.
+		 *
+		 * @member {module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView} #form
+		 */
+		this._form = new TextAlternativeFormView( editor.locale );
+
+		// Render the form so its #element is available for clickOutsideHandler.
+		this._form.render();
+
+		this.listenTo( this._form, 'submit', () => {
+			editor.execute( 'imageTextAlternative', {
+				newValue: this._form.labeledInput.inputView.element.value
+			} );
+
+			this._hideForm( true );
+		} );
+
+		this.listenTo( this._form, 'cancel', () => {
+			this._hideForm( true );
+		} );
+
+		// Close the form on Esc key press.
+		this._form.keystrokes.set( 'Esc', ( data, cancel ) => {
+			this._hideForm( true );
+			cancel();
+		} );
+
+		// Reposition the balloon or hide the form if an image widget is no longer selected.
+		this.listenTo( editingView, 'render', () => {
+			if ( !isImageWidgetSelected( editingView.selection ) ) {
+				this._hideForm( true );
+			} else if ( this._isVisible ) {
+				repositionContextualBalloon( editor );
+			}
+		}, { priority: 'low' } );
+
+		// Close on click outside of balloon panel element.
+		clickOutsideHandler( {
+			emitter: this._form,
+			activator: () => this._isVisible,
+			contextElements: [ this._form.element ],
+			callback: () => this._hideForm()
+		} );
+	}
+
+	/**
+	 * Shows the {@link #_form} in the {@link #_balloon}.
+	 *
+	 * @private
+	 */
+	_showForm() {
+		if ( this._isVisible ) {
+			return;
+		}
+
+		const editor = this.editor;
+		const command = editor.commands.get( 'imageTextAlternative' );
+		const labeledInput = this._form.labeledInput;
+
+		if ( !this._balloon.hasView( this._form ) ) {
+			this._balloon.add( {
+				view: this._form,
+				position: getBalloonPositionData( editor )
+			} );
+		}
+
+		// Make sure that each time the panel shows up, the field remains in sync with the value of
+		// the command. If the user typed in the input, then canceled the balloon (`labeledInput#value`
+		// stays unaltered) and re-opened it without changing the value of the command, they would see the
+		// old value instead of the actual value of the command.
+		// https://github.com/ckeditor/ckeditor5-image/issues/114
+		labeledInput.value = labeledInput.inputView.element.value = command.value || '';
+
+		this._form.labeledInput.select();
+	}
+
+	/**
+	 * Removes the {@link #_form} from the {@link #_balloon}.
+	 *
+	 * @param {Boolean} [focusEditable=false] Controls whether the editing view is focused afterwards.
+	 * @private
+	 */
+	_hideForm( focusEditable ) {
+		if ( !this._isVisible ) {
+			return;
+		}
+
+		this._balloon.remove( this._form );
+
+		if ( focusEditable ) {
+			this.editor.editing.view.focus();
+		}
+	}
+
+	/**
+	 * Returns `true` when the {@link #_form} is the visible view
+	 * in the {@link #_balloon}.
+	 *
+	 * @private
+	 * @type {Boolean}
+	 */
+	get _isVisible() {
+		return this._balloon.visibleView == this._form;
+	}
+}

+ 3 - 3
packages/ckeditor5-image/tests/image.js

@@ -5,7 +5,7 @@
 
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
 import Image from '../src/image';
-import ImageEngine from '../src/image/imageengine';
+import ImageEditing from '../src/image/imageediting';
 import Widget from '@ckeditor/ckeditor5-widget/src/widget';
 import ImageTextAlternative from '../src/imagetextalternative';
 import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
@@ -42,8 +42,8 @@ describe( 'Image', () => {
 		expect( editor.plugins.get( Image ) ).to.instanceOf( Image );
 	} );
 
-	it( 'should load ImageEngine plugin', () => {
-		expect( editor.plugins.get( ImageEngine ) ).to.instanceOf( ImageEngine );
+	it( 'should load ImageEditing plugin', () => {
+		expect( editor.plugins.get( ImageEditing ) ).to.instanceOf( ImageEditing );
 	} );
 
 	it( 'should load Widget plugin', () => {

+ 1 - 1
packages/ckeditor5-image/tests/image/converters.js

@@ -8,7 +8,7 @@ import {
 	modelToViewAttributeConverter
 } from '../../src/image/converters';
 import { toImageWidget } from '../../src/image/utils';
-import { createImageViewElement } from '../../src/image/imageengine';
+import { createImageViewElement } from '../../src/image/imageediting';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 
 import { downcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';

+ 4 - 4
packages/ckeditor5-image/tests/image/imageengine.js → packages/ckeditor5-image/tests/image/imageediting.js

@@ -4,20 +4,20 @@
  */
 
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
-import ImageEngine from '../../src/image/imageengine';
+import ImageEditing from '../../src/image/imageediting';
 import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
 import { elementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/two-way-converters';
 import { isImageWidget } from '../../src/image/utils';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 
-describe( 'ImageEngine', () => {
+describe( 'ImageEditing', () => {
 	let editor, model, document, viewDocument;
 
 	beforeEach( () => {
 		return VirtualTestEditor
 			.create( {
-				plugins: [ ImageEngine ]
+				plugins: [ ImageEditing ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
@@ -28,7 +28,7 @@ describe( 'ImageEngine', () => {
 	} );
 
 	it( 'should be loaded', () => {
-		expect( editor.plugins.get( ImageEngine ) ).to.be.instanceOf( ImageEngine );
+		expect( editor.plugins.get( ImageEditing ) ).to.be.instanceOf( ImageEditing );
 	} );
 
 	it( 'should set proper schema rules', () => {

+ 3 - 3
packages/ckeditor5-image/tests/imagecaption.js

@@ -7,7 +7,7 @@
 
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
 import ImageCaption from '../src/imagecaption';
-import ImageCaptionEngine from '../src/imagecaption/imagecaptionengine';
+import ImageCaptionEditing from '../src/imagecaption/imagecaptionediting';
 
 describe( 'ImageCaption', () => {
 	let editor;
@@ -29,7 +29,7 @@ describe( 'ImageCaption', () => {
 		expect( editor.plugins.get( ImageCaption ) ).to.instanceOf( ImageCaption );
 	} );
 
-	it( 'should load ImageCaptionEngine plugin', () => {
-		expect( editor.plugins.get( ImageCaptionEngine ) ).to.instanceOf( ImageCaptionEngine );
+	it( 'should load ImageCaptionEditing plugin', () => {
+		expect( editor.plugins.get( ImageCaptionEditing ) ).to.instanceOf( ImageCaptionEditing );
 	} );
 } );

+ 6 - 6
packages/ckeditor5-image/tests/imagecaption/imagecaptionengine.js → packages/ckeditor5-image/tests/imagecaption/imagecaptionediting.js

@@ -5,9 +5,9 @@
 
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 
-import ImageCaptionEngine from '../../src/imagecaption/imagecaptionengine';
-import ImageEngine from '../../src/image/imageengine';
-import UndoEngine from '@ckeditor/ckeditor5-undo/src/undoengine';
+import ImageCaptionEditing from '../../src/imagecaption/imagecaptionediting';
+import ImageEditing from '../../src/image/imageediting';
+import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 
 import ViewAttributeElement from '@ckeditor/ckeditor5-engine/src/view/attributeelement';
@@ -21,13 +21,13 @@ import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils
 
 import { elementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/two-way-converters';
 
-describe( 'ImageCaptionEngine', () => {
+describe( 'ImageCaptionEditing', () => {
 	let editor, model, doc, viewDocument;
 
 	beforeEach( () => {
 		return VirtualTestEditor
 			.create( {
-				plugins: [ ImageCaptionEngine, ImageEngine, UndoEngine, Paragraph ]
+				plugins: [ ImageCaptionEditing, ImageEditing, UndoEditing, Paragraph ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
@@ -47,7 +47,7 @@ describe( 'ImageCaptionEngine', () => {
 	} );
 
 	it( 'should be loaded', () => {
-		expect( editor.plugins.get( ImageCaptionEngine ) ).to.be.instanceOf( ImageCaptionEngine );
+		expect( editor.plugins.get( ImageCaptionEditing ) ).to.be.instanceOf( ImageCaptionEditing );
 	} );
 
 	it( 'should set proper schema rules', () => {

+ 7 - 52
packages/ckeditor5-image/tests/imagestyle.js

@@ -5,17 +5,12 @@
 
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
 import ImageStyle from '../src/imagestyle';
-import ImageStyleEngine from '../src/imagestyle/imagestyleengine';
-import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import ImageStyleEditing from '../src/imagestyle/imagestyleediting';
+import ImageStyleUI from '../src/imagestyle/imagestyleui';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 
 describe( 'ImageStyle', () => {
 	let editor;
-	const styles = [
-		{ name: 'style 1', title: 'Style 1 title', icon: 'style1-icon', isDefault: true },
-		{ name: 'style 2', title: 'Style 2 title', icon: 'style2-icon', cssClass: 'style2-class' },
-		{ name: 'style 3', title: 'Style 3 title', icon: 'style3-icon', cssClass: 'style3-class' }
-	];
 
 	beforeEach( () => {
 		const editorElement = global.document.createElement( 'div' );
@@ -23,10 +18,7 @@ describe( 'ImageStyle', () => {
 
 		return ClassicTestEditor
 			.create( editorElement, {
-				plugins: [ ImageStyle ],
-				image: {
-					styles
-				}
+				plugins: [ ImageStyle ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
@@ -41,48 +33,11 @@ describe( 'ImageStyle', () => {
 		expect( editor.plugins.get( ImageStyle ) ).to.be.instanceOf( ImageStyle );
 	} );
 
-	it( 'should load ImageStyleEngine plugin', () => {
-		expect( editor.plugins.get( ImageStyleEngine ) ).to.be.instanceOf( ImageStyleEngine );
+	it( 'should load ImageStyleEditing plugin', () => {
+		expect( editor.plugins.get( ImageStyleEditing ) ).to.be.instanceOf( ImageStyleEditing );
 	} );
 
-	it( 'should register buttons for each style', () => {
-		const spy = sinon.spy( editor, 'execute' );
-
-		for ( const style of styles ) {
-			const command = editor.commands.get( style.name );
-			const buttonView = editor.ui.componentFactory.create( style.name );
-
-			expect( buttonView ).to.be.instanceOf( ButtonView );
-			expect( buttonView.label ).to.equal( style.title );
-			expect( buttonView.icon ).to.equal( style.icon );
-
-			command.isEnabled = true;
-			expect( buttonView.isEnabled ).to.be.true;
-			command.isEnabled = false;
-			expect( buttonView.isEnabled ).to.be.false;
-
-			buttonView.fire( 'execute' );
-			sinon.assert.calledWithExactly( editor.execute, style.name );
-
-			spy.reset();
-		}
-	} );
-
-	it( 'should not add buttons to image toolbar if configuration is present', () => {
-		const editorElement = global.document.createElement( 'div' );
-		global.document.body.appendChild( editorElement );
-
-		return ClassicTestEditor
-			.create( editorElement, {
-				plugins: [ ImageStyle ],
-				image: {
-					styles,
-					toolbar: [ 'foo', 'bar' ]
-				}
-			} )
-			.then( newEditor => {
-				expect( newEditor.config.get( 'image.toolbar' ) ).to.eql( [ 'foo', 'bar' ] );
-				newEditor.destroy();
-			} );
+	it( 'should load ImageStyleUI plugin', () => {
+		expect( editor.plugins.get( ImageStyleUI ) ).to.be.instanceOf( ImageStyleUI );
 	} );
 } );

+ 27 - 27
packages/ckeditor5-image/tests/imagestyle/imagestyleengine.js → packages/ckeditor5-image/tests/imagestyle/imagestyleediting.js

@@ -4,8 +4,8 @@
  */
 
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
-import ImageStyleEngine from '../../src/imagestyle/imagestyleengine';
-import ImageEngine from '../../src/image/imageengine';
+import ImageStyleEditing from '../../src/imagestyle/imagestyleediting';
+import ImageEditing from '../../src/image/imageediting';
 import ImageStyleCommand from '../../src/imagestyle/imagestylecommand';
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import log from '@ckeditor/ckeditor5-utils/src/log';
@@ -21,7 +21,7 @@ import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 
 testUtils.createSinonSandbox();
 
-describe( 'ImageStyleEngine', () => {
+describe( 'ImageStyleEditing', () => {
 	let editor, plugin, model, document, viewDocument;
 
 	afterEach( () => {
@@ -32,7 +32,7 @@ describe( 'ImageStyleEngine', () => {
 		beforeEach( () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ],
+					plugins: [ ImageStyleEditing ],
 				} )
 				.then( newEditor => {
 					editor = newEditor;
@@ -40,11 +40,11 @@ describe( 'ImageStyleEngine', () => {
 		} );
 
 		it( 'should be loaded', () => {
-			expect( editor.plugins.get( ImageStyleEngine ) ).to.be.instanceOf( ImageStyleEngine );
+			expect( editor.plugins.get( ImageStyleEditing ) ).to.be.instanceOf( ImageStyleEditing );
 		} );
 
-		it( 'should load image engine', () => {
-			expect( editor.plugins.get( ImageEngine ) ).to.be.instanceOf( ImageEngine );
+		it( 'should load image editing', () => {
+			expect( editor.plugins.get( ImageEditing ) ).to.be.instanceOf( ImageEditing );
 		} );
 	} );
 
@@ -52,7 +52,7 @@ describe( 'ImageStyleEngine', () => {
 		beforeEach( () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ],
+					plugins: [ ImageStyleEditing ],
 					image: {
 						styles: [
 							{ name: 'fullStyle', title: 'foo', icon: 'object-center', isDefault: true },
@@ -72,7 +72,7 @@ describe( 'ImageStyleEngine', () => {
 		it( 'should define image.styles config', () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ]
+					plugins: [ ImageStyleEditing ]
 				} )
 				.then( newEditor => {
 					editor = newEditor;
@@ -267,7 +267,7 @@ describe( 'ImageStyleEngine', () => {
 		it( 'should fall back to defaults when no image.styles', () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ]
+					plugins: [ ImageStyleEditing ]
 				} )
 				.then( newEditor => {
 					editor = newEditor;
@@ -279,7 +279,7 @@ describe( 'ImageStyleEngine', () => {
 		it( 'should not alter the image.styles config', () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ],
+					plugins: [ ImageStyleEditing ],
 					image: {
 						styles: [
 							'imageStyleSide'
@@ -296,7 +296,7 @@ describe( 'ImageStyleEngine', () => {
 		it( 'should not alter object definitions in the image.styles config', () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ],
+					plugins: [ ImageStyleEditing ],
 					image: {
 						styles: [
 							{ name: 'imageStyleSide' }
@@ -313,11 +313,11 @@ describe( 'ImageStyleEngine', () => {
 		it( 'should cache the styles', () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ]
+					plugins: [ ImageStyleEditing ]
 				} )
 				.then( newEditor => {
 					editor = newEditor;
-					plugin = editor.plugins.get( ImageStyleEngine );
+					plugin = editor.plugins.get( ImageStyleEditing );
 
 					expect( plugin.imageStyles ).to.equal( plugin.imageStyles );
 				} );
@@ -333,7 +333,7 @@ describe( 'ImageStyleEngine', () => {
 
 				return VirtualTestEditor
 					.create( {
-						plugins: [ TranslationMock, ImageStyleEngine ],
+						plugins: [ TranslationMock, ImageStyleEditing ],
 						image: {
 							styles: [
 								// Custom user styles.
@@ -348,7 +348,7 @@ describe( 'ImageStyleEngine', () => {
 					} )
 					.then( newEditor => {
 						editor = newEditor;
-						plugin = editor.plugins.get( ImageStyleEngine );
+						plugin = editor.plugins.get( ImageStyleEditing );
 					} );
 			} );
 
@@ -363,7 +363,7 @@ describe( 'ImageStyleEngine', () => {
 			} );
 
 			it( 'should use one of default icons if #icon matches', () => {
-				expect( plugin.imageStyles[ 1 ].icon ).to.equal( ImageStyleEngine.defaultIcons.right );
+				expect( plugin.imageStyles[ 1 ].icon ).to.equal( ImageStyleEditing.defaultIcons.right );
 			} );
 
 			it( 'should use one of default translations if #title matches', () => {
@@ -374,7 +374,7 @@ describe( 'ImageStyleEngine', () => {
 				expect( plugin.imageStyles[ 3 ] ).to.deep.equal( {
 					name: 'imageStyleFull',
 					title: 'Custom title',
-					icon: ImageStyleEngine.defaultIcons.left,
+					icon: ImageStyleEditing.defaultIcons.left,
 					isDefault: true
 				} );
 			} );
@@ -384,15 +384,15 @@ describe( 'ImageStyleEngine', () => {
 			it( 'should use one of default styles if #name matches', () => {
 				return VirtualTestEditor
 					.create( {
-						plugins: [ ImageStyleEngine ],
+						plugins: [ ImageStyleEditing ],
 						image: {
 							styles: [ 'imageStyleFull' ]
 						}
 					} )
 					.then( newEditor => {
 						editor = newEditor;
-						plugin = editor.plugins.get( ImageStyleEngine );
-						expect( plugin.imageStyles[ 0 ] ).to.deep.equal( ImageStyleEngine.defaultStyles.imageStyleFull );
+						plugin = editor.plugins.get( ImageStyleEditing );
+						expect( plugin.imageStyles[ 0 ] ).to.deep.equal( ImageStyleEditing.defaultStyles.imageStyleFull );
 					} );
 			} );
 
@@ -401,14 +401,14 @@ describe( 'ImageStyleEngine', () => {
 
 				return VirtualTestEditor
 					.create( {
-						plugins: [ ImageStyleEngine ],
+						plugins: [ ImageStyleEditing ],
 						image: {
 							styles: [ 'foo' ]
 						}
 					} )
 					.then( newEditor => {
 						editor = newEditor;
-						plugin = editor.plugins.get( ImageStyleEngine );
+						plugin = editor.plugins.get( ImageStyleEditing );
 
 						expect( plugin.imageStyles[ 0 ] ).to.deep.equal( {
 							name: 'foo'
@@ -428,11 +428,11 @@ describe( 'ImageStyleEngine', () => {
 		it( 'should return localized titles of default styles', () => {
 			return VirtualTestEditor
 				.create( {
-					plugins: [ ImageStyleEngine ]
+					plugins: [ ImageStyleEditing ]
 				} )
 				.then( newEditor => {
 					editor = newEditor;
-					plugin = editor.plugins.get( ImageStyleEngine );
+					plugin = editor.plugins.get( ImageStyleEditing );
 
 					expect( plugin.localizedDefaultStylesTitles ).to.deep.equal( {
 						'Full size image': 'Full size image',
@@ -447,7 +447,7 @@ describe( 'ImageStyleEngine', () => {
 
 	describe( 'defaultStyles', () => {
 		it( 'should be defined', () => {
-			expect( ImageStyleEngine.defaultStyles ).to.deep.equal( {
+			expect( ImageStyleEditing.defaultStyles ).to.deep.equal( {
 				imageStyleFull: {
 					name: 'imageStyleFull',
 					title: 'Full size image',
@@ -484,7 +484,7 @@ describe( 'ImageStyleEngine', () => {
 
 	describe( 'defaultIcons', () => {
 		it( 'should be defined', () => {
-			expect( ImageStyleEngine.defaultIcons ).to.deep.equal( {
+			expect( ImageStyleEditing.defaultIcons ).to.deep.equal( {
 				full: fullWidthIcon,
 				left: leftIcon,
 				right: rightIcon,

+ 80 - 0
packages/ckeditor5-image/tests/imagestyle/imagestyleui.js

@@ -0,0 +1,80 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
+import ImageStyleEditing from '../../src/imagestyle/imagestyleediting';
+import ImageStyleUI from '../../src/imagestyle/imagestyleui';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import global from '@ckeditor/ckeditor5-utils/src/dom/global';
+
+describe( 'ImageStyleUI', () => {
+	let editor;
+	const styles = [
+		{ name: 'style 1', title: 'Style 1 title', icon: 'style1-icon', isDefault: true },
+		{ name: 'style 2', title: 'Style 2 title', icon: 'style2-icon', cssClass: 'style2-class' },
+		{ name: 'style 3', title: 'Style 3 title', icon: 'style3-icon', cssClass: 'style3-class' }
+	];
+
+	beforeEach( () => {
+		const editorElement = global.document.createElement( 'div' );
+		global.document.body.appendChild( editorElement );
+
+		return ClassicTestEditor
+			.create( editorElement, {
+				plugins: [ ImageStyleEditing, ImageStyleUI ],
+				image: {
+					styles
+				}
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+			} );
+	} );
+
+	afterEach( () => {
+		return editor.destroy();
+	} );
+
+	it( 'should register buttons for each style', () => {
+		const spy = sinon.spy( editor, 'execute' );
+
+		for ( const style of styles ) {
+			const command = editor.commands.get( style.name );
+			const buttonView = editor.ui.componentFactory.create( style.name );
+
+			expect( buttonView ).to.be.instanceOf( ButtonView );
+			expect( buttonView.label ).to.equal( style.title );
+			expect( buttonView.icon ).to.equal( style.icon );
+
+			command.isEnabled = true;
+			expect( buttonView.isEnabled ).to.be.true;
+			command.isEnabled = false;
+			expect( buttonView.isEnabled ).to.be.false;
+
+			buttonView.fire( 'execute' );
+			sinon.assert.calledWithExactly( editor.execute, style.name );
+
+			spy.reset();
+		}
+	} );
+
+	it( 'should not add buttons to image toolbar if configuration is present', () => {
+		const editorElement = global.document.createElement( 'div' );
+		global.document.body.appendChild( editorElement );
+
+		return ClassicTestEditor
+			.create( editorElement, {
+				plugins: [ ImageStyleEditing, ImageStyleUI ],
+				image: {
+					styles,
+					toolbar: [ 'foo', 'bar' ]
+				}
+			} )
+			.then( newEditor => {
+				expect( newEditor.config.get( 'image.toolbar' ) ).to.eql( [ 'foo', 'bar' ] );
+				newEditor.destroy();
+			} );
+	} );
+} );

+ 7 - 197
packages/ckeditor5-image/tests/imagetextalternative.js

@@ -3,20 +3,15 @@
  * For licensing, see LICENSE.md.
  */
 
-/* global Event, document */
-
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
 import Image from '../src/image';
 import ImageTextAlternative from '../src/imagetextalternative';
-import ImageTextAlternativeEngine from '../src/imagetextalternative/imagetextalternativeengine';
-import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
-import View from '@ckeditor/ckeditor5-ui/src/view';
+import ImageTextAlternativeEditing from '../src/imagetextalternative/imagetextalternativeediting';
+import ImageTextAlternativeUI from '../src/imagetextalternative/imagetextalternativeui';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
-import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
-import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 
 describe( 'ImageTextAlternative', () => {
-	let editor, editingView, model, doc, plugin, command, form, balloon, editorElement, button;
+	let editor, plugin, editorElement;
 
 	beforeEach( () => {
 		editorElement = global.document.createElement( 'div' );
@@ -28,15 +23,7 @@ describe( 'ImageTextAlternative', () => {
 			} )
 			.then( newEditor => {
 				editor = newEditor;
-				model = editor.model;
-				editingView = editor.editing.view;
-				doc = model.document;
-				newEditor.editing.view.attachDomRoot( editorElement );
 				plugin = editor.plugins.get( ImageTextAlternative );
-				command = editor.commands.get( 'imageTextAlternative' );
-				form = plugin._form;
-				balloon = editor.plugins.get( 'ContextualBalloon' );
-				button = editor.ui.componentFactory.create( 'imageTextAlternative' );
 			} );
 	} );
 
@@ -50,188 +37,11 @@ describe( 'ImageTextAlternative', () => {
 		expect( plugin ).to.be.instanceOf( ImageTextAlternative );
 	} );
 
-	it( 'should load ImageTextAlternativeEngine plugin', () => {
-		expect( editor.plugins.get( ImageTextAlternativeEngine ) ).to.be.instanceOf( ImageTextAlternativeEngine );
-	} );
-
-	describe( 'toolbar button', () => {
-		it( 'should be registered in component factory', () => {
-			expect( button ).to.be.instanceOf( ButtonView );
-		} );
-
-		it( 'should have isEnabled property bind to command\'s isEnabled property', () => {
-			command.isEnabled = true;
-			expect( button.isEnabled ).to.be.true;
-
-			command.isEnabled = false;
-			expect( button.isEnabled ).to.be.false;
-		} );
-
-		it( 'should show balloon panel on execute', () => {
-			expect( balloon.visibleView ).to.be.null;
-
-			setData( model, '[<image src="" alt="foo bar"></image>]' );
-
-			button.fire( 'execute' );
-			expect( balloon.visibleView ).to.equal( form );
-
-			// Make sure successive execute does not throw, e.g. attempting
-			// to display the form twice.
-			button.fire( 'execute' );
-			expect( balloon.visibleView ).to.equal( form );
-		} );
-
-		it( 'should set alt attribute value to textarea and select it', () => {
-			const spy = sinon.spy( form.labeledInput, 'select' );
-
-			setData( model, '[<image src="" alt="foo bar"></image>]' );
-
-			button.fire( 'execute' );
-			sinon.assert.calledOnce( spy );
-			expect( form.labeledInput.value ).equals( 'foo bar' );
-		} );
-
-		it( 'should set empty text to textarea and select it when there is no alt attribute', () => {
-			const spy = sinon.spy( form.labeledInput, 'select' );
-
-			setData( model, '[<image src=""></image>]' );
-
-			button.fire( 'execute' );
-			sinon.assert.calledOnce( spy );
-			expect( form.labeledInput.value ).equals( '' );
-		} );
+	it( 'should load ImageTextAlternativeEditing plugin', () => {
+		expect( editor.plugins.get( ImageTextAlternativeEditing ) ).to.be.instanceOf( ImageTextAlternativeEditing );
 	} );
 
-	describe( 'balloon panel form', () => {
-		// https://github.com/ckeditor/ckeditor5-image/issues/114
-		it( 'should make sure the input always stays in sync with the value of the command', () => {
-			const button = editor.ui.componentFactory.create( 'imageTextAlternative' );
-
-			// Mock the value of the input after some past editing.
-			form.labeledInput.value = 'foo';
-
-			// Mock the user using the form, changing the value but clicking "Cancel".
-			// so the command's value is not updated.
-			form.labeledInput.inputView.element.value = 'This value was canceled.';
-
-			// Mock the user editing the same image once again.
-			setData( model, '[<image src="" alt="foo"></image>]' );
-
-			button.fire( 'execute' );
-			expect( form.labeledInput.inputView.element.value ).to.equal( 'foo' );
-		} );
-
-		it( 'should execute command on submit', () => {
-			const spy = sinon.spy( editor, 'execute' );
-			form.fire( 'submit' );
-
-			sinon.assert.calledOnce( spy );
-			sinon.assert.calledWithExactly( spy, 'imageTextAlternative', {
-				newValue: form.labeledInput.inputView.element.value
-			} );
-		} );
-
-		it( 'should hide the panel on cancel and focus the editing view', () => {
-			const spy = sinon.spy( editor.editing.view, 'focus' );
-
-			setData( model, '[<image src="" alt="foo bar"></image>]' );
-
-			editor.ui.componentFactory.create( 'imageTextAlternative' ).fire( 'execute' );
-			expect( balloon.visibleView ).to.equal( form );
-
-			form.fire( 'cancel' );
-			expect( balloon.visibleView ).to.be.null;
-			sinon.assert.calledOnce( spy );
-		} );
-
-		it( 'should not engage when the form is in the balloon yet invisible', () => {
-			setData( model, '[<image src=""></image>]' );
-			button.fire( 'execute' );
-			expect( balloon.visibleView ).to.equal( form );
-
-			const lastView = new View();
-			lastView.element = document.createElement( 'div' );
-
-			balloon.add( { view: lastView } );
-			expect( balloon.visibleView ).to.equal( lastView );
-
-			button.fire( 'execute' );
-			expect( balloon.visibleView ).to.equal( lastView );
-		} );
-
-		describe( 'integration with the editor selection (#render event)', () => {
-			it( 'should re-position the form', () => {
-				setData( model, '[<image src=""></image>]' );
-				button.fire( 'execute' );
-
-				const spy = sinon.spy( balloon, 'updatePosition' );
-
-				editingView.fire( 'render' );
-				sinon.assert.calledOnce( spy );
-			} );
-
-			it( 'should hide the form and focus editable when image widget has been removed by external change', () => {
-				setData( model, '[<image src=""></image>]' );
-				button.fire( 'execute' );
-
-				const remveSpy = sinon.spy( balloon, 'remove' );
-				const focusSpy = sinon.spy( editor.editing.view, 'focus' );
-
-				// EnqueueChange automatically fires #render event.
-				model.enqueueChange( 'transparent', writer => {
-					writer.remove( doc.selection.getFirstRange() );
-				} );
-
-				sinon.assert.calledWithExactly( remveSpy, form );
-				sinon.assert.calledOnce( focusSpy );
-			} );
-		} );
-
-		describe( 'close listeners', () => {
-			describe( 'keyboard', () => {
-				it( 'should close upon Esc key press and focus the editing view', () => {
-					const hideSpy = sinon.spy( plugin, '_hideForm' );
-					const focusSpy = sinon.spy( editor.editing.view, 'focus' );
-
-					setData( model, '[<image src=""></image>]' );
-					button.fire( 'execute' );
-
-					const keyEvtData = {
-						keyCode: keyCodes.esc,
-						preventDefault: sinon.spy(),
-						stopPropagation: sinon.spy()
-					};
-
-					form.keystrokes.press( keyEvtData );
-					sinon.assert.calledOnce( hideSpy );
-					sinon.assert.calledOnce( keyEvtData.preventDefault );
-					sinon.assert.calledOnce( focusSpy );
-				} );
-			} );
-
-			describe( 'mouse', () => {
-				it( 'should close and not focus editable on click outside the panel', () => {
-					const hideSpy = sinon.spy( plugin, '_hideForm' );
-					const focusSpy = sinon.spy( editor.editing.view, 'focus' );
-
-					setData( model, '[<image src=""></image>]' );
-					button.fire( 'execute' );
-
-					global.document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
-					sinon.assert.called( hideSpy );
-					sinon.assert.notCalled( focusSpy );
-				} );
-
-				it( 'should not close on click inside the panel', () => {
-					const spy = sinon.spy( plugin, '_hideForm' );
-
-					setData( model, '[<image src=""></image>]' );
-					button.fire( 'execute' );
-
-					form.element.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
-					sinon.assert.notCalled( spy );
-				} );
-			} );
-		} );
+	it( 'should load ImageTextAlternativeUI plugin', () => {
+		expect( editor.plugins.get( ImageTextAlternativeUI ) ).to.be.instanceOf( ImageTextAlternativeUI );
 	} );
 } );

+ 5 - 4
packages/ckeditor5-image/tests/imagetextalternative/imagetextalternativeengine.js → packages/ckeditor5-image/tests/imagetextalternative/imagetextalternativeediting.js

@@ -4,22 +4,23 @@
  */
 
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
-import ImageTextAlternativeEngine from '../../src/imagetextalternative/imagetextalternativeengine';
+import ImageTextAlternativeEditing from '../../src/imagetextalternative/imagetextalternativeediting';
 import ImageTextAlternativeCommand from '../../src/imagetextalternative/imagetextalternativecommand';
 
-describe( 'ImageTextAlternativeEngine', () => {
+describe( 'ImageTextAlternativeEditing', () => {
 	let editor;
+
 	beforeEach( () => {
 		return VirtualTestEditor
 			.create( {
-				plugins: [ ImageTextAlternativeEngine ]
+				plugins: [ ImageTextAlternativeEditing ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
 			} );
 	} );
 
-	it( 'should register ImageAlteranteTextCommand', () => {
+	it( 'should register ImageAlternativeTextCommand', () => {
 		expect( editor.commands.get( 'imageTextAlternative' ) ).to.be.instanceOf( ImageTextAlternativeCommand );
 	} );
 } );

+ 229 - 0
packages/ckeditor5-image/tests/imagetextalternative/imagetextalternativeui.js

@@ -0,0 +1,229 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global Event, document */
+
+import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
+import Image from '../../src/image';
+import ImageTextAlternativeEditing from '../../src/imagetextalternative/imagetextalternativeediting';
+import ImageTextAlternativeUI from '../../src/imagetextalternative/imagetextalternativeui';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import View from '@ckeditor/ckeditor5-ui/src/view';
+import global from '@ckeditor/ckeditor5-utils/src/dom/global';
+import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
+
+describe( 'ImageTextAlternative', () => {
+	let editor, editingView, model, doc, plugin, command, form, balloon, editorElement, button;
+
+	beforeEach( () => {
+		editorElement = global.document.createElement( 'div' );
+		global.document.body.appendChild( editorElement );
+
+		return ClassicTestEditor
+			.create( editorElement, {
+				plugins: [ ImageTextAlternativeEditing, ImageTextAlternativeUI, Image ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				editingView = editor.editing.view;
+				doc = model.document;
+				newEditor.editing.view.attachDomRoot( editorElement );
+				plugin = editor.plugins.get( ImageTextAlternativeUI );
+				command = editor.commands.get( 'imageTextAlternative' );
+				form = plugin._form;
+				balloon = editor.plugins.get( 'ContextualBalloon' );
+				button = editor.ui.componentFactory.create( 'imageTextAlternative' );
+			} );
+	} );
+
+	afterEach( () => {
+		editorElement.remove();
+
+		return editor.destroy();
+	} );
+
+	describe( 'toolbar button', () => {
+		it( 'should be registered in component factory', () => {
+			expect( button ).to.be.instanceOf( ButtonView );
+		} );
+
+		it( 'should have isEnabled property bind to command\'s isEnabled property', () => {
+			command.isEnabled = true;
+			expect( button.isEnabled ).to.be.true;
+
+			command.isEnabled = false;
+			expect( button.isEnabled ).to.be.false;
+		} );
+
+		it( 'should show balloon panel on execute', () => {
+			expect( balloon.visibleView ).to.be.null;
+
+			setData( model, '[<image src="" alt="foo bar"></image>]' );
+
+			button.fire( 'execute' );
+			expect( balloon.visibleView ).to.equal( form );
+
+			// Make sure successive execute does not throw, e.g. attempting
+			// to display the form twice.
+			button.fire( 'execute' );
+			expect( balloon.visibleView ).to.equal( form );
+		} );
+
+		it( 'should set alt attribute value to textarea and select it', () => {
+			const spy = sinon.spy( form.labeledInput, 'select' );
+
+			setData( model, '[<image src="" alt="foo bar"></image>]' );
+
+			button.fire( 'execute' );
+			sinon.assert.calledOnce( spy );
+			expect( form.labeledInput.value ).equals( 'foo bar' );
+		} );
+
+		it( 'should set empty text to textarea and select it when there is no alt attribute', () => {
+			const spy = sinon.spy( form.labeledInput, 'select' );
+
+			setData( model, '[<image src=""></image>]' );
+
+			button.fire( 'execute' );
+			sinon.assert.calledOnce( spy );
+			expect( form.labeledInput.value ).equals( '' );
+		} );
+	} );
+
+	describe( 'balloon panel form', () => {
+		// https://github.com/ckeditor/ckeditor5-image/issues/114
+		it( 'should make sure the input always stays in sync with the value of the command', () => {
+			const button = editor.ui.componentFactory.create( 'imageTextAlternative' );
+
+			// Mock the value of the input after some past editing.
+			form.labeledInput.value = 'foo';
+
+			// Mock the user using the form, changing the value but clicking "Cancel".
+			// so the command's value is not updated.
+			form.labeledInput.inputView.element.value = 'This value was canceled.';
+
+			// Mock the user editing the same image once again.
+			setData( model, '[<image src="" alt="foo"></image>]' );
+
+			button.fire( 'execute' );
+			expect( form.labeledInput.inputView.element.value ).to.equal( 'foo' );
+		} );
+
+		it( 'should execute command on submit', () => {
+			const spy = sinon.spy( editor, 'execute' );
+			form.fire( 'submit' );
+
+			sinon.assert.calledOnce( spy );
+			sinon.assert.calledWithExactly( spy, 'imageTextAlternative', {
+				newValue: form.labeledInput.inputView.element.value
+			} );
+		} );
+
+		it( 'should hide the panel on cancel and focus the editing view', () => {
+			const spy = sinon.spy( editor.editing.view, 'focus' );
+
+			setData( model, '[<image src="" alt="foo bar"></image>]' );
+
+			editor.ui.componentFactory.create( 'imageTextAlternative' ).fire( 'execute' );
+			expect( balloon.visibleView ).to.equal( form );
+
+			form.fire( 'cancel' );
+			expect( balloon.visibleView ).to.be.null;
+			sinon.assert.calledOnce( spy );
+		} );
+
+		it( 'should not engage when the form is in the balloon yet invisible', () => {
+			setData( model, '[<image src=""></image>]' );
+			button.fire( 'execute' );
+			expect( balloon.visibleView ).to.equal( form );
+
+			const lastView = new View();
+			lastView.element = document.createElement( 'div' );
+
+			balloon.add( { view: lastView } );
+			expect( balloon.visibleView ).to.equal( lastView );
+
+			button.fire( 'execute' );
+			expect( balloon.visibleView ).to.equal( lastView );
+		} );
+
+		describe( 'integration with the editor selection (#render event)', () => {
+			it( 'should re-position the form', () => {
+				setData( model, '[<image src=""></image>]' );
+				button.fire( 'execute' );
+
+				const spy = sinon.spy( balloon, 'updatePosition' );
+
+				editingView.fire( 'render' );
+				sinon.assert.calledOnce( spy );
+			} );
+
+			it( 'should hide the form and focus editable when image widget has been removed by external change', () => {
+				setData( model, '[<image src=""></image>]' );
+				button.fire( 'execute' );
+
+				const remveSpy = sinon.spy( balloon, 'remove' );
+				const focusSpy = sinon.spy( editor.editing.view, 'focus' );
+
+				// EnqueueChange automatically fires #render event.
+				model.enqueueChange( 'transparent', writer => {
+					writer.remove( doc.selection.getFirstRange() );
+				} );
+
+				sinon.assert.calledWithExactly( remveSpy, form );
+				sinon.assert.calledOnce( focusSpy );
+			} );
+		} );
+
+		describe( 'close listeners', () => {
+			describe( 'keyboard', () => {
+				it( 'should close upon Esc key press and focus the editing view', () => {
+					const hideSpy = sinon.spy( plugin, '_hideForm' );
+					const focusSpy = sinon.spy( editor.editing.view, 'focus' );
+
+					setData( model, '[<image src=""></image>]' );
+					button.fire( 'execute' );
+
+					const keyEvtData = {
+						keyCode: keyCodes.esc,
+						preventDefault: sinon.spy(),
+						stopPropagation: sinon.spy()
+					};
+
+					form.keystrokes.press( keyEvtData );
+					sinon.assert.calledOnce( hideSpy );
+					sinon.assert.calledOnce( keyEvtData.preventDefault );
+					sinon.assert.calledOnce( focusSpy );
+				} );
+			} );
+
+			describe( 'mouse', () => {
+				it( 'should close and not focus editable on click outside the panel', () => {
+					const hideSpy = sinon.spy( plugin, '_hideForm' );
+					const focusSpy = sinon.spy( editor.editing.view, 'focus' );
+
+					setData( model, '[<image src=""></image>]' );
+					button.fire( 'execute' );
+
+					global.document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
+					sinon.assert.called( hideSpy );
+					sinon.assert.notCalled( focusSpy );
+				} );
+
+				it( 'should not close on click inside the panel', () => {
+					const spy = sinon.spy( plugin, '_hideForm' );
+
+					setData( model, '[<image src=""></image>]' );
+					button.fire( 'execute' );
+
+					form.element.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
+					sinon.assert.notCalled( spy );
+				} );
+			} );
+		} );
+	} );
+} );

+ 1 - 1
packages/ckeditor5-image/tests/imageupload/imageuploadcommand.js

@@ -12,7 +12,7 @@ import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
 
 import { createNativeFileMock, UploadAdapterMock } from '@ckeditor/ckeditor5-upload/tests/_utils/mocks';
 import { setData as setModelData, getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
-import Image from '../../src/image/imageengine';
+import Image from '../../src/image/imageediting';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 import { downcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
 import ModelPosition from '@ckeditor/ckeditor5-engine/src/model/position';

+ 3 - 3
packages/ckeditor5-image/tests/imageupload/imageuploadediting.js

@@ -8,11 +8,11 @@
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import ImageEngine from '../../src/image/imageengine';
+import ImageEditing from '../../src/image/imageediting';
 import ImageUploadEditing from '../../src/imageupload/imageuploadediting';
 import ImageUploadCommand from '../../src/imageupload/imageuploadcommand';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
-import UndoEngine from '@ckeditor/ckeditor5-undo/src/undoengine';
+import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
 import DataTransfer from '@ckeditor/ckeditor5-clipboard/src/datatransfer';
 
 import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
@@ -54,7 +54,7 @@ describe( 'ImageUploadEditing', () => {
 
 		return VirtualTestEditor
 			.create( {
-				plugins: [ ImageEngine, ImageUploadEditing, Paragraph, UndoEngine, UploadAdapterPluginMock ]
+				plugins: [ ImageEditing, ImageUploadEditing, Paragraph, UndoEditing, UploadAdapterPluginMock ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;

+ 2 - 2
packages/ckeditor5-image/tests/imageupload/imageuploadprogress.js

@@ -8,7 +8,7 @@
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import ImageEngine from '../../src/image/imageengine';
+import ImageEditing from '../../src/image/imageediting';
 import ImageUploadEditing from '../../src/imageupload/imageuploadediting';
 import ImageUploadProgress from '../../src/imageupload/imageuploadprogress';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
@@ -50,7 +50,7 @@ describe( 'ImageUploadProgress', () => {
 
 		return VirtualTestEditor
 			.create( {
-				plugins: [ ImageEngine, Paragraph, ImageUploadEditing, ImageUploadProgress, UploadAdapterPluginMock ]
+				plugins: [ ImageEditing, Paragraph, ImageUploadEditing, ImageUploadProgress, UploadAdapterPluginMock ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;

+ 2 - 2
packages/ckeditor5-image/tests/manual/imageplaceholder.js

@@ -6,11 +6,11 @@
 /* global document */
 
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
-import ImageEngine from '../../src/image/imageengine';
+import ImageEditing from '../../src/image/imageediting';
 import ImageUploadEditing from '../../src/imageupload/imageuploadediting';
 import ImageUploadProgress from '../../src/imageupload/imageuploadprogress';
 
-VirtualTestEditor.create( { plugins: [ ImageEngine, ImageUploadEditing, ImageUploadProgress ] } )
+VirtualTestEditor.create( { plugins: [ ImageEditing, ImageUploadEditing, ImageUploadProgress ] } )
 	.then( editor => {
 		const imageUploadProgress = editor.plugins.get( ImageUploadProgress );
 		const img = document.createElement( 'img' );