8
0
Просмотр исходного кода

Merge branch 'master' into i/5866-todo-list-conversion

Kuba Niegowski 5 лет назад
Родитель
Сommit
68a5b5f2dc

+ 57 - 0
packages/ckeditor5-engine/src/model/range.js

@@ -276,6 +276,63 @@ export default class Range {
 		return null;
 	}
 
+	/**
+	 * Returns a range created by joining this {@link ~Range range} with the given {@link ~Range range}.
+	 * If ranges have no common part, returns `null`.
+	 *
+	 * Examples:
+	 *
+	 *		let range = model.createRange(
+	 *			model.createPositionFromPath( root, [ 2, 7 ] ),
+	 *			model.createPositionFromPath( root, [ 4, 0, 1 ] )
+	 *		);
+	 *		let otherRange = model.createRange(
+	 *			model.createPositionFromPath( root, [ 1 ] ),
+	 *			model.createPositionFromPath( root, [ 2 ] )
+ 	 *		);
+	 *		let transformed = range.getJoined( otherRange ); // null - ranges have no common part
+	 *
+	 *		otherRange = model.createRange(
+	 *			model.createPositionFromPath( root, [ 3 ] ),
+	 *			model.createPositionFromPath( root, [ 5 ] )
+	 *		);
+	 *		transformed = range.getJoined( otherRange ); // range from [ 2, 7 ] to [ 5 ]
+	 *
+	 * @param {module:engine/model/range~Range} otherRange Range to be joined.
+	 * @param {Boolean} [loose=false] Whether the intersection check is loose or strict. If the check is strict (`false`),
+	 * ranges are tested for intersection or whether start/end positions are equal. If the check is loose (`true`),
+	 * compared range is also checked if it's {@link module:engine/model/position~Position#isTouching touching} current range.
+	 * @returns {module:engine/model/range~Range|null} A sum of given ranges or `null` if ranges have no common part.
+	 */
+	getJoined( otherRange, loose = false ) {
+		let shouldJoin = this.isIntersecting( otherRange );
+
+		if ( !shouldJoin ) {
+			if ( this.start.isBefore( otherRange.start ) ) {
+				shouldJoin = loose ? this.end.isTouching( otherRange.start ) : this.end.isEqual( otherRange.start );
+			} else {
+				shouldJoin = loose ? otherRange.end.isTouching( this.start ) : otherRange.end.isEqual( this.start );
+			}
+		}
+
+		if ( !shouldJoin ) {
+			return null;
+		}
+
+		let startPosition = this.start;
+		let endPosition = this.end;
+
+		if ( otherRange.start.isBefore( startPosition ) ) {
+			startPosition = otherRange.start;
+		}
+
+		if ( otherRange.end.isAfter( endPosition ) ) {
+			endPosition = otherRange.end;
+		}
+
+		return new Range( startPosition, endPosition );
+	}
+
 	/**
 	 * Computes and returns the smallest set of {@link #isFlat flat} ranges, that covers this range in whole.
 	 *

+ 110 - 0
packages/ckeditor5-engine/tests/model/range.js

@@ -789,6 +789,116 @@ describe( 'Range', () => {
 		} );
 	} );
 
+	describe( 'getJoined()', () => {
+		let range;
+
+		beforeEach( () => {
+			range = new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 5, 4 ] ) );
+		} );
+
+		it( 'should return null if ranges do not intersect nor have equal start/end', () => {
+			const otherRange = new Range( new Position( root, [ 5, 5 ] ), new Position( root, [ 7 ] ) );
+			const sum = range.getJoined( otherRange );
+
+			expect( sum ).to.be.null;
+		} );
+
+		it( 'should return a range spanning both of the ranges if the ranges have equal start/end positions', () => {
+			const otherRange = new Range( new Position( root, [ 5, 4 ] ), new Position( root, [ 7 ] ) );
+			const sum = range.getJoined( otherRange );
+
+			expect( sum.start.path ).to.deep.equal( [ 3, 2 ] );
+			expect( sum.end.path ).to.deep.equal( [ 7 ] );
+		} );
+
+		it( 'should return a range spanning both of the ranges if the ranges have equal start/end positions (different order)', () => {
+			const otherRange = new Range( new Position( root, [ 1, 4 ] ), new Position( root, [ 3, 2 ] ) );
+			const sum = range.getJoined( otherRange );
+
+			expect( sum.start.path ).to.deep.equal( [ 1, 4 ] );
+			expect( sum.end.path ).to.deep.equal( [ 5, 4 ] );
+		} );
+
+		it( 'should return a range spanning both of the ranges - original range contains the other range', () => {
+			const otherRange = new Range( new Position( root, [ 4 ] ), new Position( root, [ 5 ] ) );
+			const sum = range.getJoined( otherRange );
+
+			expect( sum.isEqual( range ) ).to.be.true;
+		} );
+
+		it( 'should return a range spanning both of the ranges - original range is contained by the other range', () => {
+			const otherRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 6 ] ) );
+			const sum = range.getJoined( otherRange );
+
+			expect( sum.isEqual( otherRange ) ).to.be.true;
+		} );
+
+		it( 'should return a range spanning both of the ranges - original range intersects with the other range', () => {
+			const otherRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 4, 7 ] ) );
+			const sum = range.getJoined( otherRange );
+
+			expect( sum.start.path ).to.deep.equal( [ 3 ] );
+			expect( sum.end.path ).to.deep.equal( [ 5, 4 ] );
+		} );
+
+		it( 'should return a range spanning both of the ranges if both ranges are equal', () => {
+			const otherRange = range.clone();
+			const sum = range.getJoined( otherRange );
+
+			expect( sum.isEqual( range ) ).to.be.true;
+		} );
+
+		describe( 'with `loose` option enabled', () => {
+			beforeEach( () => {
+				prepareRichRoot( root );
+			} );
+
+			it( 'should return null if ranges are not intersecting nor touching', () => {
+				const range = new Range( new Position( root, [ 0, 1 ] ), new Position( root, [ 3 ] ) );
+				const otherRange = new Range( new Position( root, [ 3, 1 ] ), new Position( root, [ 3, 2 ] ) );
+				const sum = range.getJoined( otherRange, true );
+
+				expect( sum ).to.be.null;
+			} );
+
+			it( 'should return a range spanning both of the ranges - original range end is equal to other range start position', () => {
+				const range = new Range( new Position( root, [ 0, 1 ] ), new Position( root, [ 3 ] ) );
+				const otherRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 3, 2 ] ) );
+				const sum = range.getJoined( otherRange, true );
+
+				expect( sum.start.path ).to.deep.equal( [ 0, 1 ] );
+				expect( sum.end.path ).to.deep.equal( [ 3, 2 ] );
+			} );
+
+			it( 'should return a range spanning both of the ranges - original range start is equal to other range end position', () => {
+				const range = new Range( new Position( root, [ 3 ] ), new Position( root, [ 3, 2 ] ) );
+				const otherRange = new Range( new Position( root, [ 0, 1 ] ), new Position( root, [ 3 ] ) );
+				const sum = range.getJoined( otherRange, true );
+
+				expect( sum.start.path ).to.deep.equal( [ 0, 1 ] );
+				expect( sum.end.path ).to.deep.equal( [ 3, 2 ] );
+			} );
+
+			it( 'should return a range spanning both of the ranges - original range is touching other range on the right side', () => {
+				const range = new Range( new Position( root, [ 0, 1 ] ), new Position( root, [ 3 ] ) );
+				const otherRange = new Range( new Position( root, [ 3, 0 ] ), new Position( root, [ 3, 2 ] ) );
+				const sum = range.getJoined( otherRange, true );
+
+				expect( sum.start.path ).to.deep.equal( [ 0, 1 ] );
+				expect( sum.end.path ).to.deep.equal( [ 3, 2 ] );
+			} );
+
+			it( 'should return a range spanning both of the ranges - original range is touching other range on the left side', () => {
+				const range = new Range( new Position( root, [ 1, 0 ] ), new Position( root, [ 3, 2 ] ) );
+				const otherRange = new Range( new Position( root, [ 0, 1 ] ), new Position( root, [ 0, 2 ] ) );
+				const sum = range.getJoined( otherRange, true );
+
+				expect( sum.start.path ).to.deep.equal( [ 0, 1 ] );
+				expect( sum.end.path ).to.deep.equal( [ 3, 2 ] );
+			} );
+		} );
+	} );
+
 	// Note: We don't create model element structure in these tests because this method
 	// is used by OT so it must not check the structure.
 	describe( 'getTransformedByOperation()', () => {

+ 0 - 5
packages/ckeditor5-table/src/commands/mergecellscommand.js

@@ -48,11 +48,6 @@ export default class MergeCellsCommand extends Command {
 			// All cells will be merged into the first one.
 			const firstTableCell = selectedTableCells.shift();
 
-			// Set the selection in cell that other cells are being merged to prevent model-selection-range-intersects error in undo.
-			// See https://github.com/ckeditor/ckeditor5/issues/6634.
-			// May be fixed by: https://github.com/ckeditor/ckeditor5/issues/6639.
-			writer.setSelection( firstTableCell, 0 );
-
 			// Update target cell dimensions.
 			const { mergeWidth, mergeHeight } = getMergeDimensions( firstTableCell, selectedTableCells, tableUtils );
 			updateNumericAttribute( 'colspan', mergeWidth, firstTableCell, writer );

+ 1 - 4
packages/ckeditor5-table/src/commands/removerowcommand.js

@@ -63,10 +63,7 @@ export default class RemoveRowCommand extends Command {
 		// Use single batch to modify table in steps but in one undo step.
 		const batch = model.createBatch();
 
-		model.enqueueChange( batch, writer => {
-			// This prevents the "model-selection-range-intersects" error, caused by removing row selected cells.
-			writer.setSelection( writer.createSelection( table, 'on' ) );
-
+		model.enqueueChange( batch, () => {
 			const rowsToRemove = removedRowIndexes.last - removedRowIndexes.first + 1;
 
 			this.editor.plugins.get( 'TableUtils' ).removeRows( table, {

+ 8 - 4
packages/ckeditor5-table/tests/tableselection-integration.js

@@ -18,7 +18,7 @@ import TableClipboard from '../src/tableclipboard';
 
 import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
-import { modelTable } from './_utils/utils';
+import { assertSelectedCells, modelTable } from './_utils/utils';
 import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';
 import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
@@ -227,7 +227,6 @@ describe( 'TableSelection - integration', () => {
 			await setupEditor( [ UndoEditing ] );
 		} );
 
-		// See https://github.com/ckeditor/ckeditor5/issues/6634.
 		it( 'works with merge cells command', () => {
 			setModelData( editor.model, modelTable( [
 				[ '00', '01' ],
@@ -248,10 +247,15 @@ describe( 'TableSelection - integration', () => {
 
 			editor.execute( 'undo' );
 
-			assertEqualMarkup( getModelData( model ), modelTable( [
-				[ '[]00', '01' ],
+			assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
+				[ '00', '01' ],
 				[ '10', '11' ]
 			] ) );
+
+			assertSelectedCells( model, [
+				[ 1, 1 ],
+				[ 0, 0 ]
+			] );
 		} );
 	} );
 

+ 2 - 1
packages/ckeditor5-undo/package.json

@@ -22,7 +22,8 @@
     "@ckeditor/ckeditor5-heading": "^20.0.0",
     "@ckeditor/ckeditor5-paragraph": "^20.0.0",
     "@ckeditor/ckeditor5-typing": "^20.0.0",
-    "@ckeditor/ckeditor5-utils": "^20.0.0"
+    "@ckeditor/ckeditor5-utils": "^20.0.0",
+    "@ckeditor/ckeditor5-table": "^20.0.0"
   },
   "engines": {
     "node": ">=12.0.0",

+ 30 - 23
packages/ckeditor5-undo/src/basecommand.js

@@ -93,15 +93,23 @@ export default class BaseCommand extends Command {
 		const selectionRanges = [];
 
 		// Transform all ranges from the restored selection.
-		for ( const range of ranges ) {
-			const transformed = transformSelectionRange( range, operations );
+		const transformedRangeGroups = ranges.map( range => range.getTransformedByOperations( operations ) );
+		const allRanges = transformedRangeGroups.flat();
+
+		for ( const rangeGroup of transformedRangeGroups ) {
+			// While transforming there could appear ranges that are contained by other ranges, we shall ignore them.
+			const transformed = rangeGroup.filter( range => !isRangeContainedByAnyOtherRange( range, allRanges ) );
+
+			// After the range got transformed, we have an array of ranges. Some of those
+			// ranges may be "touching" -- they can be next to each other and could be merged.
+			normalizeRanges( transformed );
 
 			// For each `range` from `ranges`, we take only one transformed range.
 			// This is because we want to prevent situation where single-range selection
 			// got transformed to multi-range selection. We will take the first range that
 			// is not in the graveyard.
 			const newRange = transformed.find(
-				range => range.start.root != document.graveyard
+				range => range.root != document.graveyard
 			);
 
 			// `transformedRange` might be `undefined` if transformed range ended up in graveyard.
@@ -110,6 +118,8 @@ export default class BaseCommand extends Command {
 			}
 		}
 
+		// @if CK_DEBUG_ENGINE // console.log( `Restored selection by undo: ${ selectionRanges.join( ', ' ) }` );
+
 		// `selectionRanges` may be empty if all ranges ended up in graveyard. If that is the case, do not restore selection.
 		if ( selectionRanges.length ) {
 			model.change( writer => {
@@ -167,28 +177,25 @@ export default class BaseCommand extends Command {
 	}
 }
 
-// Transforms given range `range` by given `operations`.
-// Returns an array containing one or more ranges, which are result of the transformation.
-function transformSelectionRange( range, operations ) {
-	const transformed = range.getTransformedByOperations( operations );
-
-	// After `range` got transformed, we have an array of ranges. Some of those
-	// ranges may be "touching" -- they can be next to each other and could be merged.
-	// First, we have to sort those ranges to assure that they are in order.
-	transformed.sort( ( a, b ) => a.start.isBefore( b.start ) ? -1 : 1 );
-
-	// Then, we check if two consecutive ranges are touching.
-	for ( let i = 1; i < transformed.length; i++ ) {
-		const a = transformed[ i - 1 ];
-		const b = transformed[ i ];
-
-		if ( a.end.isTouching( b.start ) ) {
-			// And join them together if they are.
-			a.end = b.end;
-			transformed.splice( i, 1 );
+// Normalizes list of ranges by joining intersecting or "touching" ranges.
+//
+// @param {Array.<module:engine/model/range~Range>} ranges
+//
+function normalizeRanges( ranges ) {
+	ranges.sort( ( a, b ) => a.start.isBefore( b.start ) ? -1 : 1 );
+
+	for ( let i = 1; i < ranges.length; i++ ) {
+		const previousRange = ranges[ i - 1 ];
+		const joinedRange = previousRange.getJoined( ranges[ i ], true );
+
+		if ( joinedRange ) {
+			// Replace the ranges on the list with the new joined range.
 			i--;
+			ranges.splice( i, 2, joinedRange );
 		}
 	}
+}
 
-	return transformed;
+function isRangeContainedByAnyOtherRange( range, ranges ) {
+	return ranges.some( otherRange => otherRange !== range && otherRange.containsRange( range, true ) );
 }

+ 86 - 7
packages/ckeditor5-undo/tests/undoediting-integration.js

@@ -15,6 +15,7 @@ import Typing from '@ckeditor/ckeditor5-typing/src/typing';
 import Enter from '@ckeditor/ckeditor5-enter/src/enter';
 import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
 import BoldEditing from '@ckeditor/ckeditor5-basic-styles/src/bold/boldediting';
+import TableEditing from '@ckeditor/ckeditor5-table/src/tableediting';
 
 import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
@@ -25,15 +26,16 @@ describe( 'UndoEditing integration', () => {
 		div = document.createElement( 'div' );
 		document.body.appendChild( div );
 
-		return ClassicEditor.create( div, { plugins: [ Paragraph, HeadingEditing, Typing, Enter, Clipboard, BoldEditing, UndoEditing ] } )
-			.then( newEditor => {
-				editor = newEditor;
+		return ClassicEditor.create( div, {
+			plugins: [ Paragraph, HeadingEditing, Typing, Enter, Clipboard, BoldEditing, UndoEditing, TableEditing ]
+		} ).then( newEditor => {
+			editor = newEditor;
 
-				model = editor.model;
-				doc = model.document;
+			model = editor.model;
+			doc = model.document;
 
-				root = doc.getRoot();
-			} );
+			root = doc.getRoot();
+		} );
 	} );
 
 	afterEach( () => {
@@ -1021,6 +1023,83 @@ describe( 'UndoEditing integration', () => {
 			expect( p.root ).to.equal( gy );
 			expect( p.getAttribute( 'bold' ) ).to.be.true;
 		} );
+
+		it( 'undo table cells merge', () => {
+			input(
+				'<table>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>00</paragraph></tableCell>' +
+						'[<tableCell><paragraph>01</paragraph></tableCell>]' +
+						'[<tableCell><paragraph>02</paragraph></tableCell>]' +
+						'<tableCell><paragraph>03</paragraph></tableCell>' +
+					'</tableRow>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>10</paragraph></tableCell>' +
+						'[<tableCell><paragraph>11</paragraph></tableCell>]' +
+						'[<tableCell><paragraph>12</paragraph></tableCell>]' +
+						'<tableCell><paragraph>13</paragraph></tableCell>' +
+					'</tableRow>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>20</paragraph></tableCell>' +
+						'<tableCell><paragraph>21</paragraph></tableCell>' +
+						'<tableCell><paragraph>22</paragraph></tableCell>' +
+						'<tableCell><paragraph>23</paragraph></tableCell>' +
+					'</tableRow>' +
+				'</table>'
+			);
+
+			editor.execute( 'mergeTableCells' );
+
+			output(
+				'<table>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>00</paragraph></tableCell>' +
+						'<tableCell colspan="2" rowspan="2">' +
+							'<paragraph>[01</paragraph>' +
+							'<paragraph>02</paragraph>' +
+							'<paragraph>11</paragraph>' +
+							'<paragraph>12]</paragraph>' +
+						'</tableCell>' +
+						'<tableCell><paragraph>03</paragraph></tableCell>' +
+					'</tableRow>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>10</paragraph></tableCell>' +
+						'<tableCell><paragraph>13</paragraph></tableCell>' +
+					'</tableRow>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>20</paragraph></tableCell>' +
+						'<tableCell><paragraph>21</paragraph></tableCell>' +
+						'<tableCell><paragraph>22</paragraph></tableCell>' +
+						'<tableCell><paragraph>23</paragraph></tableCell>' +
+					'</tableRow>' +
+				'</table>'
+			);
+
+			editor.execute( 'undo' );
+
+			output(
+				'<table>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>00</paragraph></tableCell>' +
+						'[<tableCell><paragraph>01</paragraph></tableCell>]' +
+						'[<tableCell><paragraph>02</paragraph></tableCell>]' +
+						'<tableCell><paragraph>03</paragraph></tableCell>' +
+					'</tableRow>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>10</paragraph></tableCell>' +
+						'[<tableCell><paragraph>11</paragraph></tableCell>]' +
+						'[<tableCell><paragraph>12</paragraph></tableCell>]' +
+						'<tableCell><paragraph>13</paragraph></tableCell>' +
+					'</tableRow>' +
+					'<tableRow>' +
+						'<tableCell><paragraph>20</paragraph></tableCell>' +
+						'<tableCell><paragraph>21</paragraph></tableCell>' +
+						'<tableCell><paragraph>22</paragraph></tableCell>' +
+						'<tableCell><paragraph>23</paragraph></tableCell>' +
+					'</tableRow>' +
+				'</table>'
+			);
+		} );
 	} );
 
 	it( 'postfixers should not add another undo step when fixing undo changes', () => {

+ 13 - 4
packages/ckeditor5-widget/src/widgetresize.js

@@ -12,6 +12,7 @@ import Resizer from './widgetresize/resizer';
 import DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
+import MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import { throttle } from 'lodash-es';
 
@@ -71,12 +72,13 @@ export default class WidgetResize extends Plugin {
 			isFormatting: true
 		} );
 
+		this.editor.editing.view.addObserver( MouseObserver );
+
 		this._observer = Object.create( DomEmitterMixin );
 
-		this._observer.listenTo( domDocument, 'mousedown', this._mouseDownListener.bind( this ) );
+		this.listenTo( this.editor.editing.view.document, 'mousedown', this._mouseDownListener.bind( this ), { priority: 'high' } );
 
 		this._observer.listenTo( domDocument, 'mousemove', this._mouseMoveListener.bind( this ) );
-
 		this._observer.listenTo( domDocument, 'mouseup', this._mouseUpListener.bind( this ) );
 
 		const redrawFocusedResizer = () => {
@@ -182,13 +184,20 @@ export default class WidgetResize extends Plugin {
 	 * @param {Event} domEventData Native DOM event.
 	 */
 	_mouseDownListener( event, domEventData ) {
-		if ( !Resizer.isResizeHandle( domEventData.target ) ) {
+		const resizeHandle = domEventData.domTarget;
+
+		if ( !Resizer.isResizeHandle( resizeHandle ) ) {
 			return;
 		}
-		const resizeHandle = domEventData.target;
+
 		this._activeResizer = this._getResizerByHandle( resizeHandle );
+
 		if ( this._activeResizer ) {
 			this._activeResizer.begin( resizeHandle );
+
+			// Do not call other events when resizing. See: #6755.
+			event.stop();
+			domEventData.preventDefault();
 		}
 	}
 

+ 55 - 0
packages/ckeditor5-widget/tests/widgetresize-integration.js

@@ -0,0 +1,55 @@
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* global document, Event */
+
+import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+
+import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import Image from '@ckeditor/ckeditor5-image/src/image';
+import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';
+
+describe( 'WidgetResize - integration', () => {
+	let editor, model, view, viewDocument, editorElement;
+
+	testUtils.createSinonSandbox();
+
+	beforeEach( () => {
+		editorElement = document.createElement( 'div' );
+		document.body.appendChild( editorElement );
+
+		return ClassicEditor.create( editorElement, { plugins: [ Image, ImageResize ] } )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				view = editor.editing.view;
+				viewDocument = view.document;
+			} );
+	} );
+
+	afterEach( () => {
+		editorElement.remove();
+
+		return editor.destroy();
+	} );
+
+	it( 'should not fire viewDocument#mousedown events after starting resizing', () => {
+		const eventSpy = sinon.spy().named( 'ViewDocument#mousedown' );
+
+		setModelData( model, '[<image src="/assets/sample.png"></image>]' );
+
+		const resizeSquareUI = [ ...viewDocument.getRoot().getChild( 0 ).getChildren() ]
+			.find( element => element.hasClass( 'ck-widget__resizer' ) );
+
+		const squareDomElement = view.domConverter.mapViewToDom( resizeSquareUI ).querySelector( '.ck-widget__resizer__handle-top-left' );
+
+		viewDocument.on( 'mousedown', eventSpy );
+
+		squareDomElement.dispatchEvent( new Event( 'mousedown' ) );
+
+		expect( eventSpy.called ).to.equal( false );
+	} );
+} );

+ 22 - 1
packages/ckeditor5-widget/tests/widgetresize.js

@@ -72,7 +72,8 @@ describe( 'WidgetResize', () => {
 			const unrelatedElement = document.createElement( 'div' );
 
 			editor.plugins.get( WidgetResize )._mouseDownListener( {}, {
-				target: unrelatedElement
+				domTarget: unrelatedElement,
+				preventDefault: sinon.spy()
 			} );
 		} );
 
@@ -114,6 +115,26 @@ describe( 'WidgetResize', () => {
 			resizerMouseSimulator.dragTo( editor, domParts.resizeHandle, initialPointerPosition );
 			// No exception should be thrown.
 		} );
+
+		it( 'stops the event after starting resizing', () => {
+			const stopSpy = sinon.spy().named( 'stop' );
+
+			const domParts = getWidgetDomParts( editor, widget, 'top-right' );
+
+			resizerMouseSimulator.down( editor, domParts.resizeHandle, { stop: stopSpy } );
+
+			expect( stopSpy.called ).to.be.equal( true );
+		} );
+
+		it( 'prevents default action after starting resizing', () => {
+			const preventDefaultSpy = sinon.spy().named( 'preventDefault' );
+
+			const domParts = getWidgetDomParts( editor, widget, 'top-right' );
+
+			resizerMouseSimulator.down( editor, domParts.resizeHandle, { preventDefault: preventDefaultSpy } );
+
+			expect( preventDefaultSpy.called ).to.be.equal( true );
+		} );
 	} );
 
 	describe( 'visibility', () => {

+ 5 - 4
packages/ckeditor5-widget/tests/widgetresize/_utils/utils.js

@@ -8,10 +8,11 @@ import WidgetResize from '../../../src/widgetresize';
 import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';
 
 export const resizerMouseSimulator = {
-	down( editor, domTarget ) {
-		this._getPlugin( editor )._mouseDownListener( {}, {
-			target: domTarget
-		} );
+	down( editor, domTarget, options = {} ) {
+		const preventDefault = options.preventDefault || sinon.spy().named( 'preventDefault' );
+		const stop = options.stop || sinon.spy().named( 'stop' );
+
+		this._getPlugin( editor )._mouseDownListener( { stop }, { domTarget, preventDefault } );
 	},
 
 	/**