diff --git a/packages/ckeditor5-ui/package.json b/packages/ckeditor5-ui/package.json index a992776b9e3..f71d705e9ec 100644 --- a/packages/ckeditor5-ui/package.json +++ b/packages/ckeditor5-ui/package.json @@ -27,6 +27,7 @@ "@ckeditor/ckeditor5-list": "^19.0.1", "@ckeditor/ckeditor5-mention": "^19.0.1", "@ckeditor/ckeditor5-paragraph": "^19.1.0", + "@ckeditor/ckeditor5-horizontal-line": "^19.0.1", "@ckeditor/ckeditor5-typing": "^19.0.1" }, "engines": { diff --git a/packages/ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js b/packages/ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js index 7ad174b3d8d..f4d86033f0e 100644 --- a/packages/ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js +++ b/packages/ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js @@ -209,6 +209,8 @@ export default class BalloonToolbar extends Plugin { */ show() { const editor = this.editor; + const selection = editor.model.document.selection; + const schema = editor.model.schema; // Do not add the toolbar to the balloon stack twice. if ( this._balloon.hasView( this.toolbarView ) ) { @@ -216,7 +218,13 @@ export default class BalloonToolbar extends Plugin { } // Do not show the toolbar when the selection is collapsed. - if ( editor.model.document.selection.isCollapsed ) { + if ( selection.isCollapsed ) { + return; + } + + // Do not show the toolbar when there is more than one range in the selection and they fully contain object elements. + // See https://github.com/ckeditor/ckeditor5/issues/6443. + if ( selectionContainsOnlyMultipleObjects( selection, schema ) ) { return; } @@ -356,6 +364,26 @@ function getBalloonPositions( isBackward ) { ]; } +// Returns "true" when the selection has multiple ranges and each range contains an object +// and nothing else. +// +// @private +// @param {module:engine/model/selection~Selection} selection +// @param {module:engine/model/schema~Schema} schema +// @returns {Boolean} +function selectionContainsOnlyMultipleObjects( selection, schema ) { + // It doesn't contain multiple objects if there is only one range. + if ( selection.rangeCount === 1 ) { + return false; + } + + return [ ...selection.getRanges() ].every( range => { + const element = range.getContainedElement(); + + return element && schema.isObject( element ); + } ); +} + /** * Contextual toolbar configuration. Used by the {@link module:ui/toolbar/balloon/balloontoolbar~BalloonToolbar} * feature. diff --git a/packages/ckeditor5-ui/tests/toolbar/balloon/balloontoolbar.js b/packages/ckeditor5-ui/tests/toolbar/balloon/balloontoolbar.js index 02a1d4c55ab..68cf6118f87 100644 --- a/packages/ckeditor5-ui/tests/toolbar/balloon/balloontoolbar.js +++ b/packages/ckeditor5-ui/tests/toolbar/balloon/balloontoolbar.js @@ -14,6 +14,7 @@ import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold'; import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic'; import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline'; import global from '@ckeditor/ckeditor5-utils/src/dom/global'; import ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver'; @@ -55,7 +56,7 @@ describe( 'BalloonToolbar', () => { return ClassicTestEditor .create( editorElement, { - plugins: [ Paragraph, Bold, Italic, BalloonToolbar ], + plugins: [ Paragraph, Bold, Italic, BalloonToolbar, HorizontalLine ], balloonToolbar: [ 'bold', 'italic' ] } ) .then( newEditor => { @@ -374,6 +375,15 @@ describe( 'BalloonToolbar', () => { sinon.assert.notCalled( balloonAddSpy ); } ); + // https://github.com/ckeditor/ckeditor5/issues/6443 + it( 'should not add the #toolbarView to the #_balloon when the selection contains more than one fully contained object', () => { + // This is for multi cell selection in tables. + setData( model, '[]foo[]' ); + + balloonToolbar.show(); + sinon.assert.notCalled( balloonAddSpy ); + } ); + it( 'should not add #toolbarView to the #_balloon when all components inside #toolbarView are disabled', () => { Array.from( balloonToolbar.toolbarView.items ).forEach( item => { item.isEnabled = false;