Ver código fonte

Changed: EnterCommand remove defaultBlockName and fire afterExecute event.

Szymon Cofalik 9 anos atrás
pai
commit
e44395e409

+ 30 - 68
packages/ckeditor5-enter/src/entercommand.js

@@ -4,22 +4,29 @@
  */
 
 import Command from '../core/command/command.js';
-import Element from '../engine/model/element.js';
-import LivePosition from '../engine/model/liveposition.js';
-import Position from '../engine/model/position.js';
 
 /**
- * The Enter command. It is used by the {@link enter.Enter Enter feature} to handle the <kbd>Enter</kbd> key.
+ * Enter command. It is used by the {@link enter.Enter Enter feature} to handle the <kbd>Enter</kbd> key.
  *
  * @member enter
  * @extends core.command.Command
  */
 export default class EnterCommand extends Command {
+	/**
+	 * Executes command.
+	 *
+	 * @protected
+	 * @returns {Object} data Data object, available in {@link core.Command#event:afterExecute}
+	 * @returns {engine.model.Batch} data.batch Batch created and used by the command.
+	 */
 	_doExecute() {
 		const doc = this.editor.document;
+		const batch = doc.batch();
 
 		doc.enqueueChanges( () => {
-			enterBlock( doc.batch(), doc.selection, { defaultBlockName: 'paragraph' } );
+			enterBlock( batch, doc.selection );
+
+			this.fire( 'afterExecute', { batch } );
 		} );
 	}
 }
@@ -28,14 +35,9 @@ export default class EnterCommand extends Command {
  * Creates a new block in the way that the <kbd>Enter</kbd> key is expected to work.
  *
  * @param {engine.model.Batch} batch A batch to which the deltas will be added.
- * @param {engine.model.Selection} selection
- * @param {Object} options
- * @param {Boolean} options.defaultBlockName The name of the block which should be created when Enter leaves
- * another block. Usually set to `'paragraph'`. For example, when creating a block in `<heading>foo^</heading>`,
- * the result will be `<heading>foo</heading><paragraph>^</paragraph>`.
+ * @param {engine.model.Selection} selection Selection on which the action should be performed.
  */
-export function enterBlock( batch, selection, options = {} ) {
-	const defaultBlockName = options.defaultBlockName;
+function enterBlock( batch, selection ) {
 	const doc = batch.document;
 	const isSelectionEmpty = selection.isCollapsed;
 	const range = selection.getFirstRange();
@@ -52,71 +54,31 @@ export function enterBlock( batch, selection, options = {} ) {
 	}
 
 	if ( isSelectionEmpty ) {
-		splitBlock( batch, selection, range.start, defaultBlockName );
+		splitBlock( batch, selection, range.start );
 	} else {
 		const shouldMerge = range.start.isAtStart && range.end.isAtEnd;
 		const isContainedWithinOneElement = ( startElement == endElement );
 
 		doc.composer.deleteContents( batch, selection, { merge: shouldMerge } );
 
-		// Fully selected elements.
-		//
-		// <h>[xx</h><p>yy]<p>	-> <h>^</h>				-> <p>^</p>
-		// <h>[xxyy]</h>		-> <h>^</h>				-> <p>^</p>
-		if ( shouldMerge ) {
-			// We'll lose the ref to the renamed element, so let's keep a position inside it
-			// (offsets won't change, so it will stay in place). See ckeditor5-engine#367.
-			const pos = Position.createFromPosition( selection.focus );
-			const newBlockName = getNewBlockName( doc, startElement, defaultBlockName );
-
-			if ( startElement.name != newBlockName ) {
-				batch.rename( startElement, newBlockName );
+		if ( !shouldMerge ) {
+			// Partially selected elements.
+			//
+			// <h>x[xx]x</h>		-> <h>x^x</h>			-> <h>x</h><h>^x</h>
+			if ( isContainedWithinOneElement ) {
+				splitBlock( batch, selection, selection.focus );
+			}
+			// Selection over multiple elements.
+			//
+			// <h>x[x</h><p>y]y<p>	-> <h>x^</h><p>y</p>	-> <h>x</h><p>^y</p>
+			else {
+				selection.collapse( endElement );
 			}
-
-			selection.collapse( pos );
-		}
-		// Partially selected elements.
-		//
-		// <h>x[xx]x</h>		-> <h>x^x</h>			-> <h>x</h><h>^x</h>
-		else if ( isContainedWithinOneElement ) {
-			splitBlock( batch, selection, selection.focus, defaultBlockName );
-		}
-		// Selection over multilpe elements.
-		//
-		// <h>x[x</h><p>y]y<p>	-> <h>x^</h><p>y</p>	-> <h>x</h><p>^y</p>
-		else {
-			selection.collapse( endElement );
 		}
 	}
 }
 
-function splitBlock( batch, selection, splitPos, defaultBlockName ) {
-	const doc = batch.document;
-	const parent = splitPos.parent;
-
-	if ( splitPos.isAtEnd ) {
-		const newElement = new Element( getNewBlockName( doc, parent, defaultBlockName ) );
-
-		batch.insert( Position.createAfter( parent ), newElement );
-
-		selection.collapse( newElement );
-	} else {
-		// TODO After ckeditor5-engine#340 is fixed we'll be able to base on splitPos's location.
-		const endPos = LivePosition.createFromPosition( splitPos );
-		endPos.stickiness = 'STICKS_TO_NEXT';
-
-		batch.split( splitPos );
-
-		selection.collapse( endPos );
-
-		endPos.detach();
-	}
-}
-
-function getNewBlockName( doc, startElement, defaultBlockName ) {
-	if ( doc.schema.check( { name: defaultBlockName, inside: startElement.parent.name } ) ) {
-		return defaultBlockName;
-	}
-
-	return startElement.name;
+function splitBlock( batch, selection, splitPos ) {
+	batch.split( splitPos );
+	selection.collapse( splitPos.parent.nextSibling );
 }

+ 22 - 90
packages/ckeditor5-enter/tests/entercommand.js

@@ -4,10 +4,10 @@
  */
 
 import ModelTestEditor from '/tests/core/_utils/modeltesteditor.js';
-import { default as EnterCommand, enterBlock } from '/ckeditor5/enter/entercommand.js';
+import EnterCommand from '/ckeditor5/enter/entercommand.js';
 import { getData, setData } from '/tests/engine/_utils/model.js';
 
-let editor, doc, schema;
+let editor, doc, schema, command;
 
 beforeEach( () => {
 	return ModelTestEditor.create()
@@ -15,7 +15,7 @@ beforeEach( () => {
 			editor = newEditor;
 			doc = editor.document;
 
-			const command = new EnterCommand( editor );
+			command = new EnterCommand( editor );
 			editor.commands.set( 'enter', command );
 
 			schema = doc.schema;
@@ -40,87 +40,38 @@ describe( 'EnterCommand', () => {
 		expect( getData( doc, { withoutSelection: true } ) ).to.equal( '<p>foo</p><p></p>' );
 		expect( spy.calledOnce ).to.be.true;
 	} );
-
-	it( 'uses paragraph as default block', () => {
-		schema.registerItem( 'paragraph', '$block' );
-		setData( doc, '<h>foo[]</h>' );
-
-		editor.execute( 'enter' );
-
-		expect( getData( doc, { withoutSelection: true } ) ).to.equal( '<h>foo</h><paragraph></paragraph>' );
-	} );
 } );
 
-describe( 'enterBlock', () => {
+describe( '_doExecute', () => {
 	describe( 'collapsed selection', () => {
 		test(
 			'does nothing in the root',
 			'foo[]bar',
-			'foo[]bar',
-			{ defaultBlockName: 'p' }
+			'foo[]bar'
 		);
 
 		test(
 			'splits block',
 			'<p>x</p><p>foo[]bar</p><p>y</p>',
-			'<p>x</p><p>foo</p><p>[]bar</p><p>y</p>',
-			{ defaultBlockName: 'p' }
-		);
-
-		test(
-			'splits block (other than default)',
-			'<p>x</p><h>foo[]bar</h><p>y</p>',
-			'<p>x</p><h>foo</h><h>[]bar</h><p>y</p>',
-			{ defaultBlockName: 'p' }
+			'<p>x</p><p>foo</p><p>[]bar</p><p>y</p>'
 		);
 
 		test(
 			'splits block at the end',
 			'<p>x</p><p>foo[]</p><p>y</p>',
-			'<p>x</p><p>foo</p><p>[]</p><p>y</p>',
-			{ defaultBlockName: 'p' }
+			'<p>x</p><p>foo</p><p>[]</p><p>y</p>'
 		);
 
 		test(
 			'splits block at the beginning',
 			'<p>x</p><p>[]foo</p><p>y</p>',
-			'<p>x</p><p></p><p>[]foo</p><p>y</p>',
-			{ defaultBlockName: 'p' }
-		);
-
-		test(
-			'splits block at the beginning (other than default)',
-			'<p>x</p><h>[]foo</h><p>y</p>',
-			'<p>x</p><h></h><h>[]foo</h><p>y</p>',
-			{ defaultBlockName: 'p' }
-		);
-
-		test(
-			'creates default block when leaving other block',
-			'<h>foo[]</h><p>x</p>',
-			'<h>foo</h><p>[]</p><p>x</p>',
-			{ defaultBlockName: 'p' }
-		);
-
-		test(
-			'does not rename when default block is not allowed',
-			'<h>foo[]</h><p>x</p>',
-			'<h>foo</h><h>[]</h><p>x</p>',
-			{ defaultBlockName: 'xxx' }
+			'<p>x</p><p></p><p>[]foo</p><p>y</p>'
 		);
 
 		test(
 			'inserts new block after empty one',
 			'<p>x</p><p>[]</p><p>y</p>',
-			'<p>x</p><p></p><p>[]</p><p>y</p>',
-			{ defaultBlockName: 'p' }
-		);
-
-		test(
-			'inserts new block after empty one (other than default)',
-			'<p>x</p><h>[]</h><p>y</p>',
-			'<p>x</p><h></h><p>[]</p><p>y</p>',
-			{ defaultBlockName: 'p' }
+			'<p>x</p><p></p><p>[]</p><p>y</p>'
 		);
 	} );
 
@@ -128,58 +79,39 @@ describe( 'enterBlock', () => {
 		test(
 			'only deletes the content when directly in the root',
 			'fo[ob]ar',
-			'fo[]ar',
-			{ defaultBlockName: 'p' }
+			'fo[]ar'
 		);
 
 		test(
 			'deletes text and splits',
 			'<p>ab[cd]ef</p><p>ghi</p>',
-			'<p>ab</p><p>[]ef</p><p>ghi</p>',
-			{ defaultBlockName: 'p' }
-		);
-
-		test(
-			'deletes text and splits (other than default)',
-			'<h>ab[cd]ef</h>',
-			'<h>ab</h><h>[]ef</h>',
-			{ defaultBlockName: 'p' }
+			'<p>ab</p><p>[]ef</p><p>ghi</p>'
 		);
 
 		test(
 			'places selection in the 2nd element',
 			'<h>ab[c</h><p>d]ef</p><p>ghi</p>',
-			'<h>ab</h><p>[]ef</p><p>ghi</p>',
-			{ defaultBlockName: 'p' }
+			'<h>ab</h><p>[]ef</p><p>ghi</p>'
 		);
 
 		test(
 			'leaves one empty element after one was fully selected',
 			'<p>x</p><p>[abcdef]</p><p>y</p>',
-			'<p>x</p><p>[]</p><p>y</p>',
-			{ defaultBlockName: 'p' }
-		);
-
-		test(
-			'leaves one (default) empty element after one was fully selected',
-			'<h>[abcdef]</h>',
-			'<p>[]</p>',
-			{ defaultBlockName: 'p' }
+			'<p>x</p><p>[]</p><p>y</p>'
 		);
 
 		test(
-			'leaves one (default) empty element after two were fully selected',
-			'<h>[abc</h><p>def]</p>',
-			'<p>[]</p>',
-			{ defaultBlockName: 'p' }
+			'leaves one empty element after two were fully selected',
+			'<p>[abc</p><p>def]</p>',
+			'<p>[]</p>'
 		);
 
-		it( 'leaves one (default) empty element after two were fully selected (backward)', () => {
-			setData( doc, '<h>[abc</h><p>def]</p>' );
+		it( 'leaves one empty element after two were fully selected (backward)', () => {
+			setData( doc, '<p>[abc</p><p>def]</p>' );
 			// @TODO: Add option for setting selection direction to model utils.
 			doc.selection._lastRangeBackward = true;
 
-			enterBlock( doc.batch(), doc.selection, { defaultBlockName: 'p' } );
+			command._doExecute();
 
 			expect( getData( doc ) ).to.equal( '<p>[]</p>' );
 		} );
@@ -191,17 +123,17 @@ describe( 'enterBlock', () => {
 
 			setData( doc, '<p>[x]</p>' );
 
-			enterBlock( doc.batch(), doc.selection, { defaultBlockName: 'p' } );
+			command._doExecute();
 
 			expect( spy.calledOnce ).to.be.true;
 		} );
 	} );
 
-	function test( title, input, output, options ) {
+	function test( title, input, output ) {
 		it( title, () => {
 			setData( doc, input );
 
-			enterBlock( doc.batch(), doc.selection, options );
+			command._doExecute();
 
 			expect( getData( doc ) ).to.equal( output );
 		} );