Browse Source

Merge branch t/ckeditor5-engine/1210

Internal: Align code to the new view API, introduced in engine t/1210.
Piotr Jasiun 7 years ago
parent
commit
59e4a4d56f
25 changed files with 219 additions and 191 deletions
  1. 1 1
      packages/ckeditor5-image/src/image.js
  2. 10 8
      packages/ckeditor5-image/src/image/converters.js
  3. 15 6
      packages/ckeditor5-image/src/image/imageengine.js
  4. 2 2
      packages/ckeditor5-image/src/image/ui/utils.js
  5. 5 4
      packages/ckeditor5-image/src/image/utils.js
  6. 46 48
      packages/ckeditor5-image/src/imagecaption/imagecaptionengine.js
  7. 7 9
      packages/ckeditor5-image/src/imagecaption/utils.js
  8. 3 2
      packages/ckeditor5-image/src/imagestyle/converters.js
  9. 5 4
      packages/ckeditor5-image/src/imagetextalternative.js
  10. 1 1
      packages/ckeditor5-image/src/imagetoolbar.js
  11. 5 4
      packages/ckeditor5-image/src/imageupload/imageuploadediting.js
  12. 20 15
      packages/ckeditor5-image/src/imageupload/imageuploadprogress.js
  13. 7 6
      packages/ckeditor5-image/tests/image.js
  14. 4 1
      packages/ckeditor5-image/tests/image/converters.js
  15. 13 12
      packages/ckeditor5-image/tests/image/imageengine.js
  16. 2 2
      packages/ckeditor5-image/tests/image/ui/utils.js
  17. 7 4
      packages/ckeditor5-image/tests/image/utils.js
  18. 22 23
      packages/ckeditor5-image/tests/imagecaption/imagecaptionengine.js
  19. 10 6
      packages/ckeditor5-image/tests/imagecaption/utils.js
  20. 5 5
      packages/ckeditor5-image/tests/imagetextalternative.js
  21. 7 7
      packages/ckeditor5-image/tests/imagetoolbar.js
  22. 10 9
      packages/ckeditor5-image/tests/imageupload/imageuploadediting.js
  23. 10 10
      packages/ckeditor5-image/tests/imageupload/imageuploadprogress.js
  24. 1 1
      packages/ckeditor5-image/tests/manual/image.md
  25. 1 1
      packages/ckeditor5-image/tests/manual/textalternative.md

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

@@ -49,7 +49,7 @@ export default class Image extends Plugin {
 		// https://github.com/ckeditor/ckeditor5-image/issues/110
 		if ( contextualToolbar ) {
 			this.listenTo( contextualToolbar, 'show', evt => {
-				if ( isImageWidgetSelected( editor.editing.view.selection ) ) {
+				if ( isImageWidgetSelected( editor.editing.view.document.selection ) ) {
 					evt.stop();
 				}
 			}, { priority: 'high' } );

+ 10 - 8
packages/ckeditor5-image/src/image/converters.js

@@ -80,6 +80,7 @@ export function srcsetAttributeConverter() {
 			return;
 		}
 
+		const writer = conversionApi.writer;
 		const figure = conversionApi.mapper.toViewElement( data.item );
 		const img = figure.getChild( 0 );
 
@@ -87,23 +88,23 @@ export function srcsetAttributeConverter() {
 			const srcset = data.attributeOldValue;
 
 			if ( srcset.data ) {
-				img.removeAttribute( 'srcset' );
-				img.removeAttribute( 'sizes' );
+				writer.removeAttribute( 'srcset', img );
+				writer.removeAttribute( 'sizes', img );
 
 				if ( srcset.width ) {
-					img.removeAttribute( 'width' );
+					writer.removeAttribute( 'width', img );
 				}
 			}
 		} else {
 			const srcset = data.attributeNewValue;
 
 			if ( srcset.data ) {
-				img.setAttribute( 'srcset', srcset.data );
+				writer.setAttribute( 'srcset', srcset.data, img );
 				// Always outputting `100vw`. See https://github.com/ckeditor/ckeditor5-image/issues/2.
-				img.setAttribute( 'sizes', '100vw' );
+				writer.setAttribute( 'sizes', '100vw', img );
 
 				if ( srcset.width ) {
-					img.setAttribute( 'width', srcset.width );
+					writer.setAttribute( 'width', srcset.width, img );
 				}
 			}
 		}
@@ -120,13 +121,14 @@ export function modelToViewAttributeConverter( attributeKey ) {
 			return;
 		}
 
+		const viewWriter = conversionApi.writer;
 		const figure = conversionApi.mapper.toViewElement( data.item );
 		const img = figure.getChild( 0 );
 
 		if ( data.attributeNewValue !== null ) {
-			img.setAttribute( data.attributeKey, data.attributeNewValue );
+			viewWriter.setAttribute( data.attributeKey, data.attributeNewValue, img );
 		} else {
-			img.removeAttribute( data.attributeKey );
+			viewWriter.removeAttribute( data.attributeKey, img );
 		}
 	}
 }

+ 15 - 6
packages/ckeditor5-image/src/image/imageengine.js

@@ -20,8 +20,7 @@ import { toImageWidget } from './utils';
 import { downcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
 import { upcastElementToElement, upcastAttributeToAttribute } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
 
-import ViewContainerElement from '@ckeditor/ckeditor5-engine/src/view/containerelement';
-import ViewEmptyElement from '@ckeditor/ckeditor5-engine/src/view/emptyelement';
+import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
 
 /**
  * The image engine plugin.
@@ -48,14 +47,18 @@ export default class ImageEngine extends Plugin {
 			allowAttributes: [ 'alt', 'src', 'srcset' ]
 		} );
 
+		const dataElementCreator = ( item, consumable, api ) => createImageViewElement( api.writer );
 		editor.conversion.for( 'dataDowncast' ).add( downcastElementToElement( {
 			model: 'image',
-			view: () => createImageViewElement()
+			view: dataElementCreator
 		} ) );
 
+		const editingElementCreator = ( item, consumable, api ) =>
+			toImageWidget( createImageViewElement( api.writer ), api.writer, t( 'image widget' ) );
+
 		editor.conversion.for( 'editingDowncast' ).add( downcastElementToElement( {
 			model: 'image',
-			view: () => toImageWidget( createImageViewElement(), t( 'image widget' ) )
+			view: editingElementCreator
 		} ) );
 
 		conversion.for( 'downcast' )
@@ -111,7 +114,13 @@ export default class ImageEngine extends Plugin {
 // Note that `alt` and `src` attributes are converted separately, so they are not included.
 //
 // @private
+// @param {module:engine/view/writer~Writer} writer
 // @return {module:engine/view/containerelement~ContainerElement}
-export function createImageViewElement() {
-	return new ViewContainerElement( 'figure', { class: 'image' }, new ViewEmptyElement( 'img' ) );
+export function createImageViewElement( writer ) {
+	const emptyElement = writer.createEmptyElement( 'img' );
+	const figure = writer.createContainerElement( 'figure', { class: 'image' } );
+
+	writer.insert( ViewPosition.createAt( figure ), emptyElement );
+
+	return figure;
 }

+ 2 - 2
packages/ckeditor5-image/src/image/ui/utils.js

@@ -20,7 +20,7 @@ import { isImageWidgetSelected } from '../utils';
 export function repositionContextualBalloon( editor ) {
 	const balloon = editor.plugins.get( 'ContextualBalloon' );
 
-	if ( isImageWidgetSelected( editor.editing.view.selection ) ) {
+	if ( isImageWidgetSelected( editor.editing.view.document.selection ) ) {
 		const position = getBalloonPositionData( editor );
 
 		balloon.updatePosition( position );
@@ -40,7 +40,7 @@ export function getBalloonPositionData( editor ) {
 	const defaultPositions = BalloonPanelView.defaultPositions;
 
 	return {
-		target: editingView.domConverter.viewToDom( editingView.selection.getSelectedElement() ),
+		target: editingView.domConverter.viewToDom( editingView.document.selection.getSelectedElement() ),
 		positions: [
 			defaultPositions.northArrowSouth,
 			defaultPositions.northArrowSouthWest,

+ 5 - 4
packages/ckeditor5-image/src/image/utils.js

@@ -14,17 +14,18 @@ const imageSymbol = Symbol( 'isImage' );
 
 /**
  * Converts a given {@link module:engine/view/element~Element} to an image widget:
- * * adds a {@link module:engine/view/element~Element#setCustomProperty custom property} allowing to recognize the image widget element,
+ * * adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the image widget element,
  * * calls the {@link module:widget/utils~toWidget toWidget} function with the proper element's label creator.
  *
  * @param {module:engine/view/element~Element} viewElement
+ * @param {module:engine/view/writer~Writer} writer Instance of view writer.
  * @param {String} label Element's label. It will be concatenated with the image `alt` attribute if one is present.
  * @returns {module:engine/view/element~Element}
  */
-export function toImageWidget( viewElement, label ) {
-	viewElement.setCustomProperty( imageSymbol, true );
+export function toImageWidget( viewElement, writer, label ) {
+	writer.setCustomProperty( imageSymbol, true, viewElement );
 
-	return toWidget( viewElement, { label: labelCreator } );
+	return toWidget( viewElement, writer, { label: labelCreator } );
 
 	function labelCreator() {
 		const imgElement = viewElement.getChild( 0 );

+ 46 - 48
packages/ckeditor5-image/src/imagecaption/imagecaptionengine.js

@@ -8,9 +8,6 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import ViewContainerElement from '@ckeditor/ckeditor5-engine/src/view/containerelement';
-import ViewElement from '@ckeditor/ckeditor5-engine/src/view/element';
-import viewWriter from '@ckeditor/ckeditor5-engine/src/view/writer';
 import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
 import { upcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
 import { isImage } from '../image/utils';
@@ -34,7 +31,7 @@ export default class ImageCaptionEngine extends Plugin {
 	 */
 	init() {
 		const editor = this.editor;
-		const viewDocument = editor.editing.view;
+		const view = editor.editing.view;
 		const schema = editor.model.schema;
 		const data = editor.data;
 		const editing = editor.editing;
@@ -48,14 +45,6 @@ export default class ImageCaptionEngine extends Plugin {
 		 * @member {module:engine/view/editableelement~EditableElement} #_lastSelectedCaption
 		 */
 
-		/**
-		 * A function used to create the editable caption element in the editing view.
-		 *
-		 * @private
-		 * @member {Function}
-		 */
-		this._createCaption = captionElementCreator( viewDocument, t( 'Enter image caption' ) );
-
 		// Schema configuration.
 		schema.register( 'caption', {
 			allowIn: 'image',
@@ -73,23 +62,25 @@ export default class ImageCaptionEngine extends Plugin {
 		} ) );
 
 		// Model to view converter for the data pipeline.
-		data.downcastDispatcher.on( 'insert:caption', captionModelToView( new ViewContainerElement( 'figcaption' ), false ) );
+		const createCaptionForData = writer => writer.createContainerElement( 'figcaption' );
+		data.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForData, false ) );
 
 		// Model to view converter for the editing pipeline.
-		editing.downcastDispatcher.on( 'insert:caption', captionModelToView( this._createCaption ) );
+		const createCaptionForEditing = captionElementCreator( view, t( 'Enter image caption' ) );
+		editing.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForEditing ) );
 
 		// Always show caption in view when something is inserted in model.
-		editing.downcastDispatcher.on( 'insert', ( evt, data ) => this._fixCaptionVisibility( data.item ), { priority: 'high' } );
-
-		// Hide caption when everything is removed from it.
 		editing.downcastDispatcher.on(
-			'remove',
-			( evt, data ) => this._fixCaptionVisibility( data.position.parent ),
+			'insert',
+			this._fixCaptionVisibility( data => data.item ),
 			{ priority: 'high' }
 		);
 
+		// Hide caption when everything is removed from it.
+		editing.downcastDispatcher.on( 'remove', this._fixCaptionVisibility( data => data.position.parent ), { priority: 'high' } );
+
 		// Update view before each rendering.
-		this.listenTo( viewDocument, 'render', () => this._updateCaptionVisibility(), { priority: 'high' } );
+		this.listenTo( view, 'render', () => this._updateCaptionVisibility( view ) );
 	}
 
 	/**
@@ -98,13 +89,13 @@ export default class ImageCaptionEngine extends Plugin {
 	 *
 	 * @private
 	 */
-	_updateCaptionVisibility() {
+	_updateCaptionVisibility( view ) {
 		const mapper = this.editor.editing.mapper;
 		let viewCaption;
 
 		// Hide last selected caption if have no child elements.
 		if ( this._lastSelectedCaption && !this._lastSelectedCaption.childCount ) {
-			this._lastSelectedCaption.addClass( 'ck-hidden' );
+			view.change( writer => writer.addClass( 'ck-hidden', this._lastSelectedCaption ) );
 		}
 
 		// If whole image is selected.
@@ -125,33 +116,41 @@ export default class ImageCaptionEngine extends Plugin {
 		}
 
 		if ( viewCaption ) {
-			viewCaption.removeClass( 'ck-hidden' );
+			view.change( writer => writer.removeClass( 'ck-hidden', viewCaption ) );
 			this._lastSelectedCaption = viewCaption;
 		}
 	}
 
 	/**
-	 * Fixes caption visibility during the model-to-view conversion.
+	 * Returns converter that fixes caption visibility during the model-to-view conversion.
 	 * Checks if the changed node is placed inside the caption element and fixes its visibility in the view.
 	 *
 	 * @private
-	 * @param {module:engine/model/node~Node} node
+	 * @param {Function} nodeFinder
+	 * @returns {Function}
 	 */
-	_fixCaptionVisibility( node ) {
-		const modelCaption = getParentCaption( node );
-		const mapper = this.editor.editing.mapper;
-
-		if ( modelCaption ) {
-			const viewCaption = mapper.toViewElement( modelCaption );
-
-			if ( viewCaption ) {
-				if ( modelCaption.childCount ) {
-					viewCaption.removeClass( 'ck-hidden' );
-				} else {
-					viewCaption.addClass( 'ck-hidden' );
+	_fixCaptionVisibility( nodeFinder ) {
+		return ( evt, data, consumable, conversionApi ) => {
+			// There is no consumable on 'remove' event.
+			conversionApi = conversionApi ? conversionApi : consumable;
+
+			const node = nodeFinder( data );
+			const modelCaption = getParentCaption( node );
+			const mapper = this.editor.editing.mapper;
+			const viewWriter = conversionApi.writer;
+
+			if ( modelCaption ) {
+				const viewCaption = mapper.toViewElement( modelCaption );
+
+				if ( viewCaption ) {
+					if ( modelCaption.childCount ) {
+						viewWriter.removeClass( 'ck-hidden', viewCaption );
+					} else {
+						viewWriter.addClass( 'ck-hidden', viewCaption );
+					}
 				}
 			}
-		}
+		};
 	}
 
 	/**
@@ -183,7 +182,7 @@ export default class ImageCaptionEngine extends Plugin {
 // Creates a converter that converts image caption model element to view element.
 //
 // @private
-// @param {Function|module:engine/view/element~Element} elementCreator
+// @param {Function} elementCreator
 // @param {Boolean} [hide=true] When set to `false` view element will not be inserted when it's empty.
 // @return {Function}
 function captionModelToView( elementCreator, hide = true ) {
@@ -201,16 +200,15 @@ function captionModelToView( elementCreator, hide = true ) {
 			}
 
 			const viewImage = conversionApi.mapper.toViewElement( data.range.start.parent );
-			const viewCaption = ( elementCreator instanceof ViewElement ) ?
-				elementCreator.clone( true ) :
-				elementCreator();
+			const viewCaption = elementCreator( conversionApi.writer );
+			const viewWriter = conversionApi.writer;
 
 			// Hide if empty.
 			if ( !captionElement.childCount ) {
-				viewCaption.addClass( 'ck-hidden' );
+				viewWriter.addClass( 'ck-hidden', viewCaption );
 			}
 
-			insertViewCaptionAndBind( viewCaption, data.item, viewImage, conversionApi.mapper );
+			insertViewCaptionAndBind( viewCaption, data.item, viewImage, conversionApi );
 		}
 	};
 }
@@ -221,12 +219,12 @@ function captionModelToView( elementCreator, hide = true ) {
 // @param {module:engine/view/containerelement~ContainerElement} viewCaption
 // @param {module:engine/model/element~Element} modelCaption
 // @param {module:engine/view/containerelement~ContainerElement} viewImage
-// @param {module:engine/conversion/mapper~Mapper} mapper
-function insertViewCaptionAndBind( viewCaption, modelCaption, viewImage, mapper ) {
+// @param {Object} conversionApi
+function insertViewCaptionAndBind( viewCaption, modelCaption, viewImage, conversionApi ) {
 	const viewPosition = ViewPosition.createAt( viewImage, 'end' );
 
-	viewWriter.insert( viewPosition, viewCaption );
-	mapper.bindElements( modelCaption, viewCaption );
+	conversionApi.writer.insert( viewPosition, viewCaption );
+	conversionApi.mapper.bindElements( modelCaption, viewCaption );
 }
 
 // Checks if the provided node or one of its ancestors is a caption element, and returns it.

+ 7 - 9
packages/ckeditor5-image/src/imagecaption/utils.js

@@ -8,7 +8,6 @@
  */
 
 import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
-import ViewEditableElement from '@ckeditor/ckeditor5-engine/src/view/editableelement';
 import { attachPlaceholder } from '@ckeditor/ckeditor5-engine/src/view/placeholder';
 import { toWidgetEditable } from '@ckeditor/ckeditor5-widget/src/utils';
 
@@ -17,18 +16,17 @@ const captionSymbol = Symbol( 'imageCaption' );
 /**
  * Returns a function that creates a caption editable element for the given {@link module:engine/view/document~Document}.
  *
- * @param {module:engine/view/document~Document} viewDocument
+ * @param {module:engine/view/view~View} view
  * @param {String} placeholderText The text to be displayed when the caption is empty.
  * @return {Function}
  */
-export function captionElementCreator( viewDocument, placeholderText ) {
-	return () => {
-		const editable = new ViewEditableElement( 'figcaption' );
-		editable.document = viewDocument;
-		editable.setCustomProperty( captionSymbol, true );
-		attachPlaceholder( editable, placeholderText );
+export function captionElementCreator( view, placeholderText ) {
+	return writer => {
+		const editable = writer.createEditableElement( 'figcaption' );
+		writer.setCustomProperty( captionSymbol, true, editable );
+		attachPlaceholder( view, editable, placeholderText );
 
-		return toWidgetEditable( editable );
+		return toWidgetEditable( editable, writer );
 	};
 }
 

+ 3 - 2
packages/ckeditor5-image/src/imagestyle/converters.js

@@ -27,13 +27,14 @@ export function modelToViewStyleAttribute( styles ) {
 		const oldStyle = getStyleByName( data.attributeOldValue, styles );
 
 		const viewElement = conversionApi.mapper.toViewElement( data.item );
+		const viewWriter = conversionApi.writer;
 
 		if ( oldStyle ) {
-			viewElement.removeClass( oldStyle.className );
+			viewWriter.removeClass( oldStyle.className, viewElement );
 		}
 
 		if ( newStyle ) {
-			viewElement.addClass( newStyle.className );
+			viewWriter.addClass( newStyle.className, viewElement );
 		}
 	};
 }

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

@@ -83,7 +83,8 @@ export default class ImageTextAlternative extends Plugin {
 	 */
 	_createForm() {
 		const editor = this.editor;
-		const editingView = editor.editing.view;
+		const view = editor.editing.view;
+		const viewDocument = view.document;
 
 		/**
 		 * The contextual balloon plugin instance.
@@ -122,13 +123,13 @@ export default class ImageTextAlternative extends Plugin {
 		} );
 
 		// Reposition the balloon or hide the form if an image widget is no longer selected.
-		this.listenTo( editingView, 'render', () => {
-			if ( !isImageWidgetSelected( editingView.selection ) ) {
+		this.listenTo( view, 'render', () => {
+			if ( !isImageWidgetSelected( viewDocument.selection ) ) {
 				this._hideForm( true );
 			} else if ( this._isVisible ) {
 				repositionContextualBalloon( editor );
 			}
-		}, { priority: 'low' } );
+		} );
 
 		// Close on click outside of balloon panel element.
 		clickOutsideHandler( {

+ 1 - 1
packages/ckeditor5-image/src/imagetoolbar.js

@@ -95,7 +95,7 @@ export default class ImageToolbar extends Plugin {
 		if ( !editor.ui.focusTracker.isFocused ) {
 			this._hideToolbar();
 		} else {
-			if ( isImageWidgetSelected( editor.editing.view.selection ) ) {
+			if ( isImageWidgetSelected( editor.editing.view.document.selection ) ) {
 				this._showToolbar();
 			} else {
 				this._hideToolbar();

+ 5 - 4
packages/ckeditor5-image/src/imageupload/imageuploadediting.js

@@ -45,7 +45,7 @@ export default class ImageUploadEditing extends Plugin {
 		editor.commands.add( 'imageUpload', new ImageUploadCommand( editor ) );
 
 		// Execute imageUpload command when image is dropped or pasted.
-		editor.editing.view.on( 'clipboardInput', ( evt, data ) => {
+		editor.editing.view.document.on( 'clipboardInput', ( evt, data ) => {
 			// Skip if non empty HTML data is included.
 			// https://github.com/ckeditor/ckeditor5-upload/issues/68
 			if ( isHtmlIncluded( data.dataTransfer ) ) {
@@ -71,7 +71,7 @@ export default class ImageUploadEditing extends Plugin {
 		} );
 
 		// Prevents from browser redirecting to the dropped image.
-		editor.editing.view.on( 'dragover', ( evt, data ) => {
+		editor.editing.view.document.on( 'dragover', ( evt, data ) => {
 			data.preventDefault();
 		} );
 
@@ -134,8 +134,9 @@ export default class ImageUploadEditing extends Plugin {
 				const viewImg = viewFigure.getChild( 0 );
 				const promise = loader.upload();
 
-				viewImg.setAttribute( 'src', data );
-				editor.editing.view.render();
+				editor.editing.view.change( writer => {
+					writer.setAttribute( 'src', data, viewImg );
+				} );
 
 				model.enqueueChange( 'transparent', writer => {
 					writer.setAttribute( 'uploadStatus', 'uploading', imageElement );

+ 20 - 15
packages/ckeditor5-image/src/imageupload/imageuploadprogress.js

@@ -10,7 +10,8 @@
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
 import uploadingPlaceholder from '../../theme/icons/image_placeholder.svg';
-import UIElement from '@ckeditor/ckeditor5-engine/src/view/uielement';
+import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
+import ViewRange from '@ckeditor/ckeditor5-engine/src/view/range';
 
 import '../../theme/imageuploadprogress.css';
 
@@ -52,8 +53,9 @@ export default class ImageUploadProgress extends Plugin {
 	 * @param {module:utils/eventinfo~EventInfo} evt Object containing information about the fired event.
 	 * @param {Object} data Additional information about the change.
 	 * @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable Values to consume.
+	 * @param {Object} conversionApi
 	 */
-	uploadStatusChange( evt, data, consumable ) {
+	uploadStatusChange( evt, data, consumable, conversionApi ) {
 		const editor = this.editor;
 		const modelImage = data.item;
 		const uploadId = modelImage.getAttribute( 'uploadId' );
@@ -66,12 +68,13 @@ export default class ImageUploadProgress extends Plugin {
 		const placeholder = this.placeholder;
 		const status = data.attributeNewValue;
 		const viewFigure = editor.editing.mapper.toViewElement( modelImage );
+		const viewWriter = conversionApi.writer;
 
 		// Show placeholder with infinite progress bar on the top while image is read from disk.
 		if ( status == 'reading' ) {
-			viewFigure.addClass( 'ck-appear', 'ck-infinite-progress', 'ck-image-upload-placeholder' );
+			viewWriter.addClass( [ 'ck-appear', 'ck-infinite-progress', 'ck-image-upload-placeholder' ], viewFigure );
 			const viewImg = viewFigure.getChild( 0 );
-			viewImg.setAttribute( 'src', placeholder );
+			viewWriter.setAttribute( 'src', placeholder, viewImg );
 
 			return;
 		}
@@ -81,15 +84,16 @@ export default class ImageUploadProgress extends Plugin {
 			const loader = fileRepository.loaders.get( uploadId );
 
 			if ( loader ) {
-				const progressBar = createProgressBar();
+				const progressBar = createProgressBar( viewWriter );
 
-				viewFigure.removeClass( 'ck-infinite-progress', 'ck-image-upload-placeholder' );
-				viewFigure.appendChildren( progressBar );
+				viewWriter.removeClass( [ 'ck-infinite-progress', 'ck-image-upload-placeholder' ], viewFigure );
+				viewWriter.insert( ViewPosition.createAt( viewFigure, 'end' ), progressBar );
 
 				// Update progress bar width when uploadedPercent is changed.
 				loader.on( 'change:uploadedPercent', ( evt, name, value ) => {
-					progressBar.setStyle( 'width', value + '%' );
-					editor.editing.view.render();
+					editor.editing.view.change( writer => {
+						writer.setStyle( 'width', value + '%', progressBar );
+					} );
 				} );
 			}
 
@@ -100,12 +104,12 @@ export default class ImageUploadProgress extends Plugin {
 		const progressBar = getProgressBar( viewFigure );
 
 		if ( progressBar ) {
-			progressBar.remove();
+			viewWriter.remove( ViewRange.createOn( progressBar ) );
 		} else {
-			viewFigure.removeClass( 'ck-infinite-progress' );
+			viewWriter.removeClass( 'ck-infinite-progress', viewFigure );
 		}
 
-		viewFigure.removeClass( 'ck-appear', 'ck-image-upload-placeholder' );
+		viewWriter.removeClass( [ 'ck-appear', 'ck-image-upload-placeholder' ], viewFigure );
 	}
 }
 
@@ -115,10 +119,11 @@ const progressBarSymbol = Symbol( 'progress-bar' );
 // Create progress bar element using {@link module:engine/view/uielement~UIElement}.
 //
 // @private
+// @param {module:engine/view/writer~Writer} writer
 // @returns {module:engine/view/uielement~UIElement}
-function createProgressBar() {
-	const progressBar = new UIElement( 'div', { class: 'ck-progress-bar' } );
-	progressBar.setCustomProperty( progressBarSymbol, true );
+function createProgressBar( writer ) {
+	const progressBar = writer.createUIElement( 'div', { class: 'ck-progress-bar' } );
+	writer.setCustomProperty( progressBarSymbol, true, progressBar );
 
 	return progressBar;
 }

+ 7 - 6
packages/ckeditor5-image/tests/image.js

@@ -14,7 +14,7 @@ import ModelRange from '@ckeditor/ckeditor5-engine/src/model/range';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 
 describe( 'Image', () => {
-	let editorElement, model, editor, document, viewDocument;
+	let editorElement, model, view, editor, document, viewDocument;
 
 	beforeEach( () => {
 		editorElement = global.document.createElement( 'div' );
@@ -28,7 +28,8 @@ describe( 'Image', () => {
 				editor = newEditor;
 				model = editor.model;
 				document = model.document;
-				viewDocument = editor.editing.view;
+				view = editor.editing.view;
+				viewDocument = editor.editing.view.document;
 			} );
 	} );
 
@@ -58,7 +59,7 @@ describe( 'Image', () => {
 		it( 'should create fake selection', () => {
 			setModelData( model, '[<image alt="alt text" src="foo.png"></image>]' );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget ck-widget_selected image" contenteditable="false">' +
 					'<img alt="alt text" src="foo.png"></img>' +
 				'</figure>]'
@@ -71,7 +72,7 @@ describe( 'Image', () => {
 		it( 'should create proper fake selection label when alt attribute is empty', () => {
 			setModelData( model, '[<image src="foo.png" alt=""></image>]' );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget ck-widget_selected image" contenteditable="false">' +
 				'<img alt="" src="foo.png"></img>' +
 				'</figure>]'
@@ -87,7 +88,7 @@ describe( 'Image', () => {
 				'<image src="foo.png" alt="alt text"></image>'
 			);
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget ck-widget_selected image" contenteditable="false">' +
 				'<img alt="alt text" src="foo.png"></img>' +
 				'</figure>]' +
@@ -101,7 +102,7 @@ describe( 'Image', () => {
 				writer.setSelection( ModelRange.createOn( secondImage ) );
 			} );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'<figure class="ck-widget image" contenteditable="false">' +
 				'<img alt="alt text" src="foo.png"></img>' +
 				'</figure>' +

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

@@ -39,9 +39,12 @@ describe( 'Image converters', () => {
 					isBlock: true
 				} );
 
+				const editingElementCreator = ( item, consumable, api ) =>
+					toImageWidget( createImageViewElement( api.writer ), api.writer, '' );
+
 				editor.conversion.for( 'editingDowncast' ).add( downcastElementToElement( {
 					model: 'image',
-					view: () => toImageWidget( createImageViewElement() )
+					view: editingElementCreator
 				} ) );
 
 				editor.conversion.for( 'downcast' )

+ 13 - 12
packages/ckeditor5-image/tests/image/imageengine.js

@@ -12,7 +12,7 @@ import { isImageWidget } from '../../src/image/utils';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 
 describe( 'ImageEngine', () => {
-	let editor, model, document, viewDocument;
+	let editor, model, document, view, viewDocument;
 
 	beforeEach( () => {
 		return VirtualTestEditor
@@ -23,7 +23,8 @@ describe( 'ImageEngine', () => {
 				editor = newEditor;
 				model = editor.model;
 				document = model.document;
-				viewDocument = editor.editing.view;
+				view = editor.editing.view;
+				viewDocument = view.document;
 			} );
 	} );
 
@@ -380,7 +381,7 @@ describe( 'ImageEngine', () => {
 			it( 'should convert', () => {
 				setModelData( model, '<image src="foo.png" alt="alt text"></image>' );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false"><img alt="alt text" src="foo.png"></img></figure>'
 				);
 			} );
@@ -401,7 +402,7 @@ describe( 'ImageEngine', () => {
 					writer.setAttribute( 'alt', 'new text', image );
 				} );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false"><img alt="new text" src="foo.png"></img></figure>'
 				);
 			} );
@@ -414,7 +415,7 @@ describe( 'ImageEngine', () => {
 					writer.removeAttribute( 'alt', image );
 				} );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) )
+				expect( getViewData( view, { withoutSelection: true } ) )
 					.to.equal( '<figure class="ck-widget image" contenteditable="false"><img src="foo.png"></img></figure>' );
 			} );
 
@@ -430,7 +431,7 @@ describe( 'ImageEngine', () => {
 					writer.removeAttribute( 'alt', image );
 				} );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false"><img alt="alt text" src="foo.png"></img></figure>'
 				);
 			} );
@@ -443,7 +444,7 @@ describe( 'ImageEngine', () => {
 						'srcset=\'{ "data":"small.png 148w, big.png 1024w" }\'>' +
 					'</image>' );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img alt="alt text" sizes="100vw" src="foo.png" srcset="small.png 148w, big.png 1024w"></img>' +
 					'</figure>'
@@ -463,7 +464,7 @@ describe( 'ImageEngine', () => {
 					writer.removeAttribute( 'srcset', image );
 				} );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img alt="alt text" src="foo.png"></img>' +
 					'</figure>'
@@ -478,7 +479,7 @@ describe( 'ImageEngine', () => {
 						'srcset=\'{ "data":"small.png 148w, big.png 1024w", "width":"1024" }\'>' +
 					'</image>' );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img alt="alt text" sizes="100vw" src="foo.png" srcset="small.png 148w, big.png 1024w" width="1024"></img>' +
 					'</figure>'
@@ -493,7 +494,7 @@ describe( 'ImageEngine', () => {
 					writer.removeAttribute( 'srcset', image );
 				} );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src="foo.png"></img>' +
 					'</figure>'
@@ -513,7 +514,7 @@ describe( 'ImageEngine', () => {
 					writer.removeAttribute( 'srcset', image );
 				} );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false">' +
 					'<img src="foo.png"></img>' +
 					'</figure>'
@@ -535,7 +536,7 @@ describe( 'ImageEngine', () => {
 					'</image>'
 				);
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img alt="alt text" src="foo.png"></img>' +
 					'</figure>'

+ 2 - 2
packages/ckeditor5-image/tests/image/ui/utils.js

@@ -56,7 +56,7 @@ describe( 'Utils', () => {
 			repositionContextualBalloon( editor );
 
 			sinon.assert.calledWithExactly( spy, {
-				target: editingView.domConverter.viewToDom( editingView.selection.getSelectedElement() ),
+				target: editingView.domConverter.viewToDom( editingView.document.selection.getSelectedElement() ),
 				positions: [
 					defaultPositions.northArrowSouth,
 					defaultPositions.northArrowSouthWest,
@@ -86,7 +86,7 @@ describe( 'Utils', () => {
 			const data = getBalloonPositionData( editor );
 
 			expect( data ).to.deep.equal( {
-				target: editingView.domConverter.viewToDom( editingView.selection.getSelectedElement() ),
+				target: editingView.domConverter.viewToDom( editingView.document.selection.getSelectedElement() ),
 				positions: [
 					defaultPositions.northArrowSouth,
 					defaultPositions.northArrowSouthWest,

+ 7 - 4
packages/ckeditor5-image/tests/image/utils.js

@@ -6,18 +6,21 @@
 import ViewElement from '@ckeditor/ckeditor5-engine/src/view/element';
 import ViewSelection from '@ckeditor/ckeditor5-engine/src/view/selection';
 import ViewDocumentFragment from '@ckeditor/ckeditor5-engine/src/view/documentfragment';
+import ViewWriter from '@ckeditor/ckeditor5-engine/src/view/writer';
+import ViewDocument from '@ckeditor/ckeditor5-engine/src/view/document';
 import ViewRange from '@ckeditor/ckeditor5-engine/src/view/range';
 import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
 import { toImageWidget, isImageWidget, isImageWidgetSelected, isImage } from '../../src/image/utils';
 import { isWidget, getLabel } from '@ckeditor/ckeditor5-widget/src/utils';
 
 describe( 'image widget utils', () => {
-	let element, image;
+	let element, image, writer;
 
 	beforeEach( () => {
+		writer = new ViewWriter( new ViewDocument() );
 		image = new ViewElement( 'img' );
 		element = new ViewElement( 'figure', null, image );
-		toImageWidget( element, 'image widget' );
+		toImageWidget( element, writer, 'image widget' );
 	} );
 
 	describe( 'toImageWidget()', () => {
@@ -30,12 +33,12 @@ describe( 'image widget utils', () => {
 		} );
 
 		it( 'should set element\'s label combined with alt attribute', () => {
-			image.setAttribute( 'alt', 'foo bar baz' );
+			writer.setAttribute( 'alt', 'foo bar baz', image );
 			expect( getLabel( element ) ).to.equal( 'foo bar baz image widget' );
 		} );
 
 		it( 'provided label creator should always return same label', () => {
-			image.setAttribute( 'alt', 'foo bar baz' );
+			writer.setAttribute( 'alt', 'foo bar baz', image );
 
 			expect( getLabel( element ) ).to.equal( 'foo bar baz image widget' );
 			expect( getLabel( element ) ).to.equal( 'foo bar baz image widget' );

+ 22 - 23
packages/ckeditor5-image/tests/imagecaption/imagecaptionengine.js

@@ -12,7 +12,6 @@ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 
 import ViewAttributeElement from '@ckeditor/ckeditor5-engine/src/view/attributeelement';
 import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
-import viewWriter from '@ckeditor/ckeditor5-engine/src/view/writer';
 import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
 import ModelRange from '@ckeditor/ckeditor5-engine/src/model/range';
 
@@ -22,7 +21,7 @@ import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils
 import { elementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/two-way-converters';
 
 describe( 'ImageCaptionEngine', () => {
-	let editor, model, doc, viewDocument;
+	let editor, model, doc, view;
 
 	beforeEach( () => {
 		return VirtualTestEditor
@@ -33,7 +32,7 @@ describe( 'ImageCaptionEngine', () => {
 				editor = newEditor;
 				model = editor.model;
 				doc = model.document;
-				viewDocument = editor.editing.view;
+				view = editor.editing.view;
 				model.schema.register( 'widget' );
 				model.schema.extend( 'widget', { allowIn: '$root' } );
 				model.schema.extend( 'caption', { allowIn: 'widget' } );
@@ -113,7 +112,7 @@ describe( 'ImageCaptionEngine', () => {
 			it( 'should convert caption element to figcaption contenteditable', () => {
 				setModelData( model, '<image src="img.png"><caption>Foo bar baz.</caption></image>' );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src="img.png"></img>' +
 						'<figcaption class="ck-editable" contenteditable="true" data-placeholder="Enter image caption">' +
@@ -126,7 +125,7 @@ describe( 'ImageCaptionEngine', () => {
 			it( 'should convert caption to element with proper CSS class if it\'s empty', () => {
 				setModelData( model, '<paragraph>foo</paragraph><image src="img.png"><caption></caption></image>' );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<p>foo</p>' +
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src="img.png"></img>' +
@@ -139,7 +138,7 @@ describe( 'ImageCaptionEngine', () => {
 
 			it( 'should not convert caption from other elements', () => {
 				setModelData( model, '<widget>foo bar<caption></caption></widget>' );
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '<widget>foo bar</widget>' );
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal( '<widget>foo bar</widget>' );
 			} );
 
 			it( 'should not convert when element is already consumed', () => {
@@ -153,14 +152,14 @@ describe( 'ImageCaptionEngine', () => {
 
 						const viewPosition = ViewPosition.createAt( imageFigure, 'end' );
 						conversionApi.mapper.bindElements( data.item, viewElement );
-						viewWriter.insert( viewPosition, viewElement );
+						conversionApi.writer.insert( viewPosition, viewElement );
 					},
 					{ priority: 'high' }
 				);
 
 				setModelData( model, '<image src="img.png"><caption>Foo bar baz.</caption></image>' );
 
-				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+				expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
 					'<figure class="ck-widget image" contenteditable="false"><img src="img.png"></img><span></span>Foo bar baz.</figure>'
 				);
 			} );
@@ -175,7 +174,7 @@ describe( 'ImageCaptionEngine', () => {
 					writer.insertText( 'foo bar', caption );
 				} );
 
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'<p>{}foo</p>' +
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src="img.png"></img>' +
@@ -196,7 +195,7 @@ describe( 'ImageCaptionEngine', () => {
 					writer.remove( ModelRange.createIn( caption ) );
 				} );
 
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'<p>{}foo</p>' +
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src="img.png"></img>' +
@@ -217,7 +216,7 @@ describe( 'ImageCaptionEngine', () => {
 					writer.remove( ModelRange.createFromParentsAndOffsets( caption, 0, caption, 8 ) );
 				} );
 
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'<p>{}foo</p>' +
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src="img.png"></img>' +
@@ -238,7 +237,7 @@ describe( 'ImageCaptionEngine', () => {
 				'[<image alt="" src=""><caption></caption></image>]<paragraph></paragraph>'
 			);
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget image" contenteditable="false">' +
 					'<img alt="" src=""></img>' +
 					'<figcaption class="ck-editable ck-placeholder" ' +
@@ -261,7 +260,7 @@ describe( 'ImageCaptionEngine', () => {
 				'[<image alt="" src=""><caption>foo bar</caption></image>]<paragraph></paragraph>'
 			);
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget image" contenteditable="false">' +
 					'<img alt="" src=""></img>' +
 					'<figcaption class="ck-editable" contenteditable="true" data-placeholder="Enter image caption">' +
@@ -289,7 +288,7 @@ describe( 'ImageCaptionEngine', () => {
 				'[<image alt="" src=""><caption></caption></image>]<paragraph></paragraph>'
 			);
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget image" contenteditable="false">' +
 					'<img alt="" src=""></img>' +
 					'<figcaption class="ck-editable ck-placeholder" ' +
@@ -318,7 +317,7 @@ describe( 'ImageCaptionEngine', () => {
 		it( 'image should have empty figcaption element when is selected', () => {
 			setModelData( model, '<paragraph>foo</paragraph>[<image src=""><caption></caption></image>]' );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'<p>foo</p>' +
 				'[<figure class="ck-widget image" contenteditable="false">' +
 					'<img src=""></img>' +
@@ -331,7 +330,7 @@ describe( 'ImageCaptionEngine', () => {
 		it( 'image should have empty figcaption element with hidden class when not selected', () => {
 			setModelData( model, '<paragraph>[]foo</paragraph><image src=""><caption></caption></image>' );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'<p>{}foo</p>' +
 				'<figure class="ck-widget image" contenteditable="false">' +
 					'<img src=""></img>' +
@@ -345,7 +344,7 @@ describe( 'ImageCaptionEngine', () => {
 		it( 'should not add additional figcaption if one is already present', () => {
 			setModelData( model, '<paragraph>foo</paragraph>[<image src=""><caption>foo bar</caption></image>]' );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'<p>foo</p>' +
 				'[<figure class="ck-widget image" contenteditable="false">' +
 					'<img src=""></img>' +
@@ -361,7 +360,7 @@ describe( 'ImageCaptionEngine', () => {
 				writer.setSelection( null );
 			} );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'<p>{}foo</p>' +
 				'<figure class="ck-widget image" contenteditable="false">' +
 					'<img src=""></img>' +
@@ -379,7 +378,7 @@ describe( 'ImageCaptionEngine', () => {
 				writer.remove( doc.selection.getFirstRange() );
 			} );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'<figure class="ck-widget image" contenteditable="false">' +
 					'<img src=""></img>' +
 					'<figcaption class="ck-editable ck-placeholder" contenteditable="true" data-placeholder="Enter image caption">' +
@@ -398,7 +397,7 @@ describe( 'ImageCaptionEngine', () => {
 				writer.setSelection( ModelRange.createOn( image ) );
 			} );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget image" contenteditable="false">' +
 					'<img src=""></img>' +
 					'<figcaption class="ck-editable ck-placeholder" ' +
@@ -415,7 +414,7 @@ describe( 'ImageCaptionEngine', () => {
 				writer.setSelection( ModelRange.createOn( image ) );
 			} );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'<figure class="ck-widget image" contenteditable="false">' +
 					'<img src=""></img>' +
 					'<figcaption class="ck-editable" contenteditable="true" data-placeholder="Enter image caption">foo bar</figcaption>' +
@@ -443,7 +442,7 @@ describe( 'ImageCaptionEngine', () => {
 				} );
 
 				// Check if there is no figcaption in the view.
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'<p>{}foo</p>' +
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src=""></img>' +
@@ -456,7 +455,7 @@ describe( 'ImageCaptionEngine', () => {
 				editor.execute( 'undo' );
 
 				// Check if figcaption is back with contents.
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'<p>foo</p>' +
 					'<figure class="ck-widget image" contenteditable="false">' +
 						'<img src=""></img>' +

+ 10 - 6
packages/ckeditor5-image/tests/imagecaption/utils.js

@@ -3,7 +3,7 @@
  * For licensing, see LICENSE.md.
  */
 
-import ViewDocument from '@ckeditor/ckeditor5-engine/src/view/document';
+import View from '@ckeditor/ckeditor5-engine/src/view/view';
 import ViewEditableElement from '@ckeditor/ckeditor5-engine/src/view/editableelement';
 import ViewElement from '@ckeditor/ckeditor5-engine/src/view/element';
 import {
@@ -15,12 +15,16 @@ import {
 import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
 
 describe( 'image captioning utils', () => {
-	let element, document;
+	let element, view, document;
 
 	beforeEach( () => {
-		document = new ViewDocument();
-		const creator = captionElementCreator( document, 'placeholder text' );
-		element = creator();
+		view = new View();
+		document = view.document;
+		const creator = captionElementCreator( view, 'placeholder text' );
+
+		view.change( writer => {
+			element = creator( writer );
+		} );
 	} );
 
 	describe( 'captionElementCreator', () => {
@@ -42,7 +46,7 @@ describe( 'image captioning utils', () => {
 
 		it( 'should return false for other elements', () => {
 			const editable = new ViewEditableElement( 'figcaption', { contenteditable: true } );
-			editable.document = document;
+			editable._document = document;
 
 			expect( isCaption( editable ) ).to.be.false;
 		} );

+ 5 - 5
packages/ckeditor5-image/tests/imagetextalternative.js

@@ -16,7 +16,7 @@ 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, model, view, doc, plugin, command, form, balloon, editorElement, button;
 
 	beforeEach( () => {
 		editorElement = global.document.createElement( 'div' );
@@ -29,7 +29,7 @@ describe( 'ImageTextAlternative', () => {
 			.then( newEditor => {
 				editor = newEditor;
 				model = editor.model;
-				editingView = editor.editing.view;
+				view = editor.editing.view;
 				doc = model.document;
 				newEditor.editing.view.attachDomRoot( editorElement );
 				plugin = editor.plugins.get( ImageTextAlternative );
@@ -166,7 +166,7 @@ describe( 'ImageTextAlternative', () => {
 
 				const spy = sinon.spy( balloon, 'updatePosition' );
 
-				editingView.fire( 'render' );
+				view.fire( 'render' );
 				sinon.assert.calledOnce( spy );
 			} );
 
@@ -174,7 +174,7 @@ describe( 'ImageTextAlternative', () => {
 				setData( model, '[<image src=""></image>]' );
 				button.fire( 'execute' );
 
-				const remveSpy = sinon.spy( balloon, 'remove' );
+				const removeSpy = sinon.spy( balloon, 'remove' );
 				const focusSpy = sinon.spy( editor.editing.view, 'focus' );
 
 				// EnqueueChange automatically fires #render event.
@@ -182,7 +182,7 @@ describe( 'ImageTextAlternative', () => {
 					writer.remove( doc.selection.getFirstRange() );
 				} );
 
-				sinon.assert.calledWithExactly( remveSpy, form );
+				sinon.assert.calledWithExactly( removeSpy, form );
 				sinon.assert.calledOnce( focusSpy );
 			} );
 		} );

+ 7 - 7
packages/ckeditor5-image/tests/imagetoolbar.js

@@ -112,7 +112,7 @@ describe( 'ImageToolbar', () => {
 		} );
 	} );
 
-	describe( 'integration with the editor selection (#render event)', () => {
+	describe( 'integration with the editor selection (#change event)', () => {
 		beforeEach( () => {
 			editor.ui.focusTracker.isFocused = true;
 		} );
@@ -122,7 +122,7 @@ describe( 'ImageToolbar', () => {
 
 			expect( balloon.visibleView ).to.be.null;
 
-			editingView.fire( 'render' );
+			editingView.change( () => {} );
 			expect( balloon.visibleView ).to.be.null;
 
 			model.change( writer => {
@@ -134,9 +134,9 @@ describe( 'ImageToolbar', () => {
 
 			expect( balloon.visibleView ).to.equal( toolbar );
 
-			// Make sure successive render does not throw, e.g. attempting
+			// Make sure successive change does not throw, e.g. attempting
 			// to insert the toolbar twice.
-			editingView.fire( 'render' );
+			editingView.change( () => {} );
 			expect( balloon.visibleView ).to.equal( toolbar );
 		} );
 
@@ -150,7 +150,7 @@ describe( 'ImageToolbar', () => {
 			balloon.add( { view: lastView } );
 			expect( balloon.visibleView ).to.equal( lastView );
 
-			editingView.fire( 'render' );
+			editingView.change( () => {} );
 			expect( balloon.visibleView ).to.equal( lastView );
 		} );
 
@@ -168,9 +168,9 @@ describe( 'ImageToolbar', () => {
 
 			expect( balloon.visibleView ).to.be.null;
 
-			// Make sure successive render does not throw, e.g. attempting
+			// Make sure successive change does not throw, e.g. attempting
 			// to remove the toolbar twice.
-			editingView.fire( 'render' );
+			editingView.change( () => {} );
 			expect( balloon.visibleView ).to.be.null;
 		} );
 	} );

+ 10 - 9
packages/ckeditor5-image/tests/imageupload/imageuploadediting.js

@@ -29,7 +29,7 @@ import Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';
 describe( 'ImageUploadEditing', () => {
 	// eslint-disable-next-line max-len
 	const base64Sample = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
-	let editor, model, doc, fileRepository, viewDocument, nativeReaderMock, loader, adapterMock;
+	let editor, model, view, doc, fileRepository, viewDocument, nativeReaderMock, loader, adapterMock;
 
 	testUtils.createSinonSandbox();
 
@@ -60,7 +60,8 @@ describe( 'ImageUploadEditing', () => {
 				editor = newEditor;
 				model = editor.model;
 				doc = model.document;
-				viewDocument = editor.editing.view;
+				view = editor.editing.view;
+				viewDocument = view.document;
 			} );
 	} );
 
@@ -139,7 +140,7 @@ describe( 'ImageUploadEditing', () => {
 
 	it( 'should not execute imageUpload command when file is not an image', () => {
 		const spy = sinon.spy( editor, 'execute' );
-		const viewDocument = editor.editing.view;
+		const viewDocument = editor.editing.view.document;
 		const fileMock = {
 			type: 'media/mp3',
 			size: 1024
@@ -203,7 +204,7 @@ describe( 'ImageUploadEditing', () => {
 
 		setModelData( model, '<image uploadId="1234"></image>' );
 
-		expect( getViewData( viewDocument ) ).to.equal(
+		expect( getViewData( view ) ).to.equal(
 			'[<figure class="ck-widget image" contenteditable="false">' +
 				'<img></img>' +
 			'</figure>]' );
@@ -215,7 +216,7 @@ describe( 'ImageUploadEditing', () => {
 		editor.execute( 'imageUpload', { file } );
 
 		model.once( '_change', () => {
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-widget image" contenteditable="false">' +
 				`<img src="${ base64Sample }"></img>` +
 				'</figure>]' +
@@ -236,7 +237,7 @@ describe( 'ImageUploadEditing', () => {
 
 		model.document.once( 'change', () => {
 			model.document.once( 'change', () => {
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'[<figure class="ck-widget image" contenteditable="false"><img src="image.png"></img></figure>]<p>foo bar</p>'
 				);
 				expect( loader.status ).to.equal( 'idle' );
@@ -291,7 +292,7 @@ describe( 'ImageUploadEditing', () => {
 	it( 'should do nothing if image does not have uploadId', () => {
 		setModelData( model, '<image src="image.png"></image>' );
 
-		expect( getViewData( viewDocument ) ).to.equal(
+		expect( getViewData( view ) ).to.equal(
 			'[<figure class="ck-widget image" contenteditable="false"><img src="image.png"></img></figure>]'
 		);
 	} );
@@ -408,7 +409,7 @@ describe( 'ImageUploadEditing', () => {
 
 		model.document.once( 'change', () => {
 			model.document.once( 'change', () => {
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'[<figure class="ck-widget image" contenteditable="false">' +
 						'<img sizes="100vw" src="image.png" srcset="image-500.png 500w, image-800.png 800w" width="800"></img>' +
 					'</figure>]<p>foo bar</p>'
@@ -427,7 +428,7 @@ describe( 'ImageUploadEditing', () => {
 	it( 'should prevent from browser redirecting when an image is dropped on another image', () => {
 		const spy = testUtils.sinon.spy();
 
-		editor.editing.view.fire( 'dragover', {
+		editor.editing.view.document.fire( 'dragover', {
 			preventDefault: spy
 		} );
 

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

@@ -25,7 +25,7 @@ describe( 'ImageUploadProgress', () => {
 
 	// eslint-disable-next-line max-len
 	const base64Sample = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
-	let editor, model, document, fileRepository, viewDocument, nativeReaderMock, loader, adapterMock;
+	let editor, model, document, fileRepository, view, nativeReaderMock, loader, adapterMock;
 
 	class UploadAdapterPluginMock extends Plugin {
 		init() {
@@ -56,7 +56,7 @@ describe( 'ImageUploadProgress', () => {
 				editor = newEditor;
 				model = editor.model;
 				document = model.document;
-				viewDocument = editor.editing.view;
+				view = editor.editing.view;
 
 				fileRepository = editor.plugins.get( FileRepository );
 				fileRepository.createUploadAdapter = newLoader => {
@@ -72,7 +72,7 @@ describe( 'ImageUploadProgress', () => {
 		setModelData( model, '<paragraph>[]foo</paragraph>' );
 		editor.execute( 'imageUpload', { file: createNativeFileMock() } );
 
-		expect( getViewData( viewDocument ) ).to.equal(
+		expect( getViewData( view ) ).to.equal(
 			'[<figure class="ck-appear ck-image-upload-placeholder ck-infinite-progress ck-widget image" contenteditable="false">' +
 				`<img src="data:image/svg+xml;utf8,${ imagePlaceholder }"></img>` +
 			'</figure>]<p>foo</p>'
@@ -84,7 +84,7 @@ describe( 'ImageUploadProgress', () => {
 		editor.execute( 'imageUpload', { file: createNativeFileMock() } );
 
 		model.document.once( 'change', () => {
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-appear ck-widget image" contenteditable="false">' +
 					`<img src="${ base64Sample }"></img>` +
 					'<div class="ck-progress-bar"></div>' +
@@ -104,7 +104,7 @@ describe( 'ImageUploadProgress', () => {
 		model.document.once( 'change', () => {
 			adapterMock.mockProgress( 40, 100 );
 
-			expect( getViewData( viewDocument ) ).to.equal(
+			expect( getViewData( view ) ).to.equal(
 				'[<figure class="ck-appear ck-widget image" contenteditable="false">' +
 				`<img src="${ base64Sample }"></img>` +
 				'<div class="ck-progress-bar" style="width:40%"></div>' +
@@ -123,7 +123,7 @@ describe( 'ImageUploadProgress', () => {
 
 		model.document.once( 'change', () => {
 			model.document.once( 'change', () => {
-				expect( getViewData( viewDocument ) ).to.equal(
+				expect( getViewData( view ) ).to.equal(
 					'[<figure class="ck-widget image" contenteditable="false">' +
 						'<img src="image.png"></img>' +
 					'</figure>]<p>foo</p>'
@@ -145,7 +145,7 @@ describe( 'ImageUploadProgress', () => {
 		setModelData( model, '<paragraph>[]foo</paragraph>' );
 		editor.execute( 'imageUpload', { file: createNativeFileMock() } );
 
-		expect( getViewData( viewDocument ) ).to.equal(
+		expect( getViewData( view ) ).to.equal(
 			'[<figure class="ck-appear ck-image-upload-placeholder ck-infinite-progress ck-widget image" contenteditable="false">' +
 				`<img src="${ base64Sample }"></img>` +
 			'</figure>]<p>foo</p>'
@@ -160,7 +160,7 @@ describe( 'ImageUploadProgress', () => {
 		setModelData( model, '<paragraph>[]foo</paragraph>' );
 		editor.execute( 'imageUpload', { file: createNativeFileMock() } );
 
-		expect( getViewData( viewDocument ) ).to.equal(
+		expect( getViewData( view ) ).to.equal(
 			'[<figure class="ck-widget image" contenteditable="false"><img></img></figure>]<p>foo</p>'
 		);
 	} );
@@ -174,7 +174,7 @@ describe( 'ImageUploadProgress', () => {
 			writer.setAttribute( 'uploadStatus', 'uploading', image );
 		} );
 
-		expect( getViewData( viewDocument ) ).to.equal(
+		expect( getViewData( view ) ).to.equal(
 			'[<figure class="ck-appear ck-image-upload-placeholder ck-infinite-progress ck-widget image" contenteditable="false">' +
 				`<img src="data:image/svg+xml;utf8,${ imagePlaceholder }"></img>` +
 			'</figure>]'
@@ -184,7 +184,7 @@ describe( 'ImageUploadProgress', () => {
 			writer.setAttribute( 'uploadStatus', 'complete', image );
 		} );
 
-		expect( getViewData( viewDocument ) ).to.equal(
+		expect( getViewData( view ) ).to.equal(
 			'[<figure class="ck-widget image" contenteditable="false">' +
 				`<img src="data:image/svg+xml;utf8,${ imagePlaceholder }"></img>` +
 			'</figure>]'

+ 1 - 1
packages/ckeditor5-image/tests/manual/image.md

@@ -1,6 +1,6 @@
 ## Image feature
 
-* Images with CKEditor logo should be loaded.
+* Images should be loaded.
 * Hovering over image should apply yellow outline.
 * Clicking on image should apply blue outline which should not change when hovering over.
 

+ 1 - 1
packages/ckeditor5-image/tests/manual/textalternative.md

@@ -5,6 +5,6 @@
   * balloon toolbar should hide,
   * image text alternative balloon panel should be visible
   * there should be `CKEditor logo` text selected inside textarea.
-* Change the text and press `Ok`. Check if text alternative is changed by opening balloon panel again.
+* Change the text and press `Save`. Check if text alternative is changed by opening balloon panel again.
 * Change the text and press `Cancel`. Check if text alternative is NOT changed by opening balloon panel again.