瀏覽代碼

Merge branch 'master' into i/6089

Aleksander Nowodzinski 5 年之前
父節點
當前提交
5b4b390865

+ 90 - 0
packages/ckeditor5-core/src/plugin.js

@@ -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;
+		}
 	}
 
 	/**
@@ -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 - 0
packages/ckeditor5-core/tests/plugin.js

@@ -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;
+		} );
+	} );
 } );

+ 1 - 0
packages/ckeditor5-core/theme/icons/align-bottom.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.239 13.938l-2.88-1.663a.75.75 0 01.75-1.3L9 12.067V4.75a.75.75 0 111.5 0v7.318l1.89-1.093a.75.75 0 01.75 1.3l-2.879 1.663a.752.752 0 01-.511.187.752.752 0 01-.511-.187zM4.25 17a.75.75 0 110-1.5h10.5a.75.75 0 010 1.5H4.25z"/></svg>

+ 1 - 0
packages/ckeditor5-core/theme/icons/align-center.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm2.286 4c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75z"/></svg>

+ 1 - 0
packages/ckeditor5-core/theme/icons/align-justify.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>

+ 1 - 0
packages/ckeditor5-core/theme/icons/align-left.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>

File diff suppressed because it is too large
+ 1 - 0
packages/ckeditor5-core/theme/icons/align-middle.svg


+ 1 - 0
packages/ckeditor5-core/theme/icons/align-right.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M18 3.75a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 8a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 4a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75zm0-8a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75z"/></svg>

+ 1 - 0
packages/ckeditor5-core/theme/icons/align-top.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.261 7.062l2.88 1.663a.75.75 0 01-.75 1.3L10.5 8.933v7.317a.75.75 0 11-1.5 0V8.932l-1.89 1.093a.75.75 0 01-.75-1.3l2.879-1.663a.752.752 0 01.511-.187.752.752 0 01.511.187zM15.25 4a.75.75 0 110 1.5H4.75a.75.75 0 010-1.5h10.5z"/></svg>