8
0
فهرست منبع

Added empty DocumentFragment handling to view utils parse().

Szymon Kupś 9 سال پیش
والد
کامیت
8f5c1b3995

+ 1 - 1
packages/ckeditor5-engine/src/view/node.js

@@ -123,7 +123,7 @@ export default class Node {
 		const ancestors = [];
 		let parent = options.includeNode ? this : this.parent;
 
-		while ( parent !== null ) {
+		while ( parent ) {
 			ancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );
 			parent = parent.parent;
 		}

+ 33 - 15
packages/ckeditor5-engine/tests/_utils-tests/view.js

@@ -311,6 +311,39 @@ describe( 'view test utils', () => {
 	} );
 
 	describe( 'parse', () => {
+		it( 'should return empty DocumentFragment for empty string', () => {
+			const fragment = parse( '' );
+
+			expect( fragment ).to.be.instanceOf( DocumentFragment );
+			expect( fragment.getChildCount() ).to.equal( 0 );
+		} );
+
+		it( 'should return empty DocumentFragment and Selection for string containing range only', () => {
+			const { view, selection } = parse( '[]' );
+
+			expect( view ).to.be.instanceOf( DocumentFragment );
+			expect( selection.rangeCount ).to.equal( 1 );
+			expect( selection.getFirstRange().isEqual( Range.createFromParentsAndOffsets( view, 0, view, 0 ) ) ).to.be.true;
+		} );
+
+		it( 'should return Element if range is around single element', () => {
+			const { view, selection } = parse( '[<b>foobar</b>]' );
+			const parent = view.parent;
+
+			expect( view ).to.be.instanceOf( Element );
+			expect( parent ).to.be.instanceOf( DocumentFragment );
+			expect( selection.rangeCount ).to.equal( 1 );
+			expect( selection.getFirstRange().isEqual( Range.createFromParentsAndOffsets( parent, 0, parent, 1 ) ) ).to.be.true;
+		} );
+
+		it( 'should create DocumentFragment when multiple elements on root', () => {
+			const view = parse( '<b></b><i></i>' );
+			expect( view ).to.be.instanceOf( DocumentFragment );
+			expect( view.getChildCount() ).to.equal( 2 );
+			expect( view.getChild( 0 ).isSimilar( new Element( 'b' ) ) ).to.be.true;
+			expect( view.getChild( 1 ).isSimilar( new Element( 'i' ) ) ).to.be.true;
+		} );
+
 		it( 'should parse text', () => {
 			const text = parse( 'foobar' );
 			expect( text ).to.be.instanceOf( Text );
@@ -369,14 +402,6 @@ describe( 'view test utils', () => {
 			expect( parsed2.isSimilar( attribute2 ) ).to.be.true;
 		} );
 
-		it( 'should create DocumentFragment when multiple elements on root', () => {
-			const view = parse( '<b></b><i></i>' );
-			expect( view ).to.be.instanceOf( DocumentFragment );
-			expect( view.getChildCount() ).to.equal( 2 );
-			expect( view.getChild( 0 ).isSimilar( new Element( 'b' ) ) ).to.be.true;
-			expect( view.getChild( 1 ).isSimilar( new Element( 'i' ) ) ).to.be.true;
-		} );
-
 		it( 'should paste nested elements and texts', () => {
 			const parsed = parse( '<container:p>foo<b:12>bar<i:25>qux</i:25></b:12></container:p>' );
 			expect( parsed.isSimilar( new ContainerElement( 'p' ) ) ).to.be.true;
@@ -473,13 +498,6 @@ describe( 'view test utils', () => {
 			expect( selection.focus.isEqual( ranges[ 2 ].start ) ).to.be.true;
 		} );
 
-		it( 'should return DocumentFragment if range is around single element', () => {
-			const { view, selection } = parse( '[<b>foobar</b>]' );
-			expect( view ).to.be.instanceOf( DocumentFragment );
-			expect( selection.rangeCount ).to.equal( 1 );
-			expect( selection.getFirstRange().isEqual( Range.createFromParentsAndOffsets( view, 0, view, 1 ) ) ).to.be.true;
-		} );
-
 		it( 'should throw when ranges order does not include all ranges', () => {
 			expect( () => {
 				parse( '{}foobar{}', { order: [ 1 ] } );

+ 17 - 1
packages/ckeditor5-engine/tests/_utils/view.js

@@ -199,6 +199,11 @@ export function stringify( node, selectionOrPositionOrRange = null, options = {}
 
 /**
  * Parses HTML-like string and returns view tree nodes.
+ *
+ * Empty string will be converted to empty {@link engine.view.DocumentFragment DocumentFragment}.
+ *
+ *		parse( '' ); // Returns instance of DocumentFragment.
+ *
  * Simple string will be converted to {@link engine.view.Text Text} node:
  *
  *		parse( 'foobar' ); // Returns instance of Text.
@@ -254,9 +259,20 @@ export function parse( data, options = {} ) {
 	const viewParser = new ViewParser();
 	const rangeParser = new RangeParser();
 
-	const view = viewParser.parse( data, options.rootElement );
+	let view = viewParser.parse( data, options.rootElement );
+
+	// If single Element or Text is returned - move it to the DocumentFragment.
+	if ( view instanceof ViewText || view instanceof ViewElement ) {
+		view = new ViewDocumentFragment( view );
+	}
+
 	const ranges = rangeParser.parse( view, options.order );
 
+	// If only one element is returned inside DocumentFragment - return that element.
+	if ( view instanceof ViewDocumentFragment && view.getChildCount() === 1 ) {
+		view = view.getChild( 0 );
+	}
+
 	// When ranges are present - return object containing view, and selection.
 	if ( ranges.length ) {
 		const selection = new Selection();

+ 11 - 0
packages/ckeditor5-engine/tests/view/node.js

@@ -100,6 +100,17 @@ describe( 'Node', () => {
 			expect( result2[ 1 ] ).to.equal( two );
 			expect( result2[ 0 ] ).to.equal( charR );
 		} );
+
+		it( 'should return ancestors including DocumentFragment', () => {
+			const fragment = new DocumentFragment( root );
+			const result = img.getAncestors();
+			root.remove();
+
+			expect( result.length ).to.equal( 3 );
+			expect( result[ 0 ] ).to.equal( fragment );
+			expect( result[ 1 ] ).to.equal( root );
+			expect( result[ 2 ] ).to.equal( two );
+		} );
 	} );
 
 	describe( 'getIndex', () => {