Explorar el Código

Feature (clipboard): Introduced `asPlainText` property for `clipboardInput` and `inputTransformation` events.

Marek Lewandowski hace 5 años
padre
commit
ede4db9ae9

+ 18 - 10
packages/ckeditor5-clipboard/src/clipboard.js

@@ -77,7 +77,11 @@ export default class Clipboard extends Plugin {
 			content = this._htmlDataProcessor.toView( content );
 
 			const eventInfo = new EventInfo( this, 'inputTransformation' );
-			this.fire( eventInfo, { content, dataTransfer } );
+			this.fire( eventInfo, {
+				content,
+				dataTransfer,
+				asPlainText: data.asPlainText
+			} );
 
 			// If CKEditor handled the input, do not bubble the original event any further.
 			// This helps external integrations recognize that fact and act accordingly.
@@ -93,6 +97,7 @@ 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
@@ -103,16 +108,19 @@ export default class Clipboard extends Plugin {
 					return;
 				}
 
-				// While pasting plain text, apply selection attributes on the text.
-				if ( isPlainText( modelFragment ) ) {
-					const node = modelFragment.getChild( 0 );
+				// Plain text can be determined based on event flag (#7799) or auto detection (#1006).
+				const isPlainText = data.asPlainText || isPlainTextFragment( modelFragment );
 
-					model.change( writer => {
-						writer.setAttributes( modelDocument.selection.getAttributes(), node );
-					} );
-				}
+				model.change( writer => {
+					const insertedRange = model.insertContent( modelFragment );
+
+					if ( isPlainText ) {
+						for ( const item of insertedRange.getItems() ) {
+							writer.setAttributes( initialAttributes, item );
+						}
+					}
+				} );
 
-				model.insertContent( modelFragment );
 				evt.stop();
 			}
 		}, { priority: 'low' } );
@@ -212,7 +220,7 @@ export default class Clipboard extends Plugin {
 //
 // @param {module:engine/view/documentfragment~DocumentFragment} documentFragment
 // @returns {Boolean}
-function isPlainText( documentFragment ) {
+function isPlainTextFragment( documentFragment ) {
 	if ( documentFragment.childCount > 1 ) {
 		return false;
 	}

+ 49 - 1
packages/ckeditor5-clipboard/tests/clipboard.js

@@ -173,7 +173,7 @@ describe( 'Clipboard feature', () => {
 
 		it( 'inserts content to the editor', () => {
 			const dataTransferMock = createDataTransfer( { 'text/html': '<p>x</p>', 'text/plain': 'y' } );
-			const spy = sinon.stub( editor.model, 'insertContent' );
+			const spy = sinon.stub( editor.model, 'insertContent' ).returns( editor.model.document.selection.getFirstRange() );
 
 			viewDocument.fire( 'paste', {
 				dataTransfer: dataTransferMock,
@@ -351,6 +351,16 @@ describe( 'Clipboard feature', () => {
 				model = editor.model;
 
 				model.schema.extend( '$text', { allowAttributes: 'bold' } );
+
+				model.schema.register( 'softBreak', {
+					allowWhere: '$text',
+					isInline: true
+				} );
+				editor.conversion.for( 'upcast' )
+					.elementToElement( {
+						model: 'softBreak',
+						view: 'br'
+					} );
 			} );
 
 			it( 'should inherit selection attributes (collapsed selection)', () => {
@@ -451,6 +461,44 @@ describe( 'Clipboard feature', () => {
 
 				expect( getModelData( model ) ).to.equal( '<paragraph><$text bold="true">Bolded foo[]text.</$text></paragraph>' );
 			} );
+
+			it( 'should inherit selection attributes with data.asPlainText switch set', () => {
+				setModelData( model, '<paragraph><$text bold="true">Bolded []text.</$text></paragraph>' );
+
+				const dataTransferMock = createDataTransfer( {
+					'text/html': 'foo',
+					'text/plain': 'foo'
+				} );
+
+				viewDocument.fire( 'clipboardInput', {
+					dataTransfer: dataTransferMock,
+					asPlainText: true,
+					stopPropagation() {},
+					preventDefault() {}
+				} );
+
+				expect( getModelData( model ) ).to.equal( '<paragraph><$text bold="true">Bolded foo[]text.</$text></paragraph>' );
+			} );
+
+			it( 'should discard selection attributes with data.asPlainText switch set to false', () => {
+				setModelData( model, '<paragraph><$text bold="true">Bolded []text.</$text></paragraph>' );
+
+				const dataTransferMock = createDataTransfer( {
+					'text/html': 'foo<br>bar',
+					'text/plain': 'foo\nbar'
+				} );
+
+				viewDocument.fire( 'clipboardInput', {
+					dataTransfer: dataTransferMock,
+					asPlainText: false,
+					stopPropagation() {},
+					preventDefault() {}
+				} );
+
+				expect( getModelData( model ) ).to.equal( '<paragraph><$text bold="true">Bolded </$text>' +
+					'foo<softBreak></softBreak>bar[]' +
+					'<$text bold="true">text.</$text></paragraph>' );
+			} );
 		} );
 
 		function createDataTransfer( data ) {