|
|
@@ -6,77 +6,238 @@
|
|
|
/* globals document */
|
|
|
|
|
|
import ClipboardObserver from '../src/clipboardobserver';
|
|
|
-import ViewDocument from '@ckeditor/ckeditor5-engine/src/view/document';
|
|
|
+import Document from '@ckeditor/ckeditor5-engine/src/view/document';
|
|
|
+import Element from '@ckeditor/ckeditor5-engine/src/view/element';
|
|
|
+import Range from '@ckeditor/ckeditor5-engine/src/view/range';
|
|
|
+import Position from '@ckeditor/ckeditor5-engine/src/view/position';
|
|
|
import DataTransfer from '../src/datatransfer';
|
|
|
|
|
|
describe( 'ClipboardObserver', () => {
|
|
|
- let viewDocument, observer;
|
|
|
+ let doc, observer, root, el, range, eventSpy, preventDefaultSpy;
|
|
|
|
|
|
beforeEach( () => {
|
|
|
- viewDocument = new ViewDocument();
|
|
|
- observer = viewDocument.addObserver( ClipboardObserver );
|
|
|
+ doc = new Document();
|
|
|
+ root = doc.createRoot( 'div' );
|
|
|
+
|
|
|
+ // Create view and DOM structures.
|
|
|
+ el = new Element( 'p' );
|
|
|
+ root.appendChildren( el );
|
|
|
+ doc.domConverter.viewToDom( root, document, { withChildren: true, bind: true } );
|
|
|
+
|
|
|
+ doc.selection.collapse( el );
|
|
|
+ range = new Range( new Position( root, 1 ) );
|
|
|
+ // Just making sure that the following tests will check anything.
|
|
|
+ expect( range.isEqual( doc.selection.getFirstRange() ) ).to.be.false;
|
|
|
+
|
|
|
+ observer = doc.addObserver( ClipboardObserver );
|
|
|
+
|
|
|
+ eventSpy = sinon.spy();
|
|
|
+ preventDefaultSpy = sinon.spy();
|
|
|
} );
|
|
|
|
|
|
it( 'should define domEventType', () => {
|
|
|
expect( observer.domEventType ).to.deep.equal( [ 'paste', 'copy', 'cut', 'drop' ] );
|
|
|
} );
|
|
|
|
|
|
- describe( 'onDomEvent', () => {
|
|
|
- let pasteSpy, preventDefaultSpy;
|
|
|
+ describe( 'paste event', () => {
|
|
|
+ it( 'should be fired with the right event data', () => {
|
|
|
+ const dataTransfer = mockDomDataTransfer();
|
|
|
+ const targetElement = mockDomTargetElement( {} );
|
|
|
|
|
|
- function getDataTransfer() {
|
|
|
- return {
|
|
|
- getData( type ) {
|
|
|
- return 'foo:' + type;
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- beforeEach( () => {
|
|
|
- pasteSpy = sinon.spy();
|
|
|
- preventDefaultSpy = sinon.spy();
|
|
|
- } );
|
|
|
-
|
|
|
- it( 'should fire paste with the right event data - clipboardData', () => {
|
|
|
- const dataTransfer = getDataTransfer();
|
|
|
-
|
|
|
- viewDocument.on( 'paste', pasteSpy );
|
|
|
+ doc.on( 'paste', eventSpy );
|
|
|
|
|
|
observer.onDomEvent( {
|
|
|
type: 'paste',
|
|
|
- target: document.body,
|
|
|
+ target: targetElement,
|
|
|
clipboardData: dataTransfer,
|
|
|
preventDefault: preventDefaultSpy
|
|
|
} );
|
|
|
|
|
|
- expect( pasteSpy.calledOnce ).to.be.true;
|
|
|
+ expect( eventSpy.calledOnce ).to.be.true;
|
|
|
+
|
|
|
+ const data = eventSpy.args[ 0 ][ 1 ];
|
|
|
+
|
|
|
+ expect( data.domTarget ).to.equal( targetElement );
|
|
|
|
|
|
- const data = pasteSpy.args[ 0 ][ 1 ];
|
|
|
- expect( data.domTarget ).to.equal( document.body );
|
|
|
expect( data.dataTransfer ).to.be.instanceOf( DataTransfer );
|
|
|
expect( data.dataTransfer.getData( 'x/y' ) ).to.equal( 'foo:x/y' );
|
|
|
+
|
|
|
expect( preventDefaultSpy.calledOnce ).to.be.true;
|
|
|
} );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'should fire paste with the right event data - dataTransfer', () => {
|
|
|
- const dataTransfer = getDataTransfer();
|
|
|
+ describe( 'drop event', () => {
|
|
|
+ it( 'should be fired with the right event data - basics', () => {
|
|
|
+ const dataTransfer = mockDomDataTransfer();
|
|
|
+ const targetElement = mockDomTargetElement( {} );
|
|
|
|
|
|
- viewDocument.on( 'drop', pasteSpy );
|
|
|
+ doc.on( 'drop', eventSpy );
|
|
|
|
|
|
observer.onDomEvent( {
|
|
|
type: 'drop',
|
|
|
- target: document.body,
|
|
|
+ target: targetElement,
|
|
|
dataTransfer,
|
|
|
preventDefault: preventDefaultSpy
|
|
|
} );
|
|
|
|
|
|
- expect( pasteSpy.calledOnce ).to.be.true;
|
|
|
+ expect( eventSpy.calledOnce ).to.be.true;
|
|
|
+
|
|
|
+ const data = eventSpy.args[ 0 ][ 1 ];
|
|
|
+
|
|
|
+ expect( data.domTarget ).to.equal( targetElement );
|
|
|
|
|
|
- const data = pasteSpy.args[ 0 ][ 1 ];
|
|
|
- expect( data.domTarget ).to.equal( document.body );
|
|
|
expect( data.dataTransfer ).to.be.instanceOf( DataTransfer );
|
|
|
expect( data.dataTransfer.getData( 'x/y' ) ).to.equal( 'foo:x/y' );
|
|
|
+
|
|
|
+ expect( data.dropRange.isEqual( doc.selection.getFirstRange() ) ).to.be.true;
|
|
|
+
|
|
|
expect( preventDefaultSpy.calledOnce ).to.be.true;
|
|
|
} );
|
|
|
+
|
|
|
+ it( 'should be fired with the right event data – dropRange (when no info about it in the drop event)', () => {
|
|
|
+ const dataTransfer = mockDomDataTransfer();
|
|
|
+ const targetElement = mockDomTargetElement( {} );
|
|
|
+
|
|
|
+ doc.on( 'drop', eventSpy );
|
|
|
+
|
|
|
+ observer.onDomEvent( {
|
|
|
+ type: 'drop',
|
|
|
+ target: targetElement,
|
|
|
+ dataTransfer,
|
|
|
+ preventDefault() {}
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( eventSpy.calledOnce ).to.be.true;
|
|
|
+
|
|
|
+ const data = eventSpy.args[ 0 ][ 1 ];
|
|
|
+
|
|
|
+ expect( data.dropRange.isEqual( doc.selection.getFirstRange() ) ).to.be.true;
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should be fired with the right event data – dropRange (when document.caretRangeFromPoint present)', () => {
|
|
|
+ let caretRangeFromPointCalledWith;
|
|
|
+
|
|
|
+ const domRange = doc.domConverter.viewRangeToDom( range );
|
|
|
+ const dataTransfer = mockDomDataTransfer();
|
|
|
+ const targetElement = mockDomTargetElement( {
|
|
|
+ caretRangeFromPoint( x, y ) {
|
|
|
+ caretRangeFromPointCalledWith = [ x, y ];
|
|
|
+
|
|
|
+ return domRange;
|
|
|
+ }
|
|
|
+ } );
|
|
|
+
|
|
|
+ doc.on( 'drop', eventSpy );
|
|
|
+
|
|
|
+ observer.onDomEvent( {
|
|
|
+ type: 'drop',
|
|
|
+ target: targetElement,
|
|
|
+ dataTransfer,
|
|
|
+ clientX: 10,
|
|
|
+ clientY: 20,
|
|
|
+ preventDefault() {}
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( eventSpy.calledOnce ).to.be.true;
|
|
|
+
|
|
|
+ const data = eventSpy.args[ 0 ][ 1 ];
|
|
|
+
|
|
|
+ expect( data.dropRange.isEqual( range ) ).to.be.true;
|
|
|
+ expect( caretRangeFromPointCalledWith ).to.deep.equal( [ 10, 20 ] );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should be fired with the right event data – dropRange (when evt.rangeParent|Offset present)', () => {
|
|
|
+ const domRange = doc.domConverter.viewRangeToDom( range );
|
|
|
+ const dataTransfer = mockDomDataTransfer();
|
|
|
+ const targetElement = mockDomTargetElement( {
|
|
|
+ createRange() {
|
|
|
+ return document.createRange();
|
|
|
+ }
|
|
|
+ } );
|
|
|
+
|
|
|
+ doc.on( 'drop', eventSpy );
|
|
|
+
|
|
|
+ observer.onDomEvent( {
|
|
|
+ type: 'drop',
|
|
|
+ target: targetElement,
|
|
|
+ dataTransfer,
|
|
|
+ rangeParent: domRange.startContainer,
|
|
|
+ rangeOffset: domRange.startOffset,
|
|
|
+ preventDefault() {}
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( eventSpy.calledOnce ).to.be.true;
|
|
|
+
|
|
|
+ const data = eventSpy.args[ 0 ][ 1 ];
|
|
|
+
|
|
|
+ expect( data.dropRange.isEqual( range ) ).to.be.true;
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'clipboardInput event', () => {
|
|
|
+ it( 'should be fired on paste', () => {
|
|
|
+ const dataTransfer = new DataTransfer( mockDomDataTransfer() );
|
|
|
+ const normalPrioritySpy = sinon.spy();
|
|
|
+
|
|
|
+ doc.on( 'clipboardInput', eventSpy );
|
|
|
+ doc.on( 'paste', normalPrioritySpy );
|
|
|
+
|
|
|
+ doc.fire( 'paste', {
|
|
|
+ dataTransfer,
|
|
|
+ preventDefault: preventDefaultSpy
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( eventSpy.calledOnce ).to.be.true;
|
|
|
+ expect( preventDefaultSpy.calledOnce ).to.be.true;
|
|
|
+
|
|
|
+ const data = eventSpy.args[ 0 ][ 1 ];
|
|
|
+ expect( data.dataTransfer ).to.equal( dataTransfer );
|
|
|
+
|
|
|
+ expect( data.targetRanges ).to.have.length( 1 );
|
|
|
+ expect( data.targetRanges[ 0 ].isEqual( doc.selection.getFirstRange() ) ).to.be.true;
|
|
|
+
|
|
|
+ expect( sinon.assert.callOrder( normalPrioritySpy, eventSpy ) );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'should be fired on drop', () => {
|
|
|
+ const dataTransfer = new DataTransfer( mockDomDataTransfer() );
|
|
|
+ const normalPrioritySpy = sinon.spy();
|
|
|
+
|
|
|
+ doc.on( 'clipboardInput', eventSpy );
|
|
|
+ doc.on( 'drop', normalPrioritySpy );
|
|
|
+
|
|
|
+ doc.fire( 'drop', {
|
|
|
+ dataTransfer,
|
|
|
+ preventDefault: preventDefaultSpy,
|
|
|
+ dropRange: range
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( eventSpy.calledOnce ).to.be.true;
|
|
|
+ expect( preventDefaultSpy.calledOnce ).to.be.true;
|
|
|
+
|
|
|
+ const data = eventSpy.args[ 0 ][ 1 ];
|
|
|
+ expect( data.dataTransfer ).to.equal( dataTransfer );
|
|
|
+
|
|
|
+ expect( data.targetRanges ).to.have.length( 1 );
|
|
|
+ expect( data.targetRanges[ 0 ].isEqual( range ) ).to.be.true;
|
|
|
+
|
|
|
+ expect( sinon.assert.callOrder( normalPrioritySpy, eventSpy ) );
|
|
|
+ } );
|
|
|
} );
|
|
|
} );
|
|
|
+
|
|
|
+// Returns a super simple mock of HTMLElement (we use only ownerDocument from it).
|
|
|
+function mockDomTargetElement( documentMock ) {
|
|
|
+ return {
|
|
|
+ ownerDocument: documentMock
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function mockDomDataTransfer() {
|
|
|
+ return {
|
|
|
+ files: [],
|
|
|
+ getData( type ) {
|
|
|
+ return 'foo:' + type;
|
|
|
+ }
|
|
|
+ };
|
|
|
+}
|