浏览代码

Merge pull request #6 from ckeditor/t/3

Internal: Improved a mechanism that handles the selection after inserting a horizontal rule. Closes #3.
Maciej 6 年之前
父节点
当前提交
cb6c149adb

+ 2 - 0
packages/ckeditor5-horizontal-line/package.json

@@ -16,10 +16,12 @@
   },
   "devDependencies": {
     "@ckeditor/ckeditor5-cloud-services": "^11.0.5",
+    "@ckeditor/ckeditor5-engine": "^14.0.0",
     "@ckeditor/ckeditor5-editor-classic": "^12.1.3",
     "@ckeditor/ckeditor5-easy-image": "^11.0.5",
     "@ckeditor/ckeditor5-image": "^14.0.0",
     "@ckeditor/ckeditor5-paragraph": "^11.0.5",
+    "@ckeditor/ckeditor5-utils": "^14.0.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",

+ 19 - 2
packages/ckeditor5-horizontal-line/src/horizontalrulecommand.js

@@ -38,9 +38,26 @@ export default class HorizontalRuleCommand extends Command {
 		const model = this.editor.model;
 
 		model.change( writer => {
-			const modelElement = writer.createElement( 'horizontalRule' );
+			const horizontalElement = writer.createElement( 'horizontalRule' );
 
-			model.insertContent( modelElement );
+			model.insertContent( horizontalElement );
+
+			let nextElement = horizontalElement.nextSibling;
+
+			// Check whether an element next to the inserted horizontal rule is defined and can contain a text.
+			const canSetSelection = nextElement && model.schema.checkChild( nextElement, '$text' );
+
+			// If the element is missing, but a paragraph could be inserted next to the horizontal rule, let's add it.
+			if ( !canSetSelection && model.schema.checkChild( horizontalElement.parent, 'paragraph' ) ) {
+				nextElement = writer.createElement( 'paragraph' );
+
+				writer.insert( nextElement, writer.createPositionAfter( horizontalElement ) );
+			}
+
+			// Put the selection inside the element, at the beginning.
+			if ( nextElement ) {
+				writer.setSelection( nextElement, 0 );
+			}
 		} );
 	}
 }

+ 128 - 3
packages/ckeditor5-horizontal-line/tests/horizontalrulecommand.js

@@ -111,6 +111,14 @@ describe( 'HorizontalRuleCommand', () => {
 	} );
 
 	describe( 'execute()', () => {
+		beforeEach( () => {
+			model.schema.register( 'heading1', { inheritAllFrom: '$block' } );
+			editor.conversion.elementToElement( { model: 'heading1', view: 'h1' } );
+
+			model.schema.register( 'media', { allowWhere: '$block' } );
+			editor.conversion.elementToElement( { model: 'media', view: 'div' } );
+		} );
+
 		it( 'should create a single batch', () => {
 			setModelData( model, '<paragraph>foo[]</paragraph>' );
 
@@ -123,7 +131,14 @@ describe( 'HorizontalRuleCommand', () => {
 			sinon.assert.calledOnce( spy );
 		} );
 
-		it( 'should insert a horizontal rule in an empty root and select it', () => {
+		it( 'should insert a horizontal rule in an empty root and select it (a paragraph cannot be inserted)', () => {
+			// Block a paragraph in $root.
+			model.schema.addChildCheck( ( context, childDefinition ) => {
+				if ( childDefinition.name === 'paragraph' && context.last.name === '$root' ) {
+					return false;
+				}
+			} );
+
 			setModelData( model, '[]' );
 
 			command.execute();
@@ -137,7 +152,7 @@ describe( 'HorizontalRuleCommand', () => {
 			command.execute();
 
 			expect( getModelData( model ) ).to.equal(
-				'<paragraph>f</paragraph>[<horizontalRule></horizontalRule>]<paragraph>o</paragraph>'
+				'<paragraph>f</paragraph><horizontalRule></horizontalRule><paragraph>[]o</paragraph>'
 			);
 		} );
 
@@ -147,7 +162,117 @@ describe( 'HorizontalRuleCommand', () => {
 			command.execute();
 
 			expect( getModelData( model ) ).to.equal(
-				'<paragraph>fo</paragraph>[<horizontalRule></horizontalRule>]<paragraph>o</paragraph>'
+				'<paragraph>fo</paragraph><horizontalRule></horizontalRule><paragraph>[]o</paragraph>'
+			);
+		} );
+
+		it( 'should create an empty paragraph after inserting a horizontal rule after a paragraph and place selection inside', () => {
+			setModelData( model, '<paragraph>foo[]</paragraph>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<paragraph>foo</paragraph><horizontalRule></horizontalRule><paragraph>[]</paragraph>'
+			);
+		} );
+
+		it( 'should create an empty paragraph after inserting a horizontal rule after a heading and place selection inside', () => {
+			setModelData( model, '<heading1>foo[]</heading1>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<heading1>foo</heading1><horizontalRule></horizontalRule><paragraph>[]</paragraph>'
+			);
+		} );
+
+		it( 'should create an empty paragraph after inserting a horizontal rule and next element must not having text', () => {
+			setModelData( model, '<paragraph>foo[]</paragraph><media></media>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<paragraph>foo</paragraph><horizontalRule></horizontalRule><paragraph>[]</paragraph><media></media>'
+			);
+		} );
+
+		it( 'should create an empty paragraph after inserting a horizontal rule in heading and next element must not having text', () => {
+			setModelData( model, '<heading1>foo[]</heading1><media></media>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<heading1>foo</heading1><horizontalRule></horizontalRule><paragraph>[]</paragraph><media></media>'
+			);
+		} );
+
+		it( 'should not create an empty paragraph if a horizontal rule split an element with text', () => {
+			setModelData( model, '<heading1>foo[]bar</heading1>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<heading1>foo</heading1><horizontalRule></horizontalRule><heading1>[]bar</heading1>'
+			);
+		} );
+
+		it( 'should replace an empty paragraph with a horizontal rule and insert another paragraph next to', () => {
+			setModelData( model, '<paragraph>[]</paragraph>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<horizontalRule></horizontalRule><paragraph>[]</paragraph>'
+			);
+		} );
+
+		it( 'should replace an empty paragraph with a horizontal rule and move the selection to next paragraph', () => {
+			setModelData( model, '<paragraph>foo</paragraph><paragraph>[]</paragraph><paragraph>bar</paragraph>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<paragraph>foo</paragraph><horizontalRule></horizontalRule><paragraph>[]bar</paragraph>'
+			);
+		} );
+
+		it( 'should replace an empty paragraph with a horizontal rule and move the selection to next element that has text', () => {
+			setModelData( model, '<paragraph>foo</paragraph><paragraph>[]</paragraph><heading1>bar</heading1>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<paragraph>foo</paragraph><horizontalRule></horizontalRule><heading1>[]bar</heading1>'
+			);
+		} );
+
+		it( 'should replace an empty block element with a horizontal rule and insert a paragraph next to', () => {
+			setModelData( model, '<heading1>[]</heading1>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<horizontalRule></horizontalRule><paragraph>[]</paragraph>'
+			);
+		} );
+
+		it( 'should move the selection to next element if it allows having text (paragraph + heading)', () => {
+			setModelData( model, '<paragraph>foo[]</paragraph><heading1>bar</heading1>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<paragraph>foo</paragraph><horizontalRule></horizontalRule><heading1>[]bar</heading1>'
+			);
+		} );
+
+		it( 'should move the selection to next element if it allows having text (heading + paragraph)', () => {
+			setModelData( model, '<heading1>foo[]</heading1><paragraph>bar</paragraph>' );
+
+			command.execute();
+
+			expect( getModelData( model ) ).to.equal(
+				'<heading1>foo</heading1><horizontalRule></horizontalRule><paragraph>[]bar</paragraph>'
 			);
 		} );
 	} );