ソースを参照

Merge pull request #20 from ckeditor/t/19

Fix: Nested element structures next to widgets will be correctly removed when pressing <kbd>Backspace</kbd> or <kbd>Delete</kbd>. Closes #19.
Szymon Kupś 8 年 前
コミット
a453fcae4d

+ 7 - 4
packages/ckeditor5-widget/src/widget.js

@@ -165,12 +165,15 @@ export default class Widget extends Plugin {
 
 		if ( objectElement ) {
 			modelDocument.enqueueChanges( () => {
+				const batch = modelDocument.batch();
+				let previousNode = modelSelection.anchor.parent;
+
 				// Remove previous element if empty.
-				const previousNode = modelSelection.anchor.parent;
+				while ( previousNode.isEmpty ) {
+					const nodeToRemove = previousNode;
+					previousNode = nodeToRemove.parent;
 
-				if ( previousNode.isEmpty ) {
-					const batch = modelDocument.batch();
-					batch.remove( previousNode );
+					batch.remove( nodeToRemove );
 				}
 
 				this._setSelectionOverElement( objectElement );

+ 268 - 0
packages/ckeditor5-widget/tests/widget.js

@@ -42,6 +42,22 @@ describe( 'Widget', () => {
 				doc.schema.allow( { name: 'editable', inside: 'widget' } );
 				doc.schema.allow( { name: 'editable', inside: '$root' } );
 
+				// Image feature.
+				doc.schema.registerItem( 'image' );
+				doc.schema.allow( { name: 'image', inside: '$root' } );
+				doc.schema.objects.add( 'image' );
+
+				// Block-quote feature.
+				doc.schema.registerItem( 'blockQuote' );
+				doc.schema.allow( { name: 'blockQuote', inside: '$root' } );
+				doc.schema.allow( { name: '$block', inside: 'blockQuote' } );
+
+				// Div element which helps nesting elements.
+				doc.schema.registerItem( 'div' );
+				doc.schema.allow( { name: 'div', inside: 'blockQuote' } );
+				doc.schema.allow( { name: 'div', inside: 'div' } );
+				doc.schema.allow( { name: 'paragraph', inside: 'div' } );
+
 				buildModelConverter().for( editor.editing.modelToView )
 					.fromElement( 'paragraph' )
 					.toElement( 'p' );
@@ -66,6 +82,18 @@ describe( 'Widget', () => {
 				buildModelConverter().for( editor.editing.modelToView )
 					.fromElement( 'editable' )
 					.toElement( () => new ViewEditable( 'figcaption', { contenteditable: true } ) );
+
+				buildModelConverter().for( editor.editing.modelToView )
+					.fromElement( 'image' )
+					.toElement( 'img' );
+
+				buildModelConverter().for( editor.editing.modelToView )
+					.fromElement( 'blockQuote' )
+					.toElement( 'blockquote' );
+
+				buildModelConverter().for( editor.editing.modelToView )
+					.fromElement( 'div' )
+					.toElement( 'div' );
 			} );
 	} );
 
@@ -450,6 +478,134 @@ describe( 'Widget', () => {
 				sinon.assert.calledOnce( domEventDataMock.preventDefault );
 				sinon.assert.notCalled( keydownHandler );
 			} );
+
+			test(
+				'should remove the entire empty element if it is next to a widget',
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote><paragraph>[]</paragraph></blockQuote>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.backspace,
+
+				'<paragraph>foo</paragraph>[<image></image>]<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should remove the entire empty element (deeper structure) if it is next to a widget',
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote><div><div><paragraph>[]</paragraph></div></div></blockQuote>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.backspace,
+
+				'<paragraph>foo</paragraph>' +
+				'[<image></image>]' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should remove the entire empty element (deeper structure) if it is next to a widget (forward delete)',
+
+				'<paragraph>foo</paragraph>' +
+				'<blockQuote><div><div><paragraph>[]</paragraph></div></div></blockQuote>' +
+				'<image></image>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.delete,
+
+				'<paragraph>foo</paragraph>' +
+				'[<image></image>]' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should not remove the entire element which is not empty and the element is next to a widget',
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote><paragraph>[]</paragraph><paragraph></paragraph></blockQuote>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.backspace,
+
+				'<paragraph>foo</paragraph>' +
+				'[<image></image>]' +
+				'<blockQuote><paragraph></paragraph></blockQuote>' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should not remove the entire element which is not empty and the element is next to a widget (forward delete)',
+
+				'<paragraph>foo</paragraph>' +
+				'<blockQuote><paragraph>Foo</paragraph><paragraph>[]</paragraph></blockQuote>' +
+				'<image></image>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.delete,
+
+				'<paragraph>foo</paragraph>' +
+				'<blockQuote><paragraph>Foo</paragraph></blockQuote>' +
+				'[<image></image>]' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should not remove the entire element (deeper structure) which is not empty and the element is next to a widget',
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph>[]</paragraph>' +
+						'</div>' +
+					'</div>' +
+					'<paragraph></paragraph>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.backspace,
+
+				'<paragraph>foo</paragraph>' +
+				'[<image></image>]' +
+				'<blockQuote>' +
+					'<paragraph></paragraph>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should do nothing if the nested element is not empty and the element is next to a widget',
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph>Foo[]</paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.backspace,
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph>Foo[]</paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>'
+			);
 		} );
 
 		describe( 'arrows', () => {
@@ -743,6 +899,118 @@ describe( 'Widget', () => {
 				keyCodes.arrowright,
 				'<paragraph>[foo]</paragraph><widget></widget><paragraph>[bar]</paragraph>'
 			);
+
+			test(
+				'should work if selection is in nested element (left arrow)',
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph>[]</paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.arrowleft,
+
+				'<paragraph>foo</paragraph>' +
+				'[<image></image>]' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph></paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should work if selection is in nested element (up arrow)',
+
+				'<paragraph>foo</paragraph>' +
+				'<image></image>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph>[]</paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.arrowup,
+
+				'<paragraph>foo</paragraph>' +
+				'[<image></image>]' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph></paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should work if selection is in nested element (right arrow)',
+
+				'<paragraph>foo</paragraph>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph>[]</paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<image></image>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.arrowright,
+
+				'<paragraph>foo</paragraph>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph></paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'[<image></image>]' +
+				'<paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should work if selection is in nested element (down arrow)',
+
+				'<paragraph>foo</paragraph>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph>[]</paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'<image></image>' +
+				'<paragraph>foo</paragraph>',
+
+				keyCodes.arrowdown,
+
+				'<paragraph>foo</paragraph>' +
+				'<blockQuote>' +
+					'<div>' +
+						'<div>' +
+							'<paragraph></paragraph>' +
+						'</div>' +
+					'</div>' +
+				'</blockQuote>' +
+				'[<image></image>]' +
+				'<paragraph>foo</paragraph>'
+			);
 		} );
 
 		describe( 'Ctrl+A', () => {