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

Added view instance to writer. Fixed placeholder update listener.

Szymon Kupś 8 лет назад
Родитель
Сommit
8d6261ac40

+ 2 - 1
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -19,6 +19,7 @@ import ViewConversionDispatcher from '../conversion/viewconversiondispatcher';
 import { convertText, convertToModelFragment } from '../conversion/view-to-model-converters';
 import { convertText, convertToModelFragment } from '../conversion/view-to-model-converters';
 
 
 import ViewDocumentFragment from '../view/documentfragment';
 import ViewDocumentFragment from '../view/documentfragment';
+import ViewDocument from '../view/document';
 import ViewWriter from '../view/writer';
 import ViewWriter from '../view/writer';
 
 
 import ModelRange from '../model/range';
 import ModelRange from '../model/range';
@@ -158,7 +159,7 @@ export default class DataController {
 		const modelRange = ModelRange.createIn( modelElementOrFragment );
 		const modelRange = ModelRange.createIn( modelElementOrFragment );
 
 
 		const viewDocumentFragment = new ViewDocumentFragment();
 		const viewDocumentFragment = new ViewDocumentFragment();
-		const viewWriter = new ViewWriter();
+		const viewWriter = new ViewWriter( new ViewDocument() );
 		this.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );
 		this.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );
 
 
 		this.modelToView.convertInsert( modelRange, viewWriter );
 		this.modelToView.convertInsert( modelRange, viewWriter );

+ 2 - 1
packages/ckeditor5-engine/src/dev-utils/model.js

@@ -21,6 +21,7 @@ import ModelSelection from '../model/selection';
 import ModelDocumentFragment from '../model/documentfragment';
 import ModelDocumentFragment from '../model/documentfragment';
 
 
 import ViewWriter from '../view/writer';
 import ViewWriter from '../view/writer';
+import ViewDocument from '../view/document';
 import ViewConversionDispatcher from '../conversion/viewconversiondispatcher';
 import ViewConversionDispatcher from '../conversion/viewconversiondispatcher';
 import ViewSelection from '../view/selection';
 import ViewSelection from '../view/selection';
 import ViewDocumentFragment from '../view/documentfragment';
 import ViewDocumentFragment from '../view/documentfragment';
@@ -213,7 +214,7 @@ export function stringify( node, selectionOrPositionOrRange = null ) {
 	modelToView.on( 'selection', convertCollapsedSelection() );
 	modelToView.on( 'selection', convertCollapsedSelection() );
 
 
 	// Convert model to view.
 	// Convert model to view.
-	const writer = new ViewWriter();
+	const writer = new ViewWriter( new ViewDocument() );
 	modelToView.convertInsert( range, writer );
 	modelToView.convertInsert( range, writer );
 
 
 	// Convert model selection to view selection.
 	// Convert model selection to view selection.

+ 5 - 13
packages/ckeditor5-engine/src/view/placeholder.js

@@ -9,7 +9,6 @@
 
 
 import extend from '@ckeditor/ckeditor5-utils/src/lib/lodash/extend';
 import extend from '@ckeditor/ckeditor5-utils/src/lib/lodash/extend';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import '../../theme/placeholder.css';
 import '../../theme/placeholder.css';
 
 
 const listener = {};
 const listener = {};
@@ -27,17 +26,8 @@ const documentPlaceholders = new WeakMap();
  * @param {Function} [checkFunction] If provided it will be called before checking if placeholder should be displayed.
  * @param {Function} [checkFunction] If provided it will be called before checking if placeholder should be displayed.
  * If function returns `false` placeholder will not be showed.
  * If function returns `false` placeholder will not be showed.
  */
  */
-export function attachPlaceholder( element, placeholderText, checkFunction ) {
-	const document = element.document;
-
-	if ( !document ) {
-		/**
-		 * Provided element is not placed in any {@link module:engine/view/document~Document}.
-		 *
-		 * @error view-placeholder-element-is-detached
-		 */
-		throw new CKEditorError( 'view-placeholder-element-is-detached: Provided element is not placed in document.' );
-	}
+export function attachPlaceholder( view, element, placeholderText, checkFunction ) {
+	const document = view.document;
 
 
 	// Detach placeholder if was used before.
 	// Detach placeholder if was used before.
 	detachPlaceholder( element );
 	detachPlaceholder( element );
@@ -45,7 +35,9 @@ export function attachPlaceholder( element, placeholderText, checkFunction ) {
 	// Single listener per document.
 	// Single listener per document.
 	if ( !documentPlaceholders.has( document ) ) {
 	if ( !documentPlaceholders.has( document ) ) {
 		documentPlaceholders.set( document, new Map() );
 		documentPlaceholders.set( document, new Map() );
-		listener.listenTo( document, 'change', () => updateAllPlaceholders( document ) );
+
+		// Attach listener just before rendering and update placeholders.
+		listener.listenTo( view.renderer, 'render', () => updateAllPlaceholders( document ), { priority: 'highest' } );
 	}
 	}
 
 
 	// Store text in element's data attribute.
 	// Store text in element's data attribute.

+ 1 - 1
packages/ckeditor5-engine/src/view/renderer.js

@@ -110,7 +110,7 @@ export default class Renderer {
 		 */
 		 */
 		this._fakeSelectionContainer = null;
 		this._fakeSelectionContainer = null;
 
 
-		// TODO: document rend er event.
+		// TODO: document render event.
 		this.decorate( 'render' );
 		this.decorate( 'render' );
 	}
 	}
 
 

+ 1 - 1
packages/ckeditor5-engine/src/view/view.js

@@ -50,7 +50,7 @@ import { injectQuirksHandling } from './filler';
 export default class View {
 export default class View {
 	constructor() {
 	constructor() {
 		this.document = new Document();
 		this.document = new Document();
-		this._writer = new Writer();
+		this._writer = new Writer( this.document );
 
 
 		// TODO: check docs
 		// TODO: check docs
 		// TODO: move change event description to this file.
 		// TODO: move change event description to this file.

+ 6 - 2
packages/ckeditor5-engine/src/view/writer.js

@@ -26,6 +26,10 @@ import EditableElement from './editableelement';
  * of view writer associated with the document use {@link module:engine/view/view~View#change view.change()) method.
  * of view writer associated with the document use {@link module:engine/view/view~View#change view.change()) method.
  */
  */
 export default class Writer {
 export default class Writer {
+	constructor( document ) {
+		this.document = document;
+	}
+
 	/**
 	/**
 	 * Creates a new {@link module:engine/view/text~Text text node}.
 	 * Creates a new {@link module:engine/view/text~Text text node}.
 	 *
 	 *
@@ -102,9 +106,9 @@ export default class Writer {
 	 * @param {Object} [attributes] Elements attributes.
 	 * @param {Object} [attributes] Elements attributes.
 	 * @returns {module:engine/view/editableelement~EditableElement} Created element.
 	 * @returns {module:engine/view/editableelement~EditableElement} Created element.
 	 */
 	 */
-	createEditableElement( document, name, attributes ) {
+	createEditableElement( name, attributes ) {
 		const editableElement = new EditableElement( name, attributes );
 		const editableElement = new EditableElement( name, attributes );
-		editableElement.document = document;
+		editableElement.document = this.document;
 
 
 		return editableElement;
 		return editableElement;
 	}
 	}

+ 10 - 8
packages/ckeditor5-engine/tests/conversion/advanced-converters.js

@@ -15,7 +15,6 @@ import ViewElement from '../../src/view/element';
 import ViewContainerElement from '../../src/view/containerelement';
 import ViewContainerElement from '../../src/view/containerelement';
 import ViewAttributeElement from '../../src/view/attributeelement';
 import ViewAttributeElement from '../../src/view/attributeelement';
 import ViewText from '../../src/view/text';
 import ViewText from '../../src/view/text';
-import ViewWriter from '../../src/view/writer';
 import ViewPosition from '../../src/view/position';
 import ViewPosition from '../../src/view/position';
 import ViewRange from '../../src/view/range';
 import ViewRange from '../../src/view/range';
 
 
@@ -31,17 +30,17 @@ import {
 import { convertToModelFragment, convertText } from '../../src/conversion/view-to-model-converters';
 import { convertToModelFragment, convertText } from '../../src/conversion/view-to-model-converters';
 
 
 describe( 'advanced-converters', () => {
 describe( 'advanced-converters', () => {
-	let model, modelDoc, modelRoot, viewWriter, viewRoot, modelDispatcher, viewDispatcher;
+	let model, modelDoc, modelRoot, view, viewRoot, modelDispatcher, viewDispatcher;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
 		model = new Model();
 		model = new Model();
 		modelDoc = model.document;
 		modelDoc = model.document;
 		modelRoot = modelDoc.createRoot();
 		modelRoot = modelDoc.createRoot();
-		viewWriter = new ViewWriter();
 
 
 		const editing = new EditingController( model );
 		const editing = new EditingController( model );
 
 
-		viewRoot = editing.view.document.getRoot();
+		view = editing.view;
+		viewRoot = view.document.getRoot();
 
 
 		// Set name of view root the same as dom root.
 		// Set name of view root the same as dom root.
 		// This is a mock of attaching view root to dom root.
 		// This is a mock of attaching view root to dom root.
@@ -180,7 +179,7 @@ describe( 'advanced-converters', () => {
 				const viewElement = new ViewContainerElement( 'blockquote' );
 				const viewElement = new ViewContainerElement( 'blockquote' );
 
 
 				conversionApi.mapper.bindElements( data.item, viewElement );
 				conversionApi.mapper.bindElements( data.item, viewElement );
-				viewWriter.insert( viewPosition, viewElement );
+				conversionApi.writer.insert( viewPosition, viewElement );
 			}, { priority: 'high' } );
 			}, { priority: 'high' } );
 
 
 			modelDispatcher.on( 'attribute:linkHref:quote', linkHrefOnQuoteConverter, { priority: 'high' } );
 			modelDispatcher.on( 'attribute:linkHref:quote', linkHrefOnQuoteConverter, { priority: 'high' } );
@@ -197,7 +196,7 @@ describe( 'advanced-converters', () => {
 					// Attribute was removed -> remove the view link.
 					// Attribute was removed -> remove the view link.
 					const viewLink = viewQuote.getChild( viewQuote.childCount - 1 );
 					const viewLink = viewQuote.getChild( viewQuote.childCount - 1 );
 
 
-					viewWriter.remove( ViewRange.createOn( viewLink ) );
+					conversionApi.writer.remove( ViewRange.createOn( viewLink ) );
 
 
 					consumable.consume( data.item, 'attribute:linkTitle' );
 					consumable.consume( data.item, 'attribute:linkTitle' );
 				} else if ( data.attributeOldValue === null ) {
 				} else if ( data.attributeOldValue === null ) {
@@ -210,7 +209,7 @@ describe( 'advanced-converters', () => {
 						viewLink.setAttribute( 'title', data.item.getAttribute( 'linkTitle' ) );
 						viewLink.setAttribute( 'title', data.item.getAttribute( 'linkTitle' ) );
 					}
 					}
 
 
-					viewWriter.insert( new ViewPosition( viewQuote, viewQuote.childCount ), viewLink );
+					conversionApi.writer.insert( new ViewPosition( viewQuote, viewQuote.childCount ), viewLink );
 				} else {
 				} else {
 					// Attribute has changed -> change the existing view link.
 					// Attribute has changed -> change the existing view link.
 					const viewLink = viewQuote.getChild( viewQuote.childCount - 1 );
 					const viewLink = viewQuote.getChild( viewQuote.childCount - 1 );
@@ -513,7 +512,10 @@ describe( 'advanced-converters', () => {
 			] );
 			] );
 
 
 			modelRoot.appendChildren( modelElement );
 			modelRoot.appendChildren( modelElement );
-			modelDispatcher.convertInsert( ModelRange.createIn( modelRoot ), viewWriter );
+
+			view.change( writer => {
+				modelDispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+			} );
 
 
 			expect( viewToString( viewRoot ) ).to.equal(
 			expect( viewToString( viewRoot ) ).to.equal(
 				'<div>' +
 				'<div>' +

+ 5 - 4
packages/ckeditor5-engine/tests/manual/placeholder.js

@@ -20,13 +20,14 @@ ClassicEditor
 		toolbar: [ 'headings', 'undo', 'redo' ]
 		toolbar: [ 'headings', 'undo', 'redo' ]
 	} )
 	} )
 	.then( editor => {
 	.then( editor => {
-		const viewDoc = editor.editing.view;
+		const view = editor.editing.view;
+		const viewDoc = view.document;
 		const header = viewDoc.getRoot().getChild( 0 );
 		const header = viewDoc.getRoot().getChild( 0 );
 		const paragraph = viewDoc.getRoot().getChild( 1 );
 		const paragraph = viewDoc.getRoot().getChild( 1 );
 
 
-		attachPlaceholder( header, 'Type some header text...' );
-		attachPlaceholder( paragraph, 'Type some paragraph text...' );
-		viewDoc.render();
+		attachPlaceholder( view, header, 'Type some header text...' );
+		attachPlaceholder( view, paragraph, 'Type some paragraph text...' );
+		view.render();
 	} )
 	} )
 	.catch( err => {
 	.catch( err => {
 		console.error( err.stack );
 		console.error( err.stack );

+ 13 - 22
packages/ckeditor5-engine/tests/view/placeholder.js

@@ -5,7 +5,6 @@
 
 
 import { attachPlaceholder, detachPlaceholder } from '../../src/view/placeholder';
 import { attachPlaceholder, detachPlaceholder } from '../../src/view/placeholder';
 import createViewRoot from './_utils/createroot';
 import createViewRoot from './_utils/createroot';
-import ViewContainerElement from '../../src/view/containerelement';
 import View from '../../src/view/view';
 import View from '../../src/view/view';
 import ViewRange from '../../src/view/range';
 import ViewRange from '../../src/view/range';
 import { setData } from '../../src/dev-utils/view';
 import { setData } from '../../src/dev-utils/view';
@@ -21,19 +20,11 @@ describe( 'placeholder', () => {
 	} );
 	} );
 
 
 	describe( 'createPlaceholder', () => {
 	describe( 'createPlaceholder', () => {
-		it( 'should throw if element is not inside document', () => {
-			const element = new ViewContainerElement( 'div' );
-
-			expect( () => {
-				attachPlaceholder( element, 'foo bar baz' );
-			} ).to.throw( 'view-placeholder-element-is-detached' );
-		} );
-
 		it( 'should attach proper CSS class and data attribute', () => {
 		it( 'should attach proper CSS class and data attribute', () => {
 			setData( view, '<div></div><div>{another div}</div>' );
 			setData( view, '<div></div><div>{another div}</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
@@ -43,7 +34,7 @@ describe( 'placeholder', () => {
 			setData( view, '<div>first div</div><div>{another div}</div>' );
 			setData( view, '<div>first div</div><div>{another div}</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
@@ -53,7 +44,7 @@ describe( 'placeholder', () => {
 			setData( view, '<div><ui:span></ui:span><ui:span></ui:span></div><div>{another div}</div>' );
 			setData( view, '<div><ui:span></ui:span><ui:span></ui:span></div><div>{another div}</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
@@ -63,7 +54,7 @@ describe( 'placeholder', () => {
 			setData( view, '<div>[]</div><div>another div</div>' );
 			setData( view, '<div>[]</div><div>another div</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
@@ -74,7 +65,7 @@ describe( 'placeholder', () => {
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 			viewDocument.isFocused = false;
 			viewDocument.isFocused = false;
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
@@ -85,7 +76,7 @@ describe( 'placeholder', () => {
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 			const spy = sinon.spy( () => false );
 			const spy = sinon.spy( () => false );
 
 
-			attachPlaceholder( element, 'foo bar baz', spy );
+			attachPlaceholder( view, element, 'foo bar baz', spy );
 
 
 			sinon.assert.calledOnce( spy );
 			sinon.assert.calledOnce( spy );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
@@ -96,7 +87,7 @@ describe( 'placeholder', () => {
 			setData( view, '<div></div><div>{another div}</div>' );
 			setData( view, '<div></div><div>{another div}</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
@@ -112,8 +103,8 @@ describe( 'placeholder', () => {
 			setData( view, '<div></div><div>{another div}</div>' );
 			setData( view, '<div></div><div>{another div}</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
-			attachPlaceholder( element, 'new text' );
+			attachPlaceholder( view, element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'new text' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'new text' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'new text' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
@@ -123,7 +114,7 @@ describe( 'placeholder', () => {
 			setData( view, '<div></div><div>{another div}</div>' );
 			setData( view, '<div></div><div>{another div}</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 			setData( view, '<p>paragraph</p>' );
 			setData( view, '<p>paragraph</p>' );
 
 
 			view.render();
 			view.render();
@@ -140,8 +131,8 @@ describe( 'placeholder', () => {
 			setData( secondView, '<div></div><div>{another div}</div>' );
 			setData( secondView, '<div></div><div>{another div}</div>' );
 			const secondElement = secondRoot.getChild( 0 );
 			const secondElement = secondRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'first placeholder' );
-			attachPlaceholder( secondElement, 'second placeholder' );
+			attachPlaceholder( view, element, 'first placeholder' );
+			attachPlaceholder( secondView, secondElement, 'second placeholder' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'first placeholder' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'first placeholder' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
@@ -171,7 +162,7 @@ describe( 'placeholder', () => {
 			setData( view, '<div></div><div>{another div}</div>' );
 			setData( view, '<div></div><div>{another div}</div>' );
 			const element = viewRoot.getChild( 0 );
 			const element = viewRoot.getChild( 0 );
 
 
-			attachPlaceholder( element, 'foo bar baz' );
+			attachPlaceholder( view, element, 'foo bar baz' );
 
 
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
 			expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;

+ 24 - 9
packages/ckeditor5-engine/tests/view/renderer.js

@@ -21,16 +21,14 @@ import { INLINE_FILLER, INLINE_FILLER_LENGTH, isBlockFiller, BR_FILLER } from '.
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import createViewRoot from './_utils/createroot';
 import createViewRoot from './_utils/createroot';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
-import Writer from '../../src/view/writer';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 
 
 testUtils.createSinonSandbox();
 testUtils.createSinonSandbox();
 
 
 describe( 'Renderer', () => {
 describe( 'Renderer', () => {
-	let selection, domConverter, renderer, writer;
+	let selection, domConverter, renderer;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		writer = new Writer();
 		selection = new Selection();
 		selection = new Selection();
 		domConverter = new DomConverter();
 		domConverter = new DomConverter();
 		renderer = new Renderer( domConverter, selection );
 		renderer = new Renderer( domConverter, selection );
@@ -1902,7 +1900,10 @@ describe( 'Renderer', () => {
 			view.render();
 			view.render();
 
 
 			// Unwrap italic attribute element.
 			// Unwrap italic attribute element.
-			writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
+			view.change( writer => {
+				writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
+			} );
+
 			expect( getViewData( view ) ).to.equal( '<p>[<strong>foo</strong>]</p>' );
 			expect( getViewData( view ) ).to.equal( '<p>[<strong>foo</strong>]</p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
@@ -1925,7 +1926,10 @@ describe( 'Renderer', () => {
 			view.render();
 			view.render();
 
 
 			// Unwrap italic attribute element and change text inside.
 			// Unwrap italic attribute element and change text inside.
-			writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
+			view.change( writer => {
+				writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
+			} );
+
 			viewRoot.getChild( 0 ).getChild( 0 ).getChild( 0 ).data = 'bar';
 			viewRoot.getChild( 0 ).getChild( 0 ).getChild( 0 ).data = 'bar';
 			expect( getViewData( view ) ).to.equal( '<p>[<strong>bar</strong>]</p>' );
 			expect( getViewData( view ) ).to.equal( '<p>[<strong>bar</strong>]</p>' );
 
 
@@ -1948,7 +1952,11 @@ describe( 'Renderer', () => {
 			// Change text and insert new element into paragraph.
 			// Change text and insert new element into paragraph.
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			textNode.data = 'foobar';
 			textNode.data = 'foobar';
-			writer.insert( ViewPosition.createAfter( textNode ), new ViewAttributeElement( 'img' ) );
+
+			view.change( writer => {
+				writer.insert( ViewPosition.createAfter( textNode ), new ViewAttributeElement( 'img' ) );
+			} );
+
 			expect( getViewData( view ) ).to.equal( '<p>foobar<img></img></p>' );
 			expect( getViewData( view ) ).to.equal( '<p>foobar<img></img></p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
@@ -1970,7 +1978,11 @@ describe( 'Renderer', () => {
 			// Change text and insert new element into paragraph.
 			// Change text and insert new element into paragraph.
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			textNode.data = 'foobar';
 			textNode.data = 'foobar';
-			writer.insert( ViewPosition.createBefore( textNode ), new ViewAttributeElement( 'img' ) );
+
+			view.change( writer => {
+				writer.insert( ViewPosition.createBefore( textNode ), new ViewAttributeElement( 'img' ) );
+			} );
+
 			expect( getViewData( view ) ).to.equal( '<p><img></img>foobar</p>' );
 			expect( getViewData( view ) ).to.equal( '<p><img></img>foobar</p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
@@ -1997,8 +2009,11 @@ describe( 'Renderer', () => {
 			const container = viewRoot.getChild( 0 );
 			const container = viewRoot.getChild( 0 );
 			const firstElement = container.getChild( 0 );
 			const firstElement = container.getChild( 0 );
 
 
-			writer.remove( ViewRange.createOn( firstElement ) );
-			writer.insert( new ViewPosition( container, 2 ), firstElement );
+			view.change( writer => {
+				writer.remove( ViewRange.createOn( firstElement ) );
+				writer.insert( new ViewPosition( container, 2 ), firstElement );
+			} );
+
 			expect( getViewData( view ) ).to.equal( '<p><i></i><span></span><b></b></p>' );
 			expect( getViewData( view ) ).to.equal( '<p><i></i><span></span><b></b></p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/breakattributes.js

@@ -4,6 +4,7 @@
  */
  */
 
 
 import Writer from '../../../src/view/writer';
 import Writer from '../../../src/view/writer';
+import Document from '../../../src/view/document';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import ContainerElement from '../../../src/view/containerelement';
 import ContainerElement from '../../../src/view/containerelement';
 import AttributeElement from '../../../src/view/attributeelement';
 import AttributeElement from '../../../src/view/attributeelement';
@@ -18,7 +19,7 @@ describe( 'Writer', () => {
 		let writer;
 		let writer;
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		describe( 'break position', () => {
 		describe( 'break position', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/breakcontainer.js

@@ -8,6 +8,7 @@ import { stringify, parse } from '../../../src/dev-utils/view';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import ContainerElement from '../../../src/view/containerelement';
 import ContainerElement from '../../../src/view/containerelement';
 import Position from '../../../src/view/position';
 import Position from '../../../src/view/position';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'breakContainer()', () => {
 	describe( 'breakContainer()', () => {
@@ -26,7 +27,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'break inside element - should break container element at given position', () => {
 		it( 'break inside element - should break container element at given position', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/clear.js

@@ -11,6 +11,7 @@ import AttributeElement from '../../../src/view/attributeelement';
 import EmptyElement from '../../../src/view/emptyelement';
 import EmptyElement from '../../../src/view/emptyelement';
 import UIElement from '../../../src/view/uielement';
 import UIElement from '../../../src/view/uielement';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'clear()', () => {
 	describe( 'clear()', () => {
@@ -30,7 +31,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'should throw when range placed in two containers', () => {
 		it( 'should throw when range placed in two containers', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/insert.js

@@ -12,6 +12,7 @@ import Position from '../../../src/view/position';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import AttributeElement from '../../../src/view/attributeelement';
 import AttributeElement from '../../../src/view/attributeelement';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'insert()', () => {
 	describe( 'insert()', () => {
@@ -31,7 +32,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'should return collapsed range in insertion position when using empty array', () => {
 		it( 'should return collapsed range in insertion position when using empty array', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/mergeattributes.js

@@ -8,6 +8,7 @@ import ContainerElement from '../../../src/view/containerelement';
 import Text from '../../../src/view/text';
 import Text from '../../../src/view/text';
 import Position from '../../../src/view/position';
 import Position from '../../../src/view/position';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import { stringify, parse } from '../../../src/dev-utils/view';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'mergeAttributes', () => {
 	describe( 'mergeAttributes', () => {
@@ -25,7 +26,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'should not merge if inside text node', () => {
 		it( 'should not merge if inside text node', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/mergecontainers.js

@@ -6,6 +6,7 @@
 import Writer from '../../../src/view/writer';
 import Writer from '../../../src/view/writer';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'mergeContainers()', () => {
 	describe( 'mergeContainers()', () => {
@@ -24,7 +25,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'should merge two container elements - position between elements', () => {
 		it( 'should merge two container elements - position between elements', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/move.js

@@ -12,6 +12,7 @@ import UIElement from '../../../src/view/uielement';
 import Range from '../../../src/view/range';
 import Range from '../../../src/view/range';
 import Position from '../../../src/view/position';
 import Position from '../../../src/view/position';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'move()', () => {
 	describe( 'move()', () => {
@@ -34,7 +35,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'should move single text node', () => {
 		it( 'should move single text node', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/remove.js

@@ -12,6 +12,7 @@ import AttributeElement from '../../../src/view/attributeelement';
 import EmptyElement from '../../../src/view/emptyelement';
 import EmptyElement from '../../../src/view/emptyelement';
 import UIElement from '../../../src/view/uielement';
 import UIElement from '../../../src/view/uielement';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'remove()', () => {
 	describe( 'remove()', () => {
@@ -33,7 +34,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'should throw when range placed in two containers', () => {
 		it( 'should throw when range placed in two containers', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/rename.js

@@ -5,13 +5,14 @@
 
 
 import Writer from '../../../src/view/writer';
 import Writer from '../../../src/view/writer';
 import { parse } from '../../../src/dev-utils/view';
 import { parse } from '../../../src/dev-utils/view';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'rename()', () => {
 	describe( 'rename()', () => {
 		let root, foo, writer;
 		let root, foo, writer;
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		beforeEach( () => {
 		beforeEach( () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/unwrap.js

@@ -14,6 +14,7 @@ import Range from '../../../src/view/range';
 import Text from '../../../src/view/text';
 import Text from '../../../src/view/text';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import { stringify, parse } from '../../../src/dev-utils/view';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'unwrap()', () => {
 	describe( 'unwrap()', () => {
@@ -32,7 +33,7 @@ describe( 'Writer', () => {
 		}
 		}
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		it( 'should do nothing on collapsed ranges', () => {
 		it( 'should do nothing on collapsed ranges', () => {

+ 2 - 1
packages/ckeditor5-engine/tests/view/writer/wrap.js

@@ -17,13 +17,14 @@ import Text from '../../../src/view/text';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import { stringify, parse } from '../../../src/dev-utils/view';
 import createViewRoot from '../_utils/createroot';
 import createViewRoot from '../_utils/createroot';
+import Document from '../../../src/view/document';
 
 
 describe( 'Writer', () => {
 describe( 'Writer', () => {
 	describe( 'wrap()', () => {
 	describe( 'wrap()', () => {
 		let writer;
 		let writer;
 
 
 		before( () => {
 		before( () => {
-			writer = new Writer();
+			writer = new Writer( new Document() );
 		} );
 		} );
 
 
 		describe( 'non-collapsed range', () => {
 		describe( 'non-collapsed range', () => {