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

Added option that allows to control when overridden gravity should be restored.

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

+ 17 - 10
packages/ckeditor5-engine/src/model/documentselection.js

@@ -394,17 +394,20 @@ export default class DocumentSelection {
 
 	/**
 	 * Temporarily and partially disables default gravity behaviour that tries to get attributes from nodes surrounding the caret.
-	 * @see module:engine/model/writer~Writer#overrideGravity
 	 *
+	 * @see module:engine/model/writer~Writer#overrideGravity
 	 * @protected
+	 * @param {Function} [customRestorer] A callback function that allows to control when default gravity should be restored.
+	 * Callback takes function as a param that allow to restore the gravity.
 	 */
-	_overrideGravity() {
-		this._selection.overrideGravity();
+	_overrideGravity( customRestorer ) {
+		this._selection.overrideGravity( customRestorer );
 	}
 
 	/**
 	 * Restore overridden gravity.
 	 *
+	 * @see module:engine/model/writer~Writer#restoreSelectionGravity
 	 * @protected
 	 */
 	_restoreGravity() {
@@ -631,15 +634,19 @@ class LiveSelection extends Selection {
 		}
 	}
 
-	overrideGravity() {
+	overrideGravity( customRestorer ) {
 		this._isGravityOverriden = true;
 
-		this.on( 'change:range', ( evt, data ) => {
-			if ( data.directChange ) {
-				this._isGravityOverriden = false;
-				evt.off();
-			}
-		} );
+		if ( typeof customRestorer == 'function' ) {
+			customRestorer( this.restoreGravity.bind( this ) );
+		} else {
+			this.on( 'change:range', ( evt, data ) => {
+				if ( data.directChange ) {
+					this._isGravityOverriden = false;
+					evt.off();
+				}
+			} );
+		}
 
 		this._updateAttributes();
 	}

+ 16 - 5
packages/ckeditor5-engine/src/model/writer.js

@@ -1017,9 +1017,10 @@ export default class Writer {
 	}
 
 	/**
-	 * Temporarily (until selection won't be changed directly by the user) disables default gravity behaviour that tries
-	 * to get attributes from nodes surrounding the caret. When gravity is marked as overridden then attributes from the
-	 * node before the caret won't be taken into consideration while updating selection attributes.
+	 * Temporarily (until selection won't be changed directly by the user or using `customRestorer`) disables default
+	 * gravity behaviour that tries to get attributes from nodes surrounding the caret. When gravity is marked
+	 * as overridden then attributes from the node before the caret won't be taken into consideration while
+	 * updating selection attributes.
 	 *
 	 * For the following model fragment:
 	 *
@@ -1027,9 +1028,19 @@ export default class Writer {
 	 *
 	 * Selection attribute keys before override will be equal `[ 'bold', 'linkHref' ]`
 	 * Selection attribute keys after override will be equal `[ 'bold' ]`
+	 *
+	 * As default gravity is restored just after a direct {@link module:model/documentselection~DocumentSelection#change:range} event
+	 * but it could be customised using `customRestorer` callback:
+	 *
+	 * 		model.change( writer => {
+	 * 			writer.overrideSelectionGravity( restore => // and gravity won't be restored until `restore` callback won't be called ).
+	 * 		} );
+	 *
+	 * @param {Function} [customRestorer] A callback function that allows to control when default gravity should be restored.
+	 * Callback takes function as a param that allow to restore the gravity.
 	 */
-	overrideSelectionGravity() {
-		this.model.document.selection._overrideGravity();
+	overrideSelectionGravity( customRestorer ) {
+		this.model.document.selection._overrideGravity( customRestorer );
 	}
 
 	/**

+ 29 - 2
packages/ckeditor5-engine/tests/model/writer.js

@@ -2372,11 +2372,38 @@ describe( 'Writer', () => {
 			overrideSelectionGravity();
 
 			expect( Array.from( model.document.selection.getAttributeKeys() ) ).to.deep.equal( [ 'foo' ] );
+			expect( model.document.selection.isGravityOverridden ).to.true;
 
 			// Disable override by moving selection.
 			setSelection( new Position( root, [ 5 ] ) );
 
 			expect( Array.from( model.document.selection.getAttributeKeys() ) ).to.deep.equal( [ 'foo', 'bar' ] );
+			expect( model.document.selection.isGravityOverridden ).to.false;
+		} );
+
+		it( 'should allow to use custom restorer callback', () => {
+			const root = doc.createRoot();
+			root.appendChildren( [ new Text( 'foobar', { foo: true } ) ] );
+
+			setSelection( new Position( root, [ 1 ] ) );
+
+			overrideSelectionGravity( restore => {
+				let i = 0;
+
+				model.document.selection.on( 'change:range', () => {
+					if ( i++ > 0 ) {
+						restore();
+					}
+				} );
+			} );
+
+			// Moving selection for the first time does not restore.
+			setSelection( new Position( root, [ 2 ] ) );
+			expect( model.document.selection.isGravityOverridden ).to.true;
+
+			// Second move does.
+			setSelection( new Position( root, [ 1 ] ) );
+			expect( model.document.selection.isGravityOverridden ).to.false;
 		} );
 	} );
 
@@ -2570,9 +2597,9 @@ describe( 'Writer', () => {
 		} );
 	}
 
-	function overrideSelectionGravity() {
+	function overrideSelectionGravity( customRestorer ) {
 		model.change( writer => {
-			writer.overrideSelectionGravity();
+			writer.overrideSelectionGravity( customRestorer );
 		} );
 	}