Kaynağa Gözat

Tests and docs and minor fixes.

Piotrek Koszuliński 9 yıl önce
ebeveyn
işleme
2d1adfe0bf

+ 3 - 0
packages/ckeditor5-engine/src/treemodel/delta/renamedelta.js

@@ -26,6 +26,7 @@ export default class RenameDelta extends Delta {
 }
 
 function apply( batch, delta, operation ) {
+	batch.addDelta( delta );
 	delta.addOperation( operation );
 	batch.doc.applyOperation( operation );
 }
@@ -56,4 +57,6 @@ register( 'rename', function( newName, element ) {
 		this, delta,
 		new RemoveOperation( Position.createBefore( element ), 1, this.doc.version )
 	);
+
+	return this;
 } );

+ 15 - 4
packages/ckeditor5-engine/src/treemodel/element.js

@@ -68,10 +68,6 @@ export default class Element extends Node {
 		return this._children.length;
 	}
 
-	isEmpty() {
-		return this.getChildCount() === 0;
-	}
-
 	/**
 	 * Gets index of the given child node.
 	 *
@@ -175,6 +171,21 @@ export default class Element extends Node {
 		this._attrs.clear();
 	}
 
+	/**
+	 * Checks whether element is empty (has no children).
+	 *
+	 * @returns {Boolean}
+	 */
+	isEmpty() {
+		return this.getChildCount() === 0;
+	}
+
+	/**
+	 * Gets the text content of the element. The return value is created by concatenating all
+	 * text nodes in this element and its descendants.
+	 *
+	 * @returns {String}
+	 */
 	getText() {
 		let text = '';
 

+ 16 - 2
packages/ckeditor5-engine/tests/treemodel/composer/composer.js

@@ -23,16 +23,30 @@ describe( 'Composer', () => {
 
 	describe( 'constructor', () => {
 		it( 'attaches deleteContents default listener', () => {
-			setData( document, 'main', '<p><selection>foo</selection>bar</p>' );
+			setData( document, 'main', '<p>f<selection>oo</p><p>ba</selection>r</p>' );
 
 			const batch = document.batch();
 
 			composer.fire( 'deleteContents', { batch, selection: document.selection } );
 
-			expect( getData( document, 'main' ) ).to.equal( '<p>bar</p>' );
+			expect( getData( document, 'main' ) ).to.equal( '<p>f</p><p>r</p>' );
 			expect( batch.deltas ).to.not.be.empty;
 		} );
 
+		it( 'attaches deleteContents default listener which passes options', () => {
+			setData( document, 'main', '<p>f<selection>oo</p><p>ba</selection>r</p>' );
+
+			const batch = document.batch();
+
+			composer.fire( 'deleteContents', {
+				batch,
+				selection: document.selection,
+				options: { merge: true }
+			} );
+
+			expect( getData( document, 'main' ) ).to.equal( '<p>fr</p>' );
+		} );
+
 		it( 'attaches modifySelection default listener', () => {
 			setData( document, 'main', '<p>foo<selection />bar</p>' );
 

+ 40 - 15
packages/ckeditor5-engine/tests/treemodel/composer/deletecontents.js

@@ -77,9 +77,10 @@ describe( 'Delete utils', () => {
 			);
 
 			test(
-				'deletes a bunch of nodes',
+				'does not break things when option.merge passed',
 				'w<selection>x<img></img>y</selection>z',
-				'w<selection />z'
+				'w<selection />z',
+				{ merge: true }
 			);
 		} );
 
@@ -122,77 +123,101 @@ describe( 'Delete utils', () => {
 			test(
 				'do not merge when no need to',
 				'<p>x</p><p><selection>foo</selection></p><p>y</p>',
-				'<p>x</p><p><selection /></p><p>y</p>'
+				'<p>x</p><p><selection /></p><p>y</p>',
+				{ merge: true }
+			);
+
+			test(
+				'merges second element into the first one (same name)',
+				'<p>x</p><p>fo<selection>o</p><p>b</selection>ar</p><p>y</p>',
+				'<p>x</p><p>fo<selection />ar</p><p>y</p>',
+				{ merge: true }
+			);
+
+			test(
+				'does not merge second element into the first one (same name, !option.merge)',
+				'<p>x</p><p>fo<selection>o</p><p>b</selection>ar</p><p>y</p>',
+				'<p>x</p><p>fo<selection /></p><p>ar</p><p>y</p>'
 			);
 
 			test(
 				'merges second element into the first one (same name)',
 				'<p>x</p><p>fo<selection>o</p><p>b</selection>ar</p><p>y</p>',
-				'<p>x</p><p>fo<selection />ar</p><p>y</p>'
+				'<p>x</p><p>fo<selection />ar</p><p>y</p>',
+				{ merge: true }
 			);
 
 			test(
 				'merges second element into the first one (different name)',
 				'<p>x</p><h1>fo<selection>o</h1><p>b</selection>ar</p><p>y</p>',
-				'<p>x</p><h1>fo<selection />ar</h1><p>y</p>'
+				'<p>x</p><h1>fo<selection />ar</h1><p>y</p>',
+				{ merge: true }
 			);
 
 			test(
 				'merges second element into the first one (different name, backward selection)',
 				'<p>x</p><h1>fo<selection backward>o</h1><p>b</selection>ar</p><p>y</p>',
-				'<p>x</p><h1>fo<selection />ar</h1><p>y</p>'
+				'<p>x</p><h1>fo<selection />ar</h1><p>y</p>',
+				{ merge: true }
 			);
 
 			test(
 				'merges second element into the first one (different attrs)',
 				'<p>x</p><p align="l">fo<selection>o</p><p>b</selection>ar</p><p>y</p>',
-				'<p>x</p><p align="l">fo<selection />ar</p><p>y</p>'
+				'<p>x</p><p align="l">fo<selection />ar</p><p>y</p>',
+				{ merge: true }
 			);
 
 			test(
 				'merges second element to an empty first element',
 				'<p>x</p><h1><selection></h1><p>fo</selection>o</p><p>y</p>',
-				'<p>x</p><h1><selection />o</h1><p>y</p>'
+				'<p>x</p><h1><selection />o</h1><p>y</p>',
+				{ merge: true }
 			);
 
 			test(
 				'merges elements when deep nested',
 				'<p>x<pchild>fo<selection>o</pchild></p><p><pchild>b</selection>ar</pchild>y</p>',
-				'<p>x<pchild>fo<selection />ar</pchild>y</p>'
+				'<p>x<pchild>fo<selection />ar</pchild>y</p>',
+				{ merge: true }
 			);
 
 			// If you disagree with this case please read the notes before this section.
 			test(
 				'merges elements when left end deep nested',
 				'<p>x<pchild>fo<selection>o</pchild></p><p>b</selection>ary</p>',
-				'<p>x<pchild>fo<selection /></pchild>ary</p>'
+				'<p>x<pchild>fo<selection /></pchild>ary</p>',
+				{ merge: true }
 			);
 
 			// If you disagree with this case please read the notes before this section.
 			test(
 				'merges elements when right end deep nested',
 				'<p>xfo<selection>o</p><p><pchild>b</selection>ar</pchild>y<img></img></p>',
-				'<p>xfo<selection /><pchild>ar</pchild>y<img></img></p>'
+				'<p>xfo<selection /><pchild>ar</pchild>y<img></img></p>',
+				{ merge: true }
 			);
 
 			test(
 				'merges elements when more content in the right branch',
 				'<p>xfo<selection>o</p><p>b</selection>a<pchild>r</pchild>y</p>',
-				'<p>xfo<selection />a<pchild>r</pchild>y</p>'
+				'<p>xfo<selection />a<pchild>r</pchild>y</p>',
+				{ merge: true }
 			);
 
 			test(
 				'leaves just one element when all selected',
 				'<h1><selection>x</h1><p>foo</p><p>y</selection></p>',
-				'<h1><selection /></h1>'
+				'<h1><selection /></h1>',
+				{ merge: true }
 			);
 		} );
 
-		function test( title, input, output ) {
+		function test( title, input, output, options ) {
 			it( title, () => {
 				setData( document, 'main', input );
 
-				deleteContents( document.batch(), document.selection );
+				deleteContents( document.batch(), document.selection, options );
 
 				expect( getData( document, 'main', { selection: true } ) ).to.equal( output );
 			} );

+ 94 - 0
packages/ckeditor5-engine/tests/treemodel/delta/renamedelta.js

@@ -0,0 +1,94 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: treemodel, delta */
+
+'use strict';
+
+import Document from '/ckeditor5/engine/treemodel/document.js';
+import Element from '/ckeditor5/engine/treemodel/element.js';
+
+import RenameDelta from '/ckeditor5/engine/treemodel/delta/renamedelta.js';
+
+describe( 'Batch', () => {
+	let doc, root, batch, chain;
+
+	beforeEach( () => {
+		doc = new Document();
+		root = doc.createRoot( 'root' );
+
+		const p = new Element( 'p', null, 'abc' );
+		root.appendChildren( p );
+
+		batch = doc.batch();
+
+		chain = batch.rename( 'h', p );
+	} );
+
+	describe( 'rename', () => {
+		it( 'should rename given element', () => {
+			expect( root.getChildCount() ).to.equal( 1 );
+			expect( root.getChild( 0 ) ).to.have.property( 'name', 'h' );
+			expect( root.getChild( 0 ).getText() ).to.equal( 'abc' );
+		} );
+
+		it( 'should be chainable', () => {
+			expect( chain ).to.equal( batch );
+		} );
+
+		it( 'should add delta to batch and operation to delta before applying operation', () => {
+			sinon.spy( doc, 'applyOperation' );
+			batch.rename( 'p', root.getChild( 0 ) );
+
+			const correctDeltaMatcher = sinon.match( operation => {
+				return operation.delta && operation.delta.batch && operation.delta.batch == batch;
+			} );
+
+			expect( doc.applyOperation.alwaysCalledWith( correctDeltaMatcher ) ).to.be.true;
+		} );
+	} );
+} );
+
+describe( 'RenameDelta', () => {
+	let renameDelta, doc, root;
+
+	beforeEach( () => {
+		doc = new Document();
+		root = doc.createRoot( 'root' );
+		renameDelta = new RenameDelta();
+	} );
+
+	describe( 'constructor', () => {
+		it( 'should create rename delta with no operations added', () => {
+			expect( renameDelta.operations.length ).to.equal( 0 );
+		} );
+	} );
+
+	describe( 'getReversed', () => {
+		it( 'should return instance of RenameDelta', () => {
+			let reversed = renameDelta.getReversed();
+
+			expect( reversed ).to.be.instanceof( RenameDelta );
+		} );
+
+		it( 'should return correct RenameDelta', () => {
+			root.appendChildren( new Element( 'p', null, 'abc' ) );
+
+			const batch = doc.batch();
+
+			batch.rename( 'h', root.getChild( 0 ) );
+
+			const reversed = batch.deltas[ 0 ].getReversed();
+
+			reversed.operations.forEach( operation => {
+				doc.applyOperation( operation );
+			} );
+
+			expect( root.getChildCount() ).to.equal( 1 );
+			expect( root.getChild( 0 ) ).to.have.property( 'name', 'p' );
+			expect( root.getChild( 0 ).getText() ).to.equal( 'abc' );
+		} );
+	} );
+} );

+ 20 - 0
packages/ckeditor5-engine/tests/treemodel/element.js

@@ -219,4 +219,24 @@ describe( 'Element', () => {
 			} );
 		} );
 	} );
+
+	describe( 'isEmpty', () => {
+		it( 'checks whether element has no children', () => {
+			expect( new Element( 'a' ).isEmpty() ).to.be.true;
+			expect( new Element( 'a', null, 'x' ).isEmpty() ).to.be.false;
+		} );
+	} );
+
+	describe( 'getText()', () => {
+		it( 'returns all text nodes', () => {
+			const el = new Element( 'p', null, [
+				new Element( 'p', null, 'abc' ),
+				'def',
+				new Element( 'p', null, 'ghi' ),
+				'jkl',
+			] );
+
+			expect( el.getText() ).to.equal( 'abcdefghijkl' );
+		} );
+	} );
 } );