瀏覽代碼

Other (clipboard): Changed paste as plain text implementation to work better with links.

Previous implementation caused "LinkEditing typing over the link should not preserve selection attributes when the changes are not caused by typing (pasting check)" test case to fail. See https://travis-ci.org/github/ckeditor/ckeditor5/builds/719551313.
Marek Lewandowski 5 年之前
父節點
當前提交
cb08c3e3a1
共有 2 個文件被更改,包括 41 次插入13 次删除
  1. 19 13
      packages/ckeditor5-clipboard/src/clipboard.js
  2. 22 0
      packages/ckeditor5-clipboard/tests/clipboard.js

+ 19 - 13
packages/ckeditor5-clipboard/src/clipboard.js

@@ -97,7 +97,6 @@ export default class Clipboard extends Plugin {
 			if ( !data.content.isEmpty ) {
 				const dataController = this.editor.data;
 				const model = this.editor.model;
-				const initialAttributes = new Map( modelDocument.selection.getAttributes() );
 
 				// Convert the pasted content to a model document fragment.
 				// Conversion is contextual, but in this case we need an "all allowed" context and for that
@@ -108,19 +107,26 @@ export default class Clipboard extends Plugin {
 					return;
 				}
 
-				// Plain text can be determined based on event flag (#7799) or auto detection (#1006).
-				const isPlainText = data.asPlainText || isPlainTextFragment( modelFragment );
-
-				model.change( writer => {
-					const insertedRange = model.insertContent( modelFragment );
-
-					// The insertedRange needs to be verified, as the return value might easily be discarded like in #7887.
-					if ( isPlainText && insertedRange ) {
-						for ( const item of insertedRange.getItems() ) {
-							writer.setAttributes( initialAttributes, item );
+				// Plain text can be determined based on event flag (#7799) or auto detection (#1006). If detected
+				// preserve selection attributes on pasted items.
+				if ( data.asPlainText || isPlainTextFragment( modelFragment ) ) {
+					// Consider only formatting attributes.
+					const textAttributes = new Map( Array.from( modelDocument.selection.getAttributes() ).filter(
+						keyValuePair => editor.model.schema.getAttributeProperties( keyValuePair[ 0 ] ).isFormatting
+					) );
+
+					model.change( writer => {
+						const range = writer.createRangeIn( modelFragment );
+
+						for ( const item of range.getItems() ) {
+							if ( item.is( '$text' ) || item.is( '$textProxy' ) ) {
+								writer.setAttributes( textAttributes, item );
+							}
 						}
-					}
-				} );
+					} );
+				}
+
+				model.insertContent( modelFragment );
 
 				evt.stop();
 			}

+ 22 - 0
packages/ckeditor5-clipboard/tests/clipboard.js

@@ -351,6 +351,9 @@ describe( 'Clipboard feature', () => {
 				model = editor.model;
 
 				model.schema.extend( '$text', { allowAttributes: 'bold' } );
+				model.schema.extend( '$text', { allowAttributes: 'test' } );
+
+				editor.model.schema.setAttributeProperties( 'bold', { isFormatting: true } );
 
 				model.schema.register( 'softBreak', {
 					allowWhere: '$text',
@@ -522,6 +525,25 @@ describe( 'Clipboard feature', () => {
 
 				expect( getModelData( model ) ).to.equal( '<paragraph><$text bold="true">Bolded []text.</$text></paragraph>' );
 			} );
+
+			it( 'ignores non-formatting text attributes', () => {
+				setModelData( model, '<paragraph><$text test="true">Bolded []text.</$text></paragraph>' );
+
+				const dataTransferMock = createDataTransfer( {
+					'text/html': 'foo',
+					'text/plain': 'foo'
+				} );
+
+				viewDocument.fire( 'clipboardInput', {
+					dataTransfer: dataTransferMock,
+					asPlainText: false,
+					stopPropagation() {},
+					preventDefault() {}
+				} );
+
+				expect( getModelData( model ) ).to.equal(
+					'<paragraph><$text test="true">Bolded </$text>foo[]<$text test="true">text.</$text></paragraph>' );
+			} );
 		} );
 
 		function createDataTransfer( data ) {