Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #208 from ckeditor/i/5862
Browse files Browse the repository at this point in the history
Feature: Introduced `Plugin#isEnabled`, `Plugin#forceDisabled()` and `Plugin#clearForceDisabled()`.
  • Loading branch information
jodator committed Jan 27, 2020
2 parents ada4a79 + 14e070b commit 7449450
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/plugin.js
Expand Up @@ -38,6 +38,90 @@ export default class Plugin {
* @member {module:core/editor/editor~Editor} #editor
*/
this.editor = editor;

/**
* Flag indicating whether a plugin is enabled or disabled.
* A disabled plugin will not transform text.
*
* Plugin can be simply disabled like that:
*
* // Disable the plugin so that no toolbars are visible.
* editor.plugins.get( 'TextTransformation' ).isEnabled = false;
*
* You can also use {@link #forceDisabled} method.
*
* @observable
* @readonly
* @member {Boolean} #isEnabled
*/
this.set( 'isEnabled', true );

/**
* Holds identifiers for {@link #forceDisabled} mechanism.
*
* @type {Set.<String>}
* @private
*/
this._disableStack = new Set();
}

/**
* Disables the plugin.
*
* Plugin may be disabled by multiple features or algorithms (at once). When disabling a plugin, unique id should be passed
* (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the plugin.
* The plugin becomes enabled only after all features {@link #clearForceDisabled enabled it back}.
*
* Disabling and enabling a plugin:
*
* plugin.isEnabled; // -> true
* plugin.forceDisabled( 'MyFeature' );
* plugin.isEnabled; // -> false
* plugin.clearForceDisabled( 'MyFeature' );
* plugin.isEnabled; // -> true
*
* Plugin disabled by multiple features:
*
* plugin.forceDisabled( 'MyFeature' );
* plugin.forceDisabled( 'OtherFeature' );
* plugin.clearForceDisabled( 'MyFeature' );
* plugin.isEnabled; // -> false
* plugin.clearForceDisabled( 'OtherFeature' );
* plugin.isEnabled; // -> true
*
* Multiple disabling with the same identifier is redundant:
*
* plugin.forceDisabled( 'MyFeature' );
* plugin.forceDisabled( 'MyFeature' );
* plugin.clearForceDisabled( 'MyFeature' );
* plugin.isEnabled; // -> true
*
* **Note:** some plugins or algorithms may have more complex logic when it comes to enabling or disabling certain plugins,
* so the plugin might be still disabled after {@link #clearForceDisabled} was used.
*
* @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the plugin.
*/
forceDisabled( id ) {
this._disableStack.add( id );

if ( this._disableStack.size == 1 ) {
this.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );
this.isEnabled = false;
}
}

/**
* Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.
*
* @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.
*/
clearForceDisabled( id ) {
this._disableStack.delete( id );

if ( this._disableStack.size == 0 ) {
this.off( 'set:isEnabled', forceDisable );
this.isEnabled = true;
}
}

/**
Expand Down Expand Up @@ -200,3 +284,9 @@ mix( Plugin, ObservableMixin );
*
* @typedef {Array.<module:core/plugin~PluginInterface>} module:core/plugin~LoadedPlugins
*/

// Helper function that forces plugin to be disabled.
function forceDisable( evt ) {
evt.return = false;
evt.stop();
}
68 changes: 68 additions & 0 deletions tests/plugin.js
Expand Up @@ -41,4 +41,72 @@ describe( 'Plugin', () => {
expect( stopListeningSpy.calledOnce ).to.equal( true );
} );
} );

describe( 'forceDisabled() / clearForceDisabled()', () => {
let plugin;

beforeEach( () => {
plugin = new Plugin( editor );
} );

afterEach( () => {
plugin.destroy();
} );

it( 'forceDisabled() should disable the plugin', () => {
plugin.forceDisabled( 'foo' );
plugin.isEnabled = true;

expect( plugin.isEnabled ).to.be.false;
} );

it( 'clearForceDisabled() should enable the plugin', () => {
plugin.forceDisabled( 'foo' );
plugin.clearForceDisabled( 'foo' );

expect( plugin.isEnabled ).to.be.true;
} );

it( 'clearForceDisabled() used with wrong identifier should not enable the plugin', () => {
plugin.forceDisabled( 'foo' );
plugin.clearForceDisabled( 'bar' );
plugin.isEnabled = true;

expect( plugin.isEnabled ).to.be.false;
} );

it( 'using forceDisabled() twice with the same identifier should not have any effect', () => {
plugin.forceDisabled( 'foo' );
plugin.forceDisabled( 'foo' );
plugin.clearForceDisabled( 'foo' );

expect( plugin.isEnabled ).to.be.true;
} );

it( 'plugin is enabled only after all disables were cleared', () => {
plugin.forceDisabled( 'foo' );
plugin.forceDisabled( 'bar' );
plugin.clearForceDisabled( 'foo' );
plugin.isEnabled = true;

expect( plugin.isEnabled ).to.be.false;

plugin.clearForceDisabled( 'bar' );

expect( plugin.isEnabled ).to.be.true;
} );

it( 'plugin should remain disabled if isEnabled has a callback disabling it', () => {
plugin.on( 'set:isEnabled', evt => {
evt.return = false;
evt.stop();
} );

plugin.forceDisabled( 'foo' );
plugin.clearForceDisabled( 'foo' );
plugin.isEnabled = true;

expect( plugin.isEnabled ).to.be.false;
} );
} );
} );

0 comments on commit 7449450

Please sign in to comment.