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

Disabled two-steps movement when shift key is pressed.

Oskar Wróbel 8 лет назад
Родитель
Сommit
76d13cc63a

+ 5 - 0
packages/ckeditor5-engine/src/utils/bindtwostepcarettoattribute.js

@@ -53,6 +53,11 @@ export default function bindTwoStepCaretToAttribute( view, model, emitter, attri
 			return;
 			return;
 		}
 		}
 
 
+		// User tries to expand selection, so two-steps movement is not necessary.
+		if ( data.shiftKey ) {
+			return;
+		}
+
 		const position = modelSelection.getFirstPosition();
 		const position = modelSelection.getFirstPosition();
 
 
 		// Moving right.
 		// Moving right.

+ 0 - 1
packages/ckeditor5-engine/tests/manual/twostepscarret.md

@@ -45,6 +45,5 @@
 ### Moving from one bound attribute to another
 ### Moving from one bound attribute to another
 1. Make sure that moving between underline and italic text from second paragraph works the same way as above.
 1. Make sure that moving between underline and italic text from second paragraph works the same way as above.
 
 
-
 ### Not bounded attribute
 ### Not bounded attribute
 Just make sure that two-steps caret movement is disabled for bold text from the third paragraph.
 Just make sure that two-steps caret movement is disabled for bold text from the third paragraph.

+ 49 - 39
packages/ckeditor5-engine/tests/utils/bindtwostepcarettoattribute.js

@@ -10,7 +10,6 @@ import DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
 import bindTwoStepCaretToAttribute from '../../src/utils/bindtwostepcarettoattribute';
 import bindTwoStepCaretToAttribute from '../../src/utils/bindtwostepcarettoattribute';
 import Position from '../../src/model/position';
 import Position from '../../src/model/position';
 import Range from '../../src/model/range';
 import Range from '../../src/model/range';
-import DomEventData from '../../src/view/observer/domeventdata';
 import { upcastElementToAttribute } from '../../src/conversion/upcast-converters';
 import { upcastElementToAttribute } from '../../src/conversion/upcast-converters';
 import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 
 
@@ -55,10 +54,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
 
 
 			// Press right key.
 			// Press right key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Gravity is overridden, caret movement is blocked, selection at the beginning but "inside" the text.
 			// Gravity is overridden, caret movement is blocked, selection at the beginning but "inside" the text.
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'a', 'b' ] );
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'a', 'b' ] );
@@ -66,10 +65,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
 
 
 			// Press right key.
 			// Press right key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
@@ -83,10 +82,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
 
 
 			// Press right key.
 			// Press right key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Gravity is overridden, caret movement is blocked, selection at the end but "outside" the text.
 			// Gravity is overridden, caret movement is blocked, selection at the end but "outside" the text.
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'c' ] );
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'c' ] );
@@ -94,10 +93,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
 
 
 			// Press right key.
 			// Press right key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
@@ -106,10 +105,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 		it( 'should do nothing for not bound attribute (at the beginning)', () => {
 		it( 'should do nothing for not bound attribute (at the beginning)', () => {
 			setData( model, '[]<$text c="true">foo</$text>' );
 			setData( model, '[]<$text c="true">foo</$text>' );
 
 
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			sinon.assert.notCalled( preventDefaultSpy );
 			sinon.assert.notCalled( preventDefaultSpy );
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
@@ -118,10 +117,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 		it( 'should do nothing for not bound attribute (at the end)', () => {
 		it( 'should do nothing for not bound attribute (at the end)', () => {
 			setData( model, '<$text c="true">foo[]</$text>' );
 			setData( model, '<$text c="true">foo[]</$text>' );
 
 
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			sinon.assert.notCalled( preventDefaultSpy );
 			sinon.assert.notCalled( preventDefaultSpy );
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
@@ -134,10 +133,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
 
 
 			// Press right key.
 			// Press right key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Gravity is overridden, caret movement is blocked.
 			// Gravity is overridden, caret movement is blocked.
 			expect( selection.isGravityOverridden ).to.true;
 			expect( selection.isGravityOverridden ).to.true;
@@ -154,10 +153,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
 
 
 			// Press left key.
 			// Press left key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowleft,
 				keyCode: keyCodes.arrowleft,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Caret movement was not blocked.
 			// Caret movement was not blocked.
 			sinon.assert.notCalled( preventDefaultSpy );
 			sinon.assert.notCalled( preventDefaultSpy );
@@ -171,10 +170,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.true;
 			expect( selection.isGravityOverridden ).to.true;
 
 
 			// Press left key.
 			// Press left key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowleft,
 				keyCode: keyCodes.arrowleft,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Caret movement was blocked but now is "inside" the text.
 			// Caret movement was blocked but now is "inside" the text.
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'a', 'b' ] );
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'a', 'b' ] );
@@ -182,10 +181,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
 
 
 			// Press left key.
 			// Press left key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowleft,
 				keyCode: keyCodes.arrowleft,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
@@ -203,10 +202,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
 
 
 			// Press left key.
 			// Press left key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowleft,
 				keyCode: keyCodes.arrowleft,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Caret movement was not blocked.
 			// Caret movement was not blocked.
 			sinon.assert.notCalled( preventDefaultSpy );
 			sinon.assert.notCalled( preventDefaultSpy );
@@ -220,10 +219,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.true;
 			expect( selection.isGravityOverridden ).to.true;
 
 
 			// Press left key.
 			// Press left key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowleft,
 				keyCode: keyCodes.arrowleft,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Gravity is not overridden, caret movement was blocked but now is "outside" the text.
 			// Gravity is not overridden, caret movement was blocked but now is "outside" the text.
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'c' ] );
 			expect( Array.from( selection.getAttributeKeys() ) ).to.have.members( [ 'c' ] );
@@ -231,10 +230,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
 
 
 			// Press left key.
 			// Press left key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowleft,
 				keyCode: keyCodes.arrowleft,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			// Caret movement was not blocked this time (still once) so everything works normally.
 			sinon.assert.calledOnce( preventDefaultSpy );
 			sinon.assert.calledOnce( preventDefaultSpy );
@@ -243,10 +242,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 		it( 'should do nothing for not bound attribute (at the beginning)', () => {
 		it( 'should do nothing for not bound attribute (at the beginning)', () => {
 			setData( model, '<$text c="true">[]foo</$text>' );
 			setData( model, '<$text c="true">[]foo</$text>' );
 
 
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			sinon.assert.notCalled( preventDefaultSpy );
 			sinon.assert.notCalled( preventDefaultSpy );
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
@@ -255,10 +254,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 		it( 'should do nothing for not bound attribute (at the end)', () => {
 		it( 'should do nothing for not bound attribute (at the end)', () => {
 			setData( model, '<$text c="true">foo</$text>[]' );
 			setData( model, '<$text c="true">foo</$text>[]' );
 
 
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowright,
 				keyCode: keyCodes.arrowright,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			sinon.assert.notCalled( preventDefaultSpy );
 			sinon.assert.notCalled( preventDefaultSpy );
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
@@ -268,7 +267,7 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			setData( model, '[]foo', { lastRangeBackward: true } );
 			setData( model, '[]foo', { lastRangeBackward: true } );
 
 
 			expect( () => {
 			expect( () => {
-				viewDoc.fire( 'keydown', getEventData( { keyCode: keyCodes.arrowleft } ) );
+				fireKeyDownEvent( { keyCode: keyCodes.arrowleft } );
 			} ).to.not.throw();
 			} ).to.not.throw();
 		} );
 		} );
 
 
@@ -279,10 +278,10 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 			expect( selection.isGravityOverridden ).to.false;
 			expect( selection.isGravityOverridden ).to.false;
 
 
 			// Press left key.
 			// Press left key.
-			viewDoc.fire( 'keydown', getEventData( {
+			fireKeyDownEvent( {
 				keyCode: keyCodes.arrowleft,
 				keyCode: keyCodes.arrowleft,
 				preventDefault: preventDefaultSpy
 				preventDefault: preventDefaultSpy
-			} ) );
+			} );
 
 
 			// Gravity is overridden, caret movement was not blocked.
 			// Gravity is overridden, caret movement was not blocked.
 			sinon.assert.notCalled( preventDefaultSpy );
 			sinon.assert.notCalled( preventDefaultSpy );
@@ -308,21 +307,32 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 		setData( model, '<$text a="true">foo[]</$text>' );
 		setData( model, '<$text a="true">foo[]</$text>' );
 
 
 		expect( () => {
 		expect( () => {
-			viewDoc.fire( 'keydown', getEventData( { keyCode: keyCodes.arrowup } ) );
+			fireKeyDownEvent( { keyCode: keyCodes.arrowup } );
 		} ).to.not.throw();
 		} ).to.not.throw();
 	} );
 	} );
 
 
 	it( 'should do nothing for non-collapsed selection', () => {
 	it( 'should do nothing for non-collapsed selection', () => {
 		setData( model, '<$text c="true">fo[o]</$text><$text a="true" b="true">bar</$text>' );
 		setData( model, '<$text c="true">fo[o]</$text><$text a="true" b="true">bar</$text>' );
 
 
-		viewDoc.fire( 'keydown', getEventData( { keyCode: keyCodes.arrowright } ) );
+		fireKeyDownEvent( { keyCode: keyCodes.arrowright } );
+
+		expect( selection.isGravityOverridden ).to.false;
+	} );
+
+	it( 'should do nothing when shift key is pressed', () => {
+		setData( model, '<$text c="true">foo</$text><$text a="true" b="true">b[]ar</$text>' );
+
+		fireKeyDownEvent( {
+			keyCode: keyCodes.arrowleft,
+			shiftKey: true
+		} );
 
 
 		expect( selection.isGravityOverridden ).to.false;
 		expect( selection.isGravityOverridden ).to.false;
 	} );
 	} );
 
 
-	function getEventData( data ) {
-		data.target = document.body;
+	function fireKeyDownEvent( options ) {
+		const eventData = Object.assign( { domTarget: document.body }, options );
 
 
-		return new DomEventData( viewDoc, data, { keyCode: data.keyCode } );
+		viewDoc.fire( 'keydown', eventData );
 	}
 	}
 } );
 } );