diff --git a/packages/ckeditor5-ui/src/toolbar/block/blocktoolbar.js b/packages/ckeditor5-ui/src/toolbar/block/blocktoolbar.js index 19996279de1..f69aa086c5b 100644 --- a/packages/ckeditor5-ui/src/toolbar/block/blocktoolbar.js +++ b/packages/ckeditor5-ui/src/toolbar/block/blocktoolbar.js @@ -25,6 +25,7 @@ import normalizeToolbarConfig from '../normalizetoolbarconfig'; import ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver'; import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit'; +import env from '@ckeditor/ckeditor5-utils/src/env'; const toPx = toUnit( 'px' ); @@ -280,6 +281,7 @@ export default class BlockToolbar extends Plugin { const editor = this.editor; const t = editor.t; const buttonView = new BlockButtonView( editor.locale ); + const bind = buttonView.bindTemplate; buttonView.set( { label: t( 'Edit block' ), @@ -287,6 +289,23 @@ export default class BlockToolbar extends Plugin { withText: false } ); + // Note that this piece over here overrides the default mousedown logic in ButtonView + // to make it work with BlockToolbar. See the implementation of the ButtonView class to learn more. + buttonView.extendTemplate( { + on: { + mousedown: bind.to( evt => { + // On Safari we have to force the focus on a button on click as it's the only browser + // that doesn't do that automatically. See #12115. + if ( env.isSafari && this.panelView.isVisible ) { + this.toolbarView.focus(); + } + + // Workaround to #12184, see https://github.com/ckeditor/ckeditor5/issues/12184#issuecomment-1199147964. + evt.preventDefault(); + } ) + } + } ); + // Bind the panelView observable properties to the buttonView. buttonView.bind( 'isOn' ).to( this.panelView, 'isVisible' ); buttonView.bind( 'tooltip' ).to( this.panelView, 'isVisible', isVisible => !isVisible ); diff --git a/packages/ckeditor5-ui/tests/toolbar/block/blocktoolbar.js b/packages/ckeditor5-ui/tests/toolbar/block/blocktoolbar.js index 77d7896100a..8a464d1247b 100644 --- a/packages/ckeditor5-ui/tests/toolbar/block/blocktoolbar.js +++ b/packages/ckeditor5-ui/tests/toolbar/block/blocktoolbar.js @@ -28,6 +28,7 @@ import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect'; +import env from '@ckeditor/ckeditor5-utils/src/env'; describe( 'BlockToolbar', () => { let editor, element, blockToolbar; @@ -328,6 +329,50 @@ describe( 'BlockToolbar', () => { const blockToolbar = editor.plugins.get( BlockToolbar ); expect( blockToolbar.buttonView.isVisible ).to.be.false; } ); + + describe( 'mousedown event', () => { + // https://github.com/ckeditor/ckeditor5/issues/12184 + it( 'should call preventDefault to avoid stealing the focus', () => { + const ret = blockToolbar.buttonView.element.dispatchEvent( new Event( 'mousedown', { cancelable: true } ) ); + + expect( ret ).to.false; + } ); + + // https://github.com/ckeditor/ckeditor5/issues/12115 + describe( 'in Safari', () => { + let view, stub, spy; + + beforeEach( () => { + stub = testUtils.sinon.stub( env, 'isSafari' ).value( true ); + view = blockToolbar.buttonView; + spy = sinon.spy( blockToolbar.toolbarView, 'focus' ); + } ); + + afterEach( () => { + stub.resetBehavior(); + } ); + + it( 'should focus the toolbar when it shows up', () => { + blockToolbar.panelView.isVisible = true; + view.element.dispatchEvent( new Event( 'mousedown', { cancelable: true } ) ); + + expect( spy.callCount ).to.equal( 1 ); + } ); + + it( 'should not focus the toolbar when it hides', () => { + blockToolbar.panelView.isVisible = false; + view.element.dispatchEvent( new Event( 'mousedown', { cancelable: true } ) ); + + expect( spy.callCount ).to.equal( 0 ); + } ); + + it( 'should also preventDefault the event', () => { + const ret = view.element.dispatchEvent( new Event( 'mousedown', { cancelable: true } ) ); + + expect( ret ).to.false; + } ); + } ); + } ); } ); } );