瀏覽代碼

Handled paste and drop events no longer propagate up DOM tree.

Kuba Niegowski 5 年之前
父節點
當前提交
744b90426d

+ 11 - 1
packages/ckeditor5-clipboard/src/clipboard.js

@@ -16,6 +16,7 @@ import normalizeClipboardHtml from './utils/normalizeclipboarddata';
 import viewToPlainText from './utils/viewtoplaintext.js';
 
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';
 
 /**
  * The clipboard feature. It is responsible for intercepting the `paste` and `drop` events and
@@ -75,7 +76,15 @@ export default class Clipboard extends Plugin {
 
 			content = this._htmlDataProcessor.toView( content );
 
-			this.fire( 'inputTransformation', { content, dataTransfer } );
+			const eventInfo = new EventInfo( this, 'inputTransformation' );
+			this.fire( eventInfo, { content, dataTransfer } );
+
+			// If CKEditor handled the input, do not bubble the original event any further.
+			// This helps external integrations recognize that fact and act accordingly.
+			// https://github.com/ckeditor/ckeditor5-upload/issues/92
+			if ( eventInfo.stop.called ) {
+				evt.stop();
+			}
 
 			view.scrollToTheSelection();
 		}, { priority: 'low' } );
@@ -95,6 +104,7 @@ export default class Clipboard extends Plugin {
 				}
 
 				model.insertContent( modelFragment );
+				evt.stop();
 			}
 		}, { priority: 'low' } );
 

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

@@ -8,6 +8,7 @@ import Clipboard from '../src/clipboard';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 
 import ClipboardObserver from '../src/clipboardobserver';
+import DataTransfer from '../src/datatransfer';
 
 import {
 	stringify as stringifyView,
@@ -176,6 +177,7 @@ describe( 'Clipboard feature', () => {
 
 			viewDocument.fire( 'paste', {
 				dataTransfer: dataTransferMock,
+				stopPropagation() {},
 				preventDefault() {}
 			} );
 
@@ -243,6 +245,7 @@ describe( 'Clipboard feature', () => {
 
 			viewDocument.fire( 'paste', {
 				dataTransfer: dataTransferMock,
+				stopPropagation() {},
 				preventDefault() {}
 			} );
 
@@ -294,6 +297,52 @@ describe( 'Clipboard feature', () => {
 			expect( spy.callCount ).to.equal( 0 );
 		} );
 
+		// https://github.com/ckeditor/ckeditor5-upload/issues/92
+		// https://github.com/ckeditor/ckeditor5/issues/6464
+		it( 'should stop propagation of the original event if CKEditor handled the input', () => {
+			const dataTransferMock = createDataTransfer( { 'text/html': 'x' } );
+			const spy = sinon.spy();
+
+			viewDocument.fire( 'paste', {
+				dataTransfer: dataTransferMock,
+				stopPropagation: spy,
+				preventDefault() {}
+			} );
+
+			expect( spy.callCount ).to.equal( 1 );
+		} );
+
+		// https://github.com/ckeditor/ckeditor5-upload/issues/92
+		// https://github.com/ckeditor/ckeditor5/issues/6464
+		it( 'should stop propagation of the original event if inputTransformation listener called stop (for file drop)', () => {
+			const fileMock = {
+				type: 'application/zip',
+				size: 1024
+			};
+			const dataTransferMock = new DataTransfer( { files: [ fileMock ], types: [ 'Files' ], getData: () => {} } );
+			const spy = sinon.spy();
+
+			viewDocument.fire( 'drop', {
+				dataTransfer: dataTransferMock,
+				stopPropagation: spy,
+				preventDefault() {}
+			} );
+
+			expect( spy.callCount ).to.equal( 0 );
+
+			clipboardPlugin.on( 'inputTransformation', evt => {
+				evt.stop();
+			} );
+
+			viewDocument.fire( 'paste', {
+				dataTransfer: dataTransferMock,
+				stopPropagation: spy,
+				preventDefault() {}
+			} );
+
+			expect( spy.callCount ).to.equal( 1 );
+		} );
+
 		function createDataTransfer( data ) {
 			return {
 				getData( type ) {

+ 1 - 0
packages/ckeditor5-clipboard/tests/pasting-integration.js

@@ -196,6 +196,7 @@ describe( 'Pasting – integration', () => {
 function pasteHtml( editor, html ) {
 	editor.editing.view.document.fire( 'paste', {
 		dataTransfer: createDataTransfer( { 'text/html': html } ),
+		stopPropagation() {},
 		preventDefault() {}
 	} );
 }