瀏覽代碼

More tests and API docs.

Piotrek Koszuliński 9 年之前
父節點
當前提交
28493a1916
共有 6 個文件被更改,包括 190 次插入20 次删除
  1. 3 3
      src/creator/creator.js
  2. 1 0
      src/editablecollection.js
  3. 22 12
      src/editor.js
  4. 24 0
      tests/creator/creator.js
  5. 92 1
      tests/editablecollection.js
  6. 48 4
      tests/editor/editor.js

+ 3 - 3
src/creator/creator.js

@@ -49,7 +49,7 @@ export default class Creator extends BaseCreator {
 	/**
 	 * Updates the {@link ckeditor5.Editor#element editor element}'s content with the data.
 	 *
-	 * @param [elementName]
+	 * @param [elementName] If not specified, the first element will be used.
 	 */
 	updateEditorElement( elementName ) {
 		if ( !elementName ) {
@@ -70,9 +70,9 @@ export default class Creator extends BaseCreator {
 	}
 
 	/**
-	 * Loads the data from the given or first {@link ckeditor5.Editor#element editor element} to the editable.
+	 * Loads the data from the given {@link ckeditor5.Editor#element editor element} to the editable.
 	 *
-	 * @param [elementName]
+	 * @param [elementName] If not specified, the first element will be used.
 	 */
 	loadDataFromEditorElement( elementName ) {
 		if ( !elementName ) {

+ 1 - 0
src/editablecollection.js

@@ -27,6 +27,7 @@ export default class EditableCollection extends Collection {
 		 * The currently focused editable.
 		 *
 		 * @observable
+		 * @readonly
 		 * @member {ckeditor5.Editable} ckeditor5.EditableCollection#current
 		 */
 		this.set( 'current', null );

+ 22 - 12
src/editor.js

@@ -243,9 +243,14 @@ export default class Editor {
 	}
 
 	/**
+	 * Sets the data in the specified editor editable root.
 	 *
+	 * @param {*} data The data to load.
+	 * @param {String} [editableRootName] The name of the editable root to which the data should be loaded.
+	 * If not specified and if there's only one editable root added to the editor, then the data will be loaded
+	 * to that editable.
 	 */
-	setData( data, rootEditableName ) {
+	setData( data, editableRootName ) {
 		if ( !this.data ) {
 			/**
 			 * Data controller has not been defined yet, so methds like {@link ckeditor5.Editor#setData} and
@@ -256,22 +261,22 @@ export default class Editor {
 			throw new CKEditorError( 'editor-no-datacontroller: Data controller has not been defined yet.' );
 		}
 
-		this.data.set( rootEditableName || this._getDefaultRootName(), data );
+		this.data.set( editableRootName || this._getDefaultRootName(), data );
 	}
 
 	/**
+	 * Gets the data from the specified editor editable root.
 	 *
+	 * @param {String} [editableRootName] The name of the editable root to get the data from.
+	 * If not specified and if there's only one editable root added to the editor, then the data will be retrieved
+	 * from it.
 	 */
-	getData( rootEditableName ) {
+	getData( editableRootName ) {
 		if ( !this.data ) {
 			throw new CKEditorError( 'editor-no-datacontroller: Data controller has not been defined yet.' );
 		}
 
-		if ( rootEditableName ) {
-			return this.data.get( rootEditableName );
-		}
-
-		return this.data.get( this._getDefaultRootName() );
+		return this.data.get( editableRootName || this._getDefaultRootName() );
 	}
 
 	/**
@@ -296,7 +301,7 @@ export default class Editor {
 	}
 
 	/**
-	 * Returns name of the root editable if there is only one. If there are multiple root editables, throws an error.
+	 * Returns name of the root editable if there is only one. If there are multiple or no root editables, throws an error.
 	 *
 	 * Note: The error message makes sense only for methods like {@link ckeditor5.Editor#setData} and
 	 * {@link ckeditor5.Editor#getData}.
@@ -312,13 +317,18 @@ export default class Editor {
 			 * The name of the root editable must be specified. There are multiple root editables added to the editor,
 			 * so the name of the editable must be specified.
 			 *
-			 * @error editor-root-editable-name-missing
+			 * @error editor-editable-root-name-missing
 			 */
-			throw new CKEditorError( 'editor-root-editable-name-missing: The name of the root editable must be specified.' );
+			throw new CKEditorError( 'editor-editable-root-name-missing: The name of the editable root must be specified.' );
 		}
 
 		if ( rootNames.length === 0 ) {
-			throw new CKEditorError( 'editor-no-root-editables: There are no root editables defined.' );
+			/**
+			 * The editor does not contain any editable roots, so the data cannot be set or read from it.
+			 *
+			 * @error editor-no-editable-roots
+			 */
+			throw new CKEditorError( 'editor-no-editable-roots: There are no editable roots defined.' );
 		}
 
 		return rootNames[ 0 ];

+ 24 - 0
tests/creator/creator.js

@@ -105,6 +105,18 @@ describe( 'Creator', () => {
 		} );
 	} );
 
+	describe( 'updateEditorElements', () => {
+		it( 'updates all editor elements', () => {
+			const spy = sinon.stub( creator, 'updateEditorElement' );
+
+			creator.updateEditorElements();
+
+			expect( spy.calledTwice ).to.be.true;
+			expect( spy.calledWith( 'first' ) ).to.be.true;
+			expect( spy.calledWith( 'second' ) ).to.be.true;
+		} );
+	} );
+
 	describe( 'loadDataFromEditorElement', () => {
 		it( 'should pass data to the first element', () => {
 			editor.setData = sinon.spy();
@@ -129,6 +141,18 @@ describe( 'Creator', () => {
 		} );
 	} );
 
+	describe( 'loadDataFromEditorElements', () => {
+		it( 'updates all editor elements', () => {
+			const spy = sinon.stub( creator, 'loadDataFromEditorElement' );
+
+			creator.loadDataFromEditorElements();
+
+			expect( spy.calledTwice ).to.be.true;
+			expect( spy.calledWith( 'first' ) ).to.be.true;
+			expect( spy.calledWith( 'second' ) ).to.be.true;
+		} );
+	} );
+
 	describe( 'getDataFromElement', () => {
 		[ 'textarea', 'template', 'div' ].forEach( ( elementName ) => {
 			it( 'should return the content of a ' + elementName, function() {

+ 92 - 1
tests/editablecollection.js

@@ -5,9 +5,100 @@
 
 'use strict';
 
+import Editor from '/ckeditor5/editor.js';
+import Editable from '/ckeditor5/editable.js';
+import EditableCollection from '/ckeditor5/editablecollection.js';
+
 describe( 'EditableCollection', () => {
+	let collection, editor;
+
+	beforeEach( () => {
+		collection = new EditableCollection();
+		editor = new Editor();
+	} );
+
 	describe( 'constructor', () => {
-		it( 'does something', () => {
+		it( 'configures collection to use idProperty=name', () => {
+			collection.add( new Editable( editor, 'foo' ) );
+
+			expect( collection.get( 'foo' ).name ).to.equal( 'foo' );
+		} );
+
+		it( 'sets observable property current', () => {
+			expect( collection ).to.have.property( 'current', null );
+
+			const spy = sinon.spy();
+			collection.on( 'change:current', spy );
+
+			collection.current = 1;
+
+			expect( spy.calledOnce ).to.be.true;
+		} );
+	} );
+
+	describe( 'add', () => {
+		it( 'binds collection.current to editable.isFocused changes', () => {
+			const editable = new Editable( editor, 'foo' );
+
+			collection.add( editable );
+
+			editable.isFocused = true;
+			expect( collection ).to.have.property( 'current', editable );
+
+			editable.isFocused = false;
+			expect( collection ).to.have.property( 'current', null );
+		} );
+	} );
+
+	describe( 'remove', () => {
+		it( 'stops watching editable.isFocused', () => {
+			const editable = new Editable( editor, 'foo' );
+
+			collection.add( editable );
+
+			editable.isFocused = true;
+
+			collection.remove( editable );
+
+			editable.isFocused = false;
+
+			expect( collection ).to.have.property( 'current', editable );
+		} );
+	} );
+
+	describe( 'destroy', () => {
+		let editables;
+
+		beforeEach( () => {
+			editables = [ new Editable( editor, 'foo' ), new Editable( editor, 'bar' ) ];
+
+			collection.add( editables[ 0 ] );
+			collection.add( editables[ 1 ] );
+		} );
+
+		it( 'stops watching all editables', () => {
+			collection.destroy();
+
+			editables[ 0 ].isFocused = true;
+			editables[ 1 ].isFocused = true;
+
+			expect( collection ).to.have.property( 'current', null );
+		} );
+
+		it( 'destroys all children', () => {
+			editables.forEach( editable => {
+				editable.destroy = sinon.spy();
+			} );
+
+			collection.destroy();
+
+			expect( editables.map( editable => editable.destroy.calledOnce ) ).to.deep.equal( [ true, true ] );
+		} );
+
+		it( 'removes all children', () => {
+			collection.destroy();
+
+			expect( collection ).to.have.lengthOf( 0 );
 		} );
 	} );
 } );

+ 48 - 4
tests/editor/editor.js

@@ -81,6 +81,34 @@ describe( 'Editor', () => {
 		} );
 	} );
 
+	describe( 'firstElement', () => {
+		it( 'should be set to first element', () => {
+			const editor = new Editor( { foo: 'a', bar: 'b' } );
+
+			expect( editor.firstElement ).to.equal( 'a' );
+		} );
+
+		it( 'should be set to null if there are no elements', () => {
+			const editor = new Editor();
+
+			expect( editor.firstElement ).to.be.null;
+		} );
+	} );
+
+	describe( 'firstElementName', () => {
+		it( 'should be set to first element name', () => {
+			const editor = new Editor( { foo: 'a', bar: 'b' } );
+
+			expect( editor.firstElementName ).to.equal( 'foo' );
+		} );
+
+		it( 'should be set to null if there are no elements', () => {
+			const editor = new Editor();
+
+			expect( editor.firstElementName ).to.be.null;
+		} );
+	} );
+
 	describe( 'init', () => {
 		it( 'should return a promise that resolves properly', () => {
 			const editor = new Editor( null, {
@@ -252,7 +280,7 @@ describe( 'Editor', () => {
 		it( 'should throw when no roots', () => {
 			expect( () => {
 				editor.setData( 'foo' );
-			} ).to.throw( CKEditorError, /^editor-no-root-editables:/ );
+			} ).to.throw( CKEditorError, /^editor-no-editable-roots:/ );
 		} );
 
 		it( 'should throw when more than one root and no root name given', () => {
@@ -261,7 +289,15 @@ describe( 'Editor', () => {
 
 			expect( () => {
 				editor.setData( 'foo' );
-			} ).to.throw( CKEditorError, /^editor-root-editable-name-missing:/ );
+			} ).to.throw( CKEditorError, /^editor-editable-root-name-missing:/ );
+		} );
+
+		it( 'should throw when no data controller', () => {
+			expect( () => {
+				editor.data = null;
+
+				editor.setData( 'foo' );
+			} ).to.throw( CKEditorError, /^editor-no-datacontroller:/ );
 		} );
 	} );
 
@@ -292,7 +328,7 @@ describe( 'Editor', () => {
 		it( 'should throw when no roots', () => {
 			expect( () => {
 				editor.getData();
-			} ).to.throw( CKEditorError, /^editor-no-root-editables:/ );
+			} ).to.throw( CKEditorError, /^editor-no-editable-roots:/ );
 		} );
 
 		it( 'should throw when more than one root and no root name given', () => {
@@ -301,7 +337,15 @@ describe( 'Editor', () => {
 
 			expect( () => {
 				editor.getData();
-			} ).to.throw( CKEditorError, /^editor-root-editable-name-missing:/ );
+			} ).to.throw( CKEditorError, /^editor-editable-root-name-missing:/ );
+		} );
+
+		it( 'should throw when no data controller', () => {
+			expect( () => {
+				editor.data = null;
+
+				editor.getData();
+			} ).to.throw( CKEditorError, /^editor-no-datacontroller:/ );
 		} );
 	} );
 } );