8
0
Pārlūkot izejas kodu

Merge pull request #166 from ckeditor/t/165

Feature: Introduced `Command#disable()` and `Command#enable()`. Closes #165.
Piotr Jasiun 6 gadi atpakaļ
vecāks
revīzija
e3473717ee

+ 48 - 4
packages/ckeditor5-core/src/command.js

@@ -96,6 +96,14 @@ export default class Command {
 		 */
 		this.set( 'isEnabled', false );
 
+		/**
+		 * Holds identifiers for {@link #disable}/{@link #enable} mechanism.
+		 *
+		 * @type {Set.<String>}
+		 * @private
+		 */
+		this._disableStack = new Set();
+
 		this.decorate( 'execute' );
 
 		// By default every command is refreshed when changes are applied to the model.
@@ -112,11 +120,9 @@ export default class Command {
 		// By default commands are disabled when the editor is in read-only mode.
 		this.listenTo( editor, 'change:isReadOnly', ( evt, name, value ) => {
 			if ( value ) {
-				this.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );
-				this.isEnabled = false;
+				this.disable( 'readOnlyMode' );
 			} else {
-				this.off( 'set:isEnabled', forceDisable );
-				this.refresh();
+				this.enable( 'readOnlyMode' );
 			}
 		} );
 	}
@@ -133,6 +139,44 @@ export default class Command {
 	}
 
 	/**
+	 * Disables the command.
+	 *
+	 * "Disable stack" is supported through identifiers. Command may be disabled by a multiple features/algorithms (at once).
+	 * When disabling a command, identifier is passed (and added to "disable stack"). The identifier is then used when
+	 * {@link #enable enabling back} the command. The command is actually enabled only after all features {@link #enable enabled it back}.
+	 *
+	 * Multiple disabling with the same identifier is redundant.
+	 *
+	 * **Note:** some algorithms may have more complex logic when it comes to enabling or disabling certain commands. Keep in mind
+	 * that disabling command is also possible through listening to {@link #isEnabled} change, so the command might be still disabled
+	 * even though "disable stack" is empty.
+	 *
+	 * @param {String} id "Disable stack" identifier. Use the same identifier when {@link #enable enabling back} the command.
+	 */
+	disable( id ) {
+		this._disableStack.add( id );
+
+		if ( this._disableStack.size == 1 ) {
+			this.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );
+			this.isEnabled = false;
+		}
+	}
+
+	/**
+	 * Enables the command previously disabled through {@link #disable}. See {@link #disable}.
+	 *
+	 * @param {String} id "Disable stack" identifier.
+	 */
+	enable( id ) {
+		this._disableStack.delete( id );
+
+		if ( this._disableStack.size == 0 ) {
+			this.off( 'set:isEnabled', forceDisable );
+			this.refresh();
+		}
+	}
+
+	/**
 	 * Executes the command.
 	 *
 	 * A command may accept parameters. They will be passed from {@link module:core/editor/editor~Editor#execute `editor.execute()`}

+ 45 - 0
packages/ckeditor5-core/tests/command.js

@@ -183,4 +183,49 @@ describe( 'Command', () => {
 			}
 		} );
 	} );
+
+	describe( 'disable() / enable()', () => {
+		it( 'disable() should disable the command', () => {
+			command.disable( 'foo' );
+			command.isEnabled = true;
+
+			expect( command.isEnabled ).to.be.false;
+		} );
+
+		it( 'enable() should enable the command', () => {
+			command.disable( 'foo' );
+			command.enable( 'foo' );
+
+			expect( command.isEnabled ).to.be.true;
+		} );
+
+		it( 'enable() used with wrong identifier should not enable the command', () => {
+			command.disable( 'foo' );
+			command.enable( 'bar' );
+			command.isEnabled = true;
+
+			expect( command.isEnabled ).to.be.false;
+		} );
+
+		it( 'using disable() twice with the same identifier should not have any effect', () => {
+			command.disable( 'foo' );
+			command.disable( 'foo' );
+			command.enable( 'foo' );
+
+			expect( command.isEnabled ).to.be.true;
+		} );
+
+		it( 'command is enabled only after whole disable stack is empty', () => {
+			command.disable( 'foo' );
+			command.disable( 'bar' );
+			command.enable( 'foo' );
+			command.isEnabled = true;
+
+			expect( command.isEnabled ).to.be.false;
+
+			command.enable( 'bar' );
+
+			expect( command.isEnabled ).to.be.true;
+		} );
+	} );
 } );