Browse Source

Introduced DataController#init method.

Oskar Wróbel 7 years ago
parent
commit
63ec35e4f3

+ 28 - 6
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -9,6 +9,7 @@
 
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 import Mapper from '../conversion/mapper';
 
@@ -100,7 +101,7 @@ export default class DataController {
 		this.upcastDispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } );
 		this.upcastDispatcher.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } );
 
-		this.decorate( 'set' );
+		this.decorate( 'init' );
 	}
 
 	/**
@@ -172,17 +173,38 @@ export default class DataController {
 	}
 
 	/**
+	 * Sets initial input data parsed by the {@link #processor data processor} and
+	 * converted by the {@link #upcastDispatcher view-to-model converters}.
+	 * Initial data can be set only to document that {@link module:engine/model/document~Document#version} is equal 0.
+	 *
+	 * **Note** This method is {@link module:utils/observablemixin~ObservableMixin#decorate decorated} which is
+	 * used by e.g. collaborative editing plugin that syncs remote data on init.
+	 *
+	 * @fires set
+	 * @param {String} data Input data.
+	 * @param {String} [rootName='main'] Root name.
+	 */
+	init( data, rootName = 'main' ) {
+		if ( this.model.document.version ) {
+			throw new CKEditorError( 'datacontroller-init-document-data-initialized: Trying to set initial data to initialized document.' );
+		}
+
+		const modelRoot = this.model.document.getRoot( rootName );
+
+		this.model.enqueueChange( 'transparent', writer => {
+			writer.insert( this.parse( data, modelRoot ), modelRoot );
+		} );
+	}
+
+	/**
 	 * Sets input data parsed by the {@link #processor data processor} and
 	 * converted by the {@link #upcastDispatcher view-to-model converters}.
+	 * This method can be used any time to replace existing editor data by the new one without clearing the
+	 * {@link module:engine/model/document~Document#history document history}.
 	 *
 	 * This method also creates a batch with all the changes applied. If all you need is to parse data, use
 	 * the {@link #parse} method.
 	 *
-	 * **Note** This method is {@link module:utils/observablemixin~ObservableMixin#decorate decorated} which is
-	 * used by some plugins to change the behavior of this method. For example, the collaborative editing plugin changes
-	 * this method’s nature to asynchronous by returning a promise.
-	 *
-	 * @fires set
 	 * @param {String} data Input data.
 	 * @param {String} [rootName='main'] Root name.
 	 */

+ 49 - 3
packages/ckeditor5-engine/tests/controller/datacontroller.js

@@ -7,6 +7,7 @@ import Model from '../../src/model/model';
 import Range from '../../src/model/range';
 import DataController from '../../src/controller/datacontroller';
 import HtmlDataProcessor from '../../src/dataprocessor/htmldataprocessor';
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 import ModelDocumentFragment from '../../src/model/documentfragment';
 import ViewDocumentFragment from '../../src/view/documentfragment';
@@ -152,17 +153,62 @@ describe( 'DataController', () => {
 		} );
 	} );
 
-	describe( 'set()', () => {
+	describe( 'init()', () => {
 		it( 'should be decorated', () => {
 			const spy = sinon.spy();
 
-			data.on( 'set', spy );
+			data.on( 'init', spy );
 
-			data.set( 'foo bar' );
+			data.init( 'foo bar' );
 
 			sinon.assert.calledWithExactly( spy, sinon.match.any, [ 'foo bar' ] );
 		} );
 
+		it( 'should throw an error when document data is already initialized', () => {
+			data.init( '<p>Foo</p>' );
+
+			expect( () => {
+				data.init( '<p>Bar</p>' );
+			} ).to.throw(
+				CKEditorError,
+				'datacontroller-init-document-data-initialized: Trying to set initial data to initialized document.'
+			);
+		} );
+
+		it( 'should set data to default main root', () => {
+			schema.extend( '$text', { allowIn: '$root' } );
+			data.init( 'foo' );
+
+			expect( getData( model, { withoutSelection: true } ) ).to.equal( 'foo' );
+		} );
+
+		it( 'should get root name as a parameter', () => {
+			schema.extend( '$text', { allowIn: '$root' } );
+			data.init( 'foo', 'title' );
+
+			expect( getData( model, { withoutSelection: true, rootName: 'title' } ) ).to.equal( 'foo' );
+		} );
+
+		it( 'should create a batch', () => {
+			schema.extend( '$text', { allowIn: '$root' } );
+			data.init( 'foo' );
+
+			expect( count( modelDocument.history.getDeltas() ) ).to.equal( 1 );
+		} );
+
+		it( 'should cause firing change event', () => {
+			const spy = sinon.spy();
+
+			schema.extend( '$text', { allowIn: '$root' } );
+			model.document.on( 'change', spy );
+
+			data.init( 'foo' );
+
+			expect( spy.calledOnce ).to.be.true;
+		} );
+	} );
+
+	describe( 'set()', () => {
 		it( 'should set data to default main root', () => {
 			schema.extend( '$text', { allowIn: '$root' } );
 			data.set( 'foo' );