Parcourir la source

Make DataController's initData() and setData() methods consistent.

Krzysztof Krztoń il y a 7 ans
Parent
commit
3dea7c9c7b

+ 36 - 12
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -24,6 +24,7 @@ import ViewDocument from '../view/document';
 import ViewDowncastWriter from '../view/downcastwriter';
 
 import ModelRange from '../model/range';
+import log from "../../../ckeditor5-utils/src/log";
 
 /**
  * Controller for the data pipeline. The data pipeline controls how data is retrieved from the document
@@ -184,10 +185,9 @@ export default class DataController {
 	 * @fires init
 	 * @param {String|Object.<String,String>} data Input data as a string or an object containing rootName - initialData pairs to
 	 * initialize data on multiple roots at once.
-	 * @param {String} [rootName='main'] Root name. Takes effect only if the first argument is provided as a string.
 	 * @returns {Promise} Promise that is resolved after the data is set on the editor.
 	 */
-	init( data, rootName = 'main' ) {
+	init( data ) {
 		if ( this.model.document.version ) {
 			/**
 			 * Cannot set initial data to not empty {@link module:engine/model/document~Document}.
@@ -201,7 +201,7 @@ export default class DataController {
 
 		let initialData = {};
 		if ( typeof data === 'string' ) {
-			initialData[ rootName ] = data;
+			initialData.main = data; // Default root is 'main'. To initiate data on a different root, object should be passed.
 		} else {
 			initialData = data;
 		}
@@ -225,19 +225,43 @@ export default class DataController {
 	 * This method also creates a batch with all the changes applied. If all you need is to parse data, use
 	 * the {@link #parse} method.
 	 *
-	 * @param {String} data Input data.
-	 * @param {String} [rootName='main'] Root name.
+	 * @param {String|Object.<String,String>} data Input data as a string or an object containing rootName - initialData pairs to
+	 * set data on multiple roots at once.
 	 */
-	set( data, rootName = 'main' ) {
-		// Save to model.
-		const modelRoot = this.model.document.getRoot( rootName );
+	set( data ) {
+		let initialData = {};
+		if ( typeof data === 'string' ) {
+			initialData.main = data; // Default root is 'main'. To set data on a different root, object should be passed.
+		} else {
+			initialData = data;
+		}
+
+		const rootNames = this.model.document.getRootNames();
+
+		// Check if all roots exists. Thrown an error if there is non-existing one.
+		for ( const rootName of Object.keys( initialData ) ) {
+			if ( !rootNames.includes( rootName ) ) {
+				/**
+				 * Thrown when there is an attempt to set data on a non-existing root.
+				 *
+				 * @error trying-to-set-data-on-non-existing-root
+				 */
+				throw new CKEditorError( 'trying-to-set-data-on-non-existing-root: ' +
+					`Attempting to set data on non-existing "${ rootName }" root.` );
+			}
+		}
 
 		this.model.enqueueChange( 'transparent', writer => {
-			writer.setSelection( null );
-			writer.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );
+			for ( const rootName of Object.keys( initialData ) ) {
+				// Save to model.
+				const modelRoot = this.model.document.getRoot( rootName );
 
-			writer.remove( writer.createRangeIn( modelRoot ) );
-			writer.insert( this.parse( data, modelRoot ), modelRoot, 0 );
+				writer.setSelection( null );
+				writer.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );
+
+				writer.remove( writer.createRangeIn( modelRoot ) );
+				writer.insert( this.parse( initialData[ rootName ], modelRoot ), modelRoot, 0 );
+			}
 		} );
 	}
 

+ 29 - 6
packages/ckeditor5-engine/tests/controller/datacontroller.js

@@ -188,7 +188,7 @@ describe( 'DataController', () => {
 
 		it( 'should get root name as a parameter', () => {
 			schema.extend( '$text', { allowIn: '$root' } );
-			data.init( 'foo', 'title' );
+			data.init( { title: 'foo' } );
 
 			expect( getData( model, { withoutSelection: true, rootName: 'title' } ) ).to.equal( 'foo' );
 		} );
@@ -248,8 +248,8 @@ describe( 'DataController', () => {
 
 		it( 'should get root name as a parameter', () => {
 			schema.extend( '$text', { allowIn: '$root' } );
-			data.set( 'foo', 'main' );
-			data.set( 'Bar', 'title' );
+			data.set( 'foo' );
+			data.set( { title: 'Bar' } );
 
 			expect( getData( model, { withoutSelection: true, rootName: 'main' } ) ).to.equal( 'foo' );
 			expect( getData( model, { withoutSelection: true, rootName: 'title' } ) ).to.equal( 'Bar' );
@@ -260,7 +260,7 @@ describe( 'DataController', () => {
 		it( 'should parse given data before set in a context of correct root', () => {
 			schema.extend( '$text', { allowIn: '$title', disallowIn: '$root' } );
 			data.set( 'foo', 'main' );
-			data.set( 'Bar', 'title' );
+			data.set( { title: 'Bar' } );
 
 			expect( getData( model, { withoutSelection: true, rootName: 'main' } ) ).to.equal( '' );
 			expect( getData( model, { withoutSelection: true, rootName: 'title' } ) ).to.equal( 'Bar' );
@@ -273,14 +273,37 @@ describe( 'DataController', () => {
 		it( 'should allow setting empty data', () => {
 			schema.extend( '$text', { allowIn: '$root' } );
 
-			data.set( 'foo', 'title' );
+			data.set( { title: 'foo' } );
 
 			expect( getData( model, { withoutSelection: true, rootName: 'title' } ) ).to.equal( 'foo' );
 
-			data.set( '', 'title' );
+			data.set( { title: '' } );
 
 			expect( getData( model, { withoutSelection: true, rootName: 'title' } ) ).to.equal( '' );
 		} );
+
+		it( 'should throw an error when non-existent root is used (single)', () => {
+			expect( () => {
+				data.set( { nonexistent: '<p>Bar</p>' } );
+			} ).to.throw(
+				CKEditorError,
+				'trying-to-set-data-on-non-existing-root: Attempting to set data on non-existing "nonexistent" root.'
+			);
+		} );
+
+		it( 'should throw an error when non-existent root is used (one of many) without touching any roots data', () => {
+			schema.extend( '$text', { allowIn: '$root' } );
+			data.set( 'foo' );
+
+			expect( () => {
+				data.set( { main: 'bar', nonexistent: '<p>Bar</p>' } );
+			} ).to.throw(
+				CKEditorError,
+				'trying-to-set-data-on-non-existing-root: Attempting to set data on non-existing "nonexistent" root.'
+			);
+
+			expect( getData( model, { withoutSelection: true } ) ).to.equal( 'foo' );
+		} );
 	} );
 
 	describe( 'get()', () => {