ソースを参照

Used FocusTracker to track focus of Balloontoolbar and EditableElement.

Oskar Wróbel 7 年 前
コミット
1ebcc89efa

+ 15 - 4
packages/ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js

@@ -11,6 +11,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import ContextualBalloon from '../../panel/balloon/contextualballoon';
 import ToolbarView from '../toolbarview';
 import BalloonPanelView from '../../panel/balloon/balloonpanelview.js';
+import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
 import debounce from '@ckeditor/ckeditor5-utils/src/lib/lodash/debounce';
 import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';
 import normalizeToolbarConfig from '../normalizetoolbarconfig';
@@ -51,6 +52,17 @@ export default class BalloonToolbar extends Plugin {
 		this.toolbarView = this._createToolbarView();
 
 		/**
+		 * Tracks focus of editable element and {@link #toolbarView}.
+		 * When both are not focused then toolbar should hide.
+		 *
+		 * @readonly
+		 * @type {module:utils:focustracker~FocusTracker}
+		 */
+		this.focusTracker = new FocusTracker();
+		this.focusTracker.add( editor.ui.view.editableElement );
+		this.focusTracker.add( this.toolbarView.element );
+
+		/**
 		 * The contextual balloon plugin instance.
 		 *
 		 * @private
@@ -82,13 +94,12 @@ export default class BalloonToolbar extends Plugin {
 		const selection = editor.model.document.selection;
 
 		// Show/hide the toolbar on editable focus/blur.
-		this.listenTo( editor.editing.view.document, 'change:isFocused', ( evt, name, isEditableFocused ) => {
-			const isToolbarFocused = this.toolbarView.focusTracker.isFocused;
+		this.listenTo( this.focusTracker, 'change:isFocused', ( evt, name, isFocused ) => {
 			const isToolbarVisible = this._balloon.visibleView === this.toolbarView;
 
-			if ( !isEditableFocused && !isToolbarFocused && isToolbarVisible ) {
+			if ( !isFocused && isToolbarVisible ) {
 				this.hide();
-			} else if ( isEditableFocused ) {
+			} else if ( isFocused ) {
 				this.show();
 			}
 		} );

+ 35 - 35
packages/ckeditor5-ui/tests/toolbar/balloon/balloontoolbar.js

@@ -8,6 +8,7 @@ import BalloonToolbar from '../../../src/toolbar/balloon/balloontoolbar';
 import ContextualBalloon from '../../../src/panel/balloon/contextualballoon';
 import BalloonPanelView from '../../../src/panel/balloon/balloonpanelview';
 import ToolbarView from '../../../src/toolbar/toolbarview';
+import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
 import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
@@ -143,6 +144,28 @@ describe( 'BalloonToolbar', () => {
 		} );
 	} );
 
+	describe( 'focusTracker', () => {
+		it( 'should be defined', () => {
+			expect( balloonToolbar.focusTracker ).to.instanceof( FocusTracker );
+		} );
+
+		it( 'it should track focus of #editableElement', () => {
+			expect( balloonToolbar.focusTracker.isFocused ).to.false;
+
+			editor.ui.view.editableElement.dispatchEvent( new Event( 'focus' ) );
+
+			expect( balloonToolbar.focusTracker.isFocused ).to.true;
+		} );
+
+		it( 'it should track focus of #toolbarView.element', () => {
+			expect( balloonToolbar.focusTracker.isFocused ).to.false;
+
+			balloonToolbar.toolbarView.element.dispatchEvent( new Event( 'focus' ) );
+
+			expect( balloonToolbar.focusTracker.isFocused ).to.true;
+		} );
+	} );
+
 	describe( 'show()', () => {
 		let balloonAddSpy, backwardSelectionRect, forwardSelectionRect;
 
@@ -459,72 +482,49 @@ describe( 'BalloonToolbar', () => {
 			sinon.assert.calledOnce( hidePanelSpy );
 		} );
 
-		it( 'should hide on editable blur', () => {
-			editingView.document.isFocused = true;
-
-			balloonToolbar.fire( '_selectionChangeDebounced' );
+		it( 'should show on #focusTracker focus', () => {
+			balloonToolbar.focusTracker.isFocused = false;
 
-			const stub = sandbox.stub( balloon, 'visibleView' ).get( () => balloonToolbar.toolbarView );
-
-			sinon.assert.calledOnce( showPanelSpy );
+			sinon.assert.notCalled( showPanelSpy );
 			sinon.assert.notCalled( hidePanelSpy );
 
-			editingView.document.isFocused = false;
+			balloonToolbar.focusTracker.isFocused = true;
 
 			sinon.assert.calledOnce( showPanelSpy );
-			sinon.assert.calledOnce( hidePanelSpy );
-
-			stub.restore();
+			sinon.assert.notCalled( hidePanelSpy );
 		} );
 
-		it( 'should not hide on editable blur when #toolbarView gets focus', () => {
-			editingView.document.isFocused = true;
-
-			balloonToolbar.fire( '_selectionChangeDebounced' );
+		it( 'should hide on #focusTracker blur', () => {
+			balloonToolbar.focusTracker.isFocused = true;
 
 			const stub = sandbox.stub( balloon, 'visibleView' ).get( () => balloonToolbar.toolbarView );
 
 			sinon.assert.calledOnce( showPanelSpy );
 			sinon.assert.notCalled( hidePanelSpy );
 
-			balloonToolbar.toolbarView.focusTracker.isFocused = true;
-			editingView.document.isFocused = false;
+			balloonToolbar.focusTracker.isFocused = false;
 
 			sinon.assert.calledOnce( showPanelSpy );
-			sinon.assert.notCalled( hidePanelSpy );
+			sinon.assert.calledOnce( hidePanelSpy );
 
 			stub.restore();
 		} );
 
-		it( 'should not hide on editable blur when #toolbarView is not visible', () => {
-			editingView.document.isFocused = true;
-
-			balloonToolbar.fire( '_selectionChangeDebounced' );
+		it( 'should not hide on #focusTracker blur when toolbar is not in the balloon stack', () => {
+			balloonToolbar.focusTracker.isFocused = true;
 
 			const stub = sandbox.stub( balloon, 'visibleView' ).get( () => null );
 
 			sinon.assert.calledOnce( showPanelSpy );
 			sinon.assert.notCalled( hidePanelSpy );
 
-			editingView.document.isFocused = false;
+			balloonToolbar.focusTracker.isFocused = false;
 
 			sinon.assert.calledOnce( showPanelSpy );
 			sinon.assert.notCalled( hidePanelSpy );
 
 			stub.restore();
 		} );
-
-		it( 'should show when editable gets focus', () => {
-			editingView.document.isFocused = false;
-
-			sinon.assert.notCalled( showPanelSpy );
-			sinon.assert.notCalled( hidePanelSpy );
-
-			editingView.document.isFocused = true;
-
-			sinon.assert.calledOnce( showPanelSpy );
-			sinon.assert.notCalled( hidePanelSpy );
-		} );
 	} );
 
 	describe( 'show event', () => {