Selaa lähdekoodia

Fixed integration between alternate text panel and image toolbar.

Szymon Kupś 8 vuotta sitten
vanhempi
commit
316a2d3b15

+ 24 - 12
packages/ckeditor5-image/src/imagealternatetext/imagealternatetext.js

@@ -11,6 +11,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
 import ImageAlternateTextEngine from './imagealternatetextengine';
 import escPressHandler from '@ckeditor/ckeditor5-ui/src/bindings/escpresshandler';
+import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';
 import ImageToolbar from '../imagetoolbar';
 import AlternateTextFormView from './ui/alternatetextformview';
 import ImageBalloonPanel from '../ui/imageballoonpanelview';
@@ -99,6 +100,21 @@ export default class ImageAlternateText extends Plugin {
 			this._hideBalloonPanel();
 		} );
 
+		// If image toolbar is present - hide it when alternate text balloon is visible.
+		const imageToolbar = editor.plugins.get( ImageToolbar );
+
+		if ( imageToolbar ) {
+			this.listenTo( panel, 'change:isVisible', () => {
+				if ( panel.isVisible ) {
+					imageToolbar.hide();
+					imageToolbar.isEnabled = false;
+				} else {
+					imageToolbar.show();
+					imageToolbar.isEnabled = true;
+				}
+			} );
+		}
+
 		this.listenTo( form, 'cancel', () => this._hideBalloonPanel() );
 
 		// Close on `ESC` press.
@@ -108,6 +124,14 @@ export default class ImageAlternateText extends Plugin {
 			callback: () => this._hideBalloonPanel()
 		} );
 
+		// Close on click outside of balloon panel element.
+		clickOutsideHandler( {
+			emitter: panel,
+			activator: () => panel.isVisible,
+			contextElement: panel.element,
+			callback: () => this._hideBalloonPanel()
+		} );
+
 		return Promise.all( [
 			panel.content.add( form ),
 			editor.ui.view.body.add( panel )
@@ -122,12 +146,6 @@ export default class ImageAlternateText extends Plugin {
 	_showBalloonPanel() {
 		const editor = this.editor;
 		const command = editor.commands.get( 'imageAlternateText' );
-		const imageToolbar = editor.plugins.get( ImageToolbar );
-
-		if ( imageToolbar ) {
-			imageToolbar.hide();
-		}
-
 		this.form.lebeledInput.value = command.value || '';
 		this.balloonPanel.attach();
 		this.form.lebeledInput.select();
@@ -142,11 +160,5 @@ export default class ImageAlternateText extends Plugin {
 		const editor = this.editor;
 		this.balloonPanel.detach();
 		editor.editing.view.focus();
-
-		const imageToolbar = editor.plugins.get( ImageToolbar );
-
-		if ( imageToolbar ) {
-			imageToolbar.show();
-		}
 	}
 }

+ 12 - 2
packages/ckeditor5-image/src/imagetoolbar.js

@@ -30,6 +30,14 @@ export default class ImageToolbar extends Plugin {
 		super( editor );
 
 		editor.config.set( 'image.defaultToolbar', [] );
+
+		/**
+		 * When set to `true`, toolbar will be repositioned and showed on each render event and focus change.
+		 * Set to `false` to temporary disable the image toolbar.
+		 *
+		 * @member {Boolean}
+		 */
+		this.isEnabled = true;
 	}
 
 	/**
@@ -70,12 +78,14 @@ export default class ImageToolbar extends Plugin {
 
 		// Show balloon panel each time image widget is selected.
 		this.listenTo( this.editor.editing.view, 'render', () => {
-			this.show();
+			if ( this.isEnabled ) {
+				this.show();
+			}
 		}, { priority: 'low' } );
 
 		// There is no render method after focus is back in editor, we need to check if balloon panel should be visible.
 		this.listenTo( editor.ui.focusTracker, 'change:isFocused', ( evt, name, is, was ) => {
-			if ( !was && is ) {
+			if ( !was && is && this.isEnabled ) {
 				this.show();
 			}
 		} );

+ 69 - 25
packages/ckeditor5-image/tests/imagealternatetext/imagealternatetext.js

@@ -13,6 +13,8 @@ import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 
+/* global Event */
+
 describe( 'ImageAlternateText', () => {
 	let editor, plugin, command, balloonPanel, form;
 
@@ -72,31 +74,6 @@ describe( 'ImageAlternateText', () => {
 			sinon.assert.calledOnce( spy );
 		} );
 
-		it( 'should hide ImageToolbar on execute', () => {
-			const editorElement = global.document.createElement( 'div' );
-			global.document.body.appendChild( editorElement );
-
-			return ClassicTestEditor.create( editorElement, {
-				plugins: [ ImageAlternateText, Image, ImageToolbar ],
-				image: {
-					toolbar: [ 'imageAlternateText' ]
-				}
-			} )
-			.then( newEditor => {
-				newEditor.editing.view.attachDomRoot( editorElement );
-				const button = newEditor.ui.componentFactory.create( 'imageAlternateText' );
-				const toolbarPlugin = newEditor.plugins.get( ImageToolbar );
-
-				const spy = sinon.spy( toolbarPlugin, 'hide' );
-				setData( newEditor.document, '[<image src="" alt="foo bar"></image>]' );
-				button.fire( 'execute' );
-
-				sinon.assert.calledOnce( spy );
-
-				newEditor.destroy();
-			} );
-		} );
-
 		it( 'should set alt attribute value to textarea and select it', () => {
 			const spy = sinon.spy( form.lebeledInput, 'select' );
 			setData( editor.document, '[<image src="" alt="foo bar"></image>]' );
@@ -175,6 +152,73 @@ describe( 'ImageAlternateText', () => {
 					sinon.assert.called( hidePanelSpy );
 				} );
 			} );
+
+			describe( 'mouse', () => {
+				it( 'should close and not focus editable on click outside the panel', () => {
+					balloonPanel.isVisible = true;
+					global.document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
+
+					sinon.assert.called( hidePanelSpy );
+				} );
+
+				it( 'should not close on click inside the panel', () => {
+					balloonPanel.isVisible = true;
+					balloonPanel.element.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
+
+					sinon.assert.notCalled( hidePanelSpy );
+				} );
+			} );
+		} );
+	} );
+
+	describe( 'working with ImageToolbar', () => {
+		let editor, button, imageToolbarPlugin, plugin;
+
+		beforeEach( () => {
+			const editorElement = global.document.createElement( 'div' );
+			global.document.body.appendChild( editorElement );
+
+			return ClassicTestEditor.create( editorElement, {
+				plugins: [ ImageAlternateText, Image, ImageToolbar ],
+				image: {
+					toolbar: [ 'imageAlternateText' ]
+				}
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				editor.editing.view.attachDomRoot( editorElement );
+				button = newEditor.ui.componentFactory.create( 'imageAlternateText' );
+				imageToolbarPlugin = newEditor.plugins.get( ImageToolbar );
+				plugin = editor.plugins.get( ImageAlternateText );
+			} );
+		} );
+
+		afterEach( () => editor.destroy() );
+
+		it( 'should hide ImageToolbar when visible', () => {
+			setData( editor.document, '[<image src="" alt="foo bar"></image>]' );
+			const spy = sinon.spy( imageToolbarPlugin, 'hide' );
+			button.fire( 'execute' );
+
+			sinon.assert.calledOnce( spy );
+		} );
+
+		it( 'ImageToolbar should not show when alternate text panel is visible', () => {
+			setData( editor.document, '[<image src="" alt="foo bar"></image>]' );
+			button.fire( 'execute' );
+			const spy = sinon.spy( imageToolbarPlugin, 'show' );
+			editor.editing.view.render();
+
+			sinon.assert.notCalled( spy );
+		} );
+
+		it( 'ImageToolbar should show when alternate text panel is not visible', () => {
+			setData( editor.document, '[<image src="" alt="foo bar"></image>]' );
+			button.fire( 'execute' );
+			const spy = sinon.spy( imageToolbarPlugin, 'show' );
+			plugin.balloonPanel.isVisible = false;
+
+			sinon.assert.called( spy );
 		} );
 	} );
 } );

+ 11 - 0
packages/ckeditor5-image/tests/imagetoolbar.js

@@ -93,6 +93,17 @@ describe( 'ImageToolbar', () => {
 		sinon.assert.calledOnce( spy );
 	} );
 
+	it( 'should not show the panel automatically when it is disabled', () => {
+		plugin.isEnabled = false;
+		setData( doc, '[<image src=""></image>]' );
+		editor.ui.focusTracker.isFocused = true;
+		const spy = sinon.spy( plugin, 'show' );
+
+		editingView.render();
+
+		sinon.assert.notCalled( spy );
+	} );
+
 	it( 'should not show the panel when editor looses focus', () => {
 		editor.ui.focusTracker.isFocused = true;
 		const spy = sinon.spy( plugin, 'show' );