8
0
Эх сурвалжийг харах

Fix: `view.Selection#getSelectedElement` should handle cases where position is anchored at the beginning/end of a text node.

Szymon Cofalik 7 жил өмнө
parent
commit
41299298dd

+ 20 - 2
packages/ckeditor5-engine/src/view/selection.js

@@ -414,8 +414,26 @@ export default class Selection {
 		}
 		}
 
 
 		const range = this.getFirstRange();
 		const range = this.getFirstRange();
-		const nodeAfterStart = range.start.nodeAfter;
-		const nodeBeforeEnd = range.end.nodeBefore;
+
+		let nodeAfterStart = range.start.nodeAfter;
+		let nodeBeforeEnd = range.end.nodeBefore;
+
+		// Handle the situation when selection position is at the beginning / at the end of a text node.
+		// In such situation `.nodeAfter` and `.nodeBefore` are `null` but the selection still might be spanning
+		// over one element.
+		//
+		// <p>Foo{<span class="widget"></span>}bar</p> vs <p>Foo[<span class="widget"></span>]bar</p>
+		//
+		// These are basically the same selections, only the difference is if the selection position is at
+		// at the end/at the beginning of a text node or just before/just after the text node.
+		//
+		if ( range.start.parent.is( 'text' ) && range.start.isAtEnd && range.start.parent.nextSibling ) {
+			nodeAfterStart = range.start.parent.nextSibling;
+		}
+
+		if ( range.end.parent.is( 'text' ) && range.end.isAtStart && range.end.parent.previousSibling ) {
+			nodeBeforeEnd = range.end.parent.previousSibling;
+		}
 
 
 		return ( nodeAfterStart instanceof Element && nodeAfterStart == nodeBeforeEnd ) ? nodeAfterStart : null;
 		return ( nodeAfterStart instanceof Element && nodeAfterStart == nodeBeforeEnd ) ? nodeAfterStart : null;
 	}
 	}

+ 8 - 0
packages/ckeditor5-engine/tests/view/selection.js

@@ -976,6 +976,14 @@ describe( 'Selection', () => {
 			expect( selection.getSelectedElement() ).to.equal( b );
 			expect( selection.getSelectedElement() ).to.equal( b );
 		} );
 		} );
 
 
+		it( 'should return selected element if the selection is anchored at the end/at the beginning of a text node', () => {
+			const { selection: docSelection, view } = parse( 'foo {<b>bar</b>} baz' );
+			const b = view.getChild( 1 );
+			const selection = new Selection( docSelection );
+
+			expect( selection.getSelectedElement() ).to.equal( b );
+		} );
+
 		it( 'should return null if there is more than one range', () => {
 		it( 'should return null if there is more than one range', () => {
 			const { selection: docSelection } = parse( 'foo [<b>bar</b>] [<i>baz</i>]' );
 			const { selection: docSelection } = parse( 'foo [<b>bar</b>] [<i>baz</i>]' );
 			const selection = new Selection( docSelection );
 			const selection = new Selection( docSelection );