8
0
Просмотр исходного кода

The findOptimalInsertionPosition() helper should respect the "fake widget caret" to provide the best UX.

Aleksander Nowodzinski 5 лет назад
Родитель
Сommit
9641d9258f
2 измененных файлов с 85 добавлено и 2 удалено
  1. 13 2
      packages/ckeditor5-widget/src/utils.js
  2. 72 0
      packages/ckeditor5-widget/tests/utils.js

+ 13 - 2
packages/ckeditor5-widget/src/utils.js

@@ -14,6 +14,7 @@ import BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpa
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 
 import dragHandleIcon from '../theme/icons/drag-handle.svg';
+import { getTypeAroundFakeCaretPosition } from './widgettypearound/utils';
 
 /**
  * CSS class added to each widget element.
@@ -256,8 +257,18 @@ export function toWidgetEditable( editable, writer ) {
 export function findOptimalInsertionPosition( selection, model ) {
 	const selectedElement = selection.getSelectedElement();
 
-	if ( selectedElement && model.schema.isBlock( selectedElement ) ) {
-		return model.createPositionAfter( selectedElement );
+	if ( selectedElement ) {
+		const typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( selection );
+
+		// If the WidgetTypeAround "fake caret" is displayed, use its position for the insertion
+		// to provide the most predictable UX (https://github.com/ckeditor/ckeditor5/issues/7438).
+		if ( typeAroundFakeCaretPosition ) {
+			return model.createPositionAt( selectedElement, typeAroundFakeCaretPosition );
+		}
+
+		if ( model.schema.isBlock( selectedElement ) ) {
+			return model.createPositionAfter( selectedElement );
+		}
 	}
 
 	const firstBlock = selection.getSelectedBlocks().next().value;

+ 72 - 0
packages/ckeditor5-widget/tests/utils.js

@@ -327,6 +327,11 @@ describe( 'widget utils', () => {
 				isBlock: true
 			} );
 
+			model.schema.register( 'horizontalLine', {
+				isObject: true,
+				allowWhere: '$block'
+			} );
+
 			model.schema.extend( 'span', { allowIn: 'paragraph' } );
 			model.schema.extend( '$text', { allowIn: 'span' } );
 		} );
@@ -410,6 +415,73 @@ describe( 'widget utils', () => {
 
 			expect( pos.path ).to.deep.equal( [ 3 ] );
 		} );
+
+		// https://github.com/ckeditor/ckeditor5/issues/7438
+		describe( 'integration with the WidgetTypeAround feature ("widget-type-around" model selection attribute)', () => {
+			it( 'should respect the attribute value when a widget (block and an object) is selected ("fake caret" before a widget)', () => {
+				setData( model, '<paragraph>x</paragraph>[<image></image>]<paragraph>y</paragraph>' );
+
+				model.change( writer => {
+					writer.setSelectionAttribute( 'widget-type-around', 'before' );
+				} );
+
+				const pos = findOptimalInsertionPosition( doc.selection, model );
+
+				expect( pos.path ).to.deep.equal( [ 1 ] );
+			} );
+
+			it( 'should respect the attribute value when a widget (block and an object) is selected ("fake caret" after a widget)', () => {
+				setData( model, '<paragraph>x</paragraph>[<image></image>]<paragraph>y</paragraph>' );
+
+				model.change( writer => {
+					writer.setSelectionAttribute( 'widget-type-around', 'after' );
+				} );
+
+				const pos = findOptimalInsertionPosition( doc.selection, model );
+
+				expect( pos.path ).to.deep.equal( [ 2 ] );
+			} );
+
+			it( 'should return a position after a selected widget (block and an object) ("fake caret" not displayed)', () => {
+				setData( model, '<paragraph>x</paragraph>[<image></image>]<paragraph>y</paragraph>' );
+
+				const pos = findOptimalInsertionPosition( doc.selection, model );
+
+				expect( pos.path ).to.deep.equal( [ 2 ] );
+			} );
+
+			it( 'should respect the attribute value when a widget (an object) is selected ("fake caret" before a widget)', () => {
+				setData( model, '<paragraph>x</paragraph>[<horizontalLine></horizontalLine>]<paragraph>y</paragraph>' );
+
+				model.change( writer => {
+					writer.setSelectionAttribute( 'widget-type-around', 'before' );
+				} );
+
+				const pos = findOptimalInsertionPosition( doc.selection, model );
+
+				expect( pos.path ).to.deep.equal( [ 1 ] );
+			} );
+
+			it( 'should respect the attribute value when a widget (an object) is selected ("fake caret" after a widget)', () => {
+				setData( model, '<paragraph>x</paragraph>[<horizontalLine></horizontalLine>]<paragraph>y</paragraph>' );
+
+				model.change( writer => {
+					writer.setSelectionAttribute( 'widget-type-around', 'after' );
+				} );
+
+				const pos = findOptimalInsertionPosition( doc.selection, model );
+
+				expect( pos.path ).to.deep.equal( [ 2 ] );
+			} );
+
+			it( 'should return a position after a selected widget (an object) ("fake caret" not displayed)', () => {
+				setData( model, '<paragraph>x</paragraph>[<horizontalLine></horizontalLine>]<paragraph>y</paragraph>' );
+
+				const pos = findOptimalInsertionPosition( doc.selection, model );
+
+				expect( pos.path ).to.deep.equal( [ 2 ] );
+			} );
+		} );
 	} );
 
 	describe( 'viewToModelPositionOutsideModelElement()', () => {