瀏覽代碼

Improved filtering of nested elements after merge.

Oskar Wróbel 8 年之前
父節點
當前提交
e8057d0d1d

+ 29 - 8
packages/ckeditor5-engine/src/controller/insertcontent.js

@@ -286,12 +286,12 @@ class Insertion {
 		if ( mergeLeft ) {
 			const position = LivePosition.createFromPosition( this.position );
 
-			// We need to check a children of node that is going to be merged
-			// and strip it from the disallowed attributes according to the new parent.
-			removeDisallowedAttributes( this.schema, Array.from( node.getChildren() ), [ mergePosLeft.nodeBefore ] );
-
 			this.batch.merge( mergePosLeft );
 
+			// We need to check and strip disallowed attributes in all nested nodes because after merge
+			// some attributes could end up in a path where are disallowed.
+			removeDisallowedAttributesOnBatch( this.batch, Array.from( this.position.parent.getChildren() ), position );
+
 			this.position = Position.createFromPosition( position );
 			position.detach();
 		}
@@ -313,12 +313,12 @@ class Insertion {
 			// NOK: <p>xx[]</p> + <p>yy</p> => <p>xxyy[]</p> (when sticks to next)
 			const position = new LivePosition( this.position.root, this.position.path, 'sticksToPrevious' );
 
-			// We need to check a children of node that is going to be merged
-			// and strip it from the disallowed attributes according to the new parent.
-			removeDisallowedAttributes( this.schema, Array.from( node.getChildren() ), [ mergePosRight.nodeAfter ] );
-
 			this.batch.merge( mergePosRight );
 
+			// We need to check and strip disallowed attributes in all nested nodes because after merge
+			// some attributes could end up in a place where are disallowed.
+			removeDisallowedAttributesOnBatch( this.batch, Array.from( this.position.parent.getChildren() ), position );
+
 			this.position = Position.createFromPosition( position );
 			position.detach();
 		}
@@ -461,3 +461,24 @@ function removeDisallowedAttributes( schema, nodes, schemaPath ) {
 		}
 	}
 }
+
+// Adds deltas with `removeAttributes` operation for disallowed by schema attributes on given nodes and its children.
+//
+// @param {module:engine/model/batch~Batch} batch Batch to which the deltas will be added.
+// @param {module:engine/model/node~Node|Array<module:engine/model/node~Node>} nodes List of nodes or a single node to filter.
+// @param {module:engine/model/schema~SchemaPath} schemaPath
+function removeDisallowedAttributesOnBatch( batch, nodes, schemaPath ) {
+	const schema = batch.document.schema;
+
+	for ( const node of nodes ) {
+		for ( const attribute of node.getAttributeKeys() ) {
+			if ( !schema.check( { name: getNodeSchemaName( node ), attributes: attribute, inside: schemaPath } ) ) {
+				batch.removeAttribute( node, attribute );
+			}
+		}
+
+		if ( node.is( 'element' ) ) {
+			removeDisallowedAttributesOnBatch( batch, Array.from( node.getChildren() ), Position.createAt( node ) );
+		}
+	}
+}

+ 11 - 0
packages/ckeditor5-engine/tests/controller/insertcontent.js

@@ -594,6 +594,7 @@ describe( 'DataController', () => {
 
 				schema.registerItem( 'paragraph', '$block' );
 				schema.registerItem( 'heading1', '$block' );
+				schema.registerItem( 'child', '$block' );
 
 				// Let's use table as an example of content which needs to be filtered out.
 				schema.registerItem( 'table' );
@@ -610,7 +611,11 @@ describe( 'DataController', () => {
 				schema.allow( { name: '$text', inside: 'disallowedWidget' } );
 				schema.objects.add( 'disallowedWidget' );
 
+				schema.allow( { name: 'child', inside: 'paragraph' } );
+				schema.allow( { name: 'child', inside: 'heading1' } );
 				schema.allow( { name: '$text', attributes: 'b', inside: 'paragraph' } );
+				schema.allow( { name: '$text', attributes: [ 'b' ], inside: 'paragraph child' } );
+				schema.allow( { name: '$text', attributes: [ 'a', 'b' ], inside: 'heading1 child' } );
 			} );
 
 			it( 'filters out disallowed elements and leaves out the text', () => {
@@ -661,6 +666,12 @@ describe( 'DataController', () => {
 				expect( getData( doc ) ).to.equal( '<paragraph>foox<$text b="1">x</$text>x[]</paragraph>' );
 			} );
 
+			it( 'filters out disallowed attributes from nested child when merging', () => {
+				setData( doc, '<paragraph>f[]oo</paragraph>' );
+				insertHelper( '<heading1>x<child>b<$text a="1" b="1">a</$text>r</child>x</heading1>' );
+				expect( getData( doc ) ).to.equal( '<paragraph>fx<child>b<$text b="1">a</$text>r</child>x[]oo</paragraph>' );
+			} );
+
 			it( 'filters out disallowed attributes when autoparagraphing', () => {
 				setData( doc, '<paragraph>f[]oo</paragraph>' );
 				insertHelper( '<paragraph>xxx</paragraph><$text a="1" b="1">yyy</$text>' );