From 7caf0b05570edc6a5be04322e77190a6a30385ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Tue, 9 May 2017 13:47:08 +0200 Subject: [PATCH 01/11] Stubbed balloon#remove method which was throwing errors. --- tests/toolbar/contextual/contextualtoolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/toolbar/contextual/contextualtoolbar.js b/tests/toolbar/contextual/contextualtoolbar.js index e301d16b..e1cfb7fd 100644 --- a/tests/toolbar/contextual/contextualtoolbar.js +++ b/tests/toolbar/contextual/contextualtoolbar.js @@ -234,7 +234,7 @@ describe( 'ContextualToolbar', () => { let removeBalloonSpy; beforeEach( () => { - removeBalloonSpy = sandbox.spy( balloon, 'remove' ); + removeBalloonSpy = sandbox.stub( balloon, 'remove', () => {} ); editor.editing.view.isFocused = true; } ); From 9c88303b15adbc0c27617de82b8b2eb0bf86294a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Tue, 9 May 2017 13:47:55 +0200 Subject: [PATCH 02/11] Improved test clean up. --- tests/toolbar/contextual/contextualtoolbar.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/toolbar/contextual/contextualtoolbar.js b/tests/toolbar/contextual/contextualtoolbar.js index e1cfb7fd..f4314cbd 100644 --- a/tests/toolbar/contextual/contextualtoolbar.js +++ b/tests/toolbar/contextual/contextualtoolbar.js @@ -49,6 +49,7 @@ describe( 'ContextualToolbar', () => { afterEach( () => { sandbox.restore(); + editorElement.remove(); return editor.destroy(); } ); From 22e3f755dc8c11abc16cd3e968a3312866ce054a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Tue, 9 May 2017 16:17:53 +0200 Subject: [PATCH 03/11] Added beforeShow event. --- src/toolbar/contextual/contextualtoolbar.js | 72 ++++++++++++++++--- tests/toolbar/contextual/contextualtoolbar.js | 61 ++++++++++++++++ 2 files changed, 122 insertions(+), 11 deletions(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index 91634331..21235c80 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -12,6 +12,7 @@ import ContextualBalloon from '../../panel/balloon/contextualballoon'; import ToolbarView from '../toolbarview'; import BalloonPanelView from '../../panel/balloon/balloonpanelview.js'; import debounce from '@ckeditor/ckeditor5-utils/src/lib/lodash/debounce'; +import spy from '@ckeditor/ckeditor5-utils/src/spy'; const defaultPositions = BalloonPanelView.defaultPositions; @@ -67,6 +68,15 @@ export default class ContextualToolbar extends Plugin { */ this._fireSelectionChangeDebounced = debounce( () => this.fire( '_selectionChangeDebounced' ), 200 ); + /** + * Resolve {@link #_showPanel} promise. When panel is prevented of being shown we need to resolve + * this promise otherwise will be pending forever. + * + * @private + * @member {Function} + */ + this._stopShowPanel = spy(); + // Attach lifecycle actions. this._handleSelectionChange(); this._handleFocusChange(); @@ -128,11 +138,25 @@ export default class ContextualToolbar extends Plugin { this.listenTo( this, '_selectionChangeDebounced', () => this._showPanel() ); } + /** + * Prevents panel of being displayed. This should be used together with {@link #event:beforeShow}` event. + * + * @param {module:utils/eventinfo~EventInfo} evt Event object provided by the {@link #event:beforeShow} event. + */ + stop( evt ) { + evt.stop(); + this._stopShowPanel(); + this.stopListening( this, 'beforeShow' ); + } + /** * Adds panel view to the {@link: #_balloon} and attaches panel to the selection. * + * Fires {@link #event:beforeShow} event just before displaying the panel. + * * @protected - * @return {Promise} A promise resolved when the {@link #toolbarView} {@link module:ui/view~View#init} is done. + * @return {Promise} A promise resolved when the {@link #toolbarView} {@link module:ui/view~View#init} is done + * or rejected when panel will be prevented of being displayed. */ _showPanel() { const editingView = this.editor.editing.view; @@ -147,17 +171,35 @@ export default class ContextualToolbar extends Plugin { return Promise.resolve(); } - // Update panel position when selection changes while balloon will be opened (by a collaboration). - this.listenTo( this.editor.editing.view, 'render', () => { - this._balloon.updatePosition( this._getBalloonPositionData() ); - } ); + const showPromise = new Promise( ( resolve ) => { + this._stopShowPanel = resolve; - // Add panel to the common editor contextual balloon. - return this._balloon.add( { - view: this.toolbarView, - position: this._getBalloonPositionData(), - balloonClassName: 'ck-toolbar-container' - } ); + // If `beforeShow` event is not stopped by any other plugin we can display toolbar panel. + this.listenTo( this, 'beforeShow', ( evt ) => { + // Update panel position when selection changes while balloon will be opened + // (by an external document changes). + this.listenTo( editingView, 'render', () => { + this._balloon.updatePosition( this._getBalloonPositionData() ); + } ); + + resolve( + // Add panel to the common editor contextual balloon. + this._balloon.add( { + view: this.toolbarView, + position: this._getBalloonPositionData(), + balloonClassName: 'ck-toolbar-container' + } ) + ); + + // Clean up listener to be sure that won't be duplicated in the future. + evt.off(); + } ); + }, { priority: 'lowest' } ); + + // Fire this event to inform interested plugins that `ContextualToolbar` is going to be shown. + this.fire( 'beforeShow' ); + + return showPromise; } /** @@ -210,6 +252,14 @@ export default class ContextualToolbar extends Plugin { super.destroy(); } + /** + * This event is fired just before balloon shows. + * It makes possible to listen to this event by the other plugins and prevent + * ContextualToolbar of being displayed by calling {@link #stop} method. + * + * @event beforeShow + */ + /** * This is internal plugin event which is fired 200 ms after model selection last change. * This is to makes easy test debounced action without need to use `setTimeout`. diff --git a/tests/toolbar/contextual/contextualtoolbar.js b/tests/toolbar/contextual/contextualtoolbar.js index f4314cbd..3dd62b68 100644 --- a/tests/toolbar/contextual/contextualtoolbar.js +++ b/tests/toolbar/contextual/contextualtoolbar.js @@ -389,6 +389,67 @@ describe( 'ContextualToolbar', () => { } ); } ); + describe( 'beforeShow event', () => { + it( 'should fire `beforeShow` event just before panel shows', () => { + const spy = sinon.spy(); + + contextualToolbar.on( 'beforeShow', spy ); + setData( editor.document, 'b[a]r' ); + + const promise = contextualToolbar._showPanel(); + + sinon.assert.calledOnce( spy ); + + return promise; + } ); + + it( 'should not show panel when `beforeShow` event will be stopped', () => { + const balloonAddSpy = sandbox.spy( balloon, 'add' ); + + setData( editor.document, 'b[a]r' ); + + contextualToolbar.on( 'beforeShow', ( evt ) => { + contextualToolbar.stop( evt ); + } ); + + return contextualToolbar._showPanel().then( () => { + sinon.assert.notCalled( balloonAddSpy ); + } ); + } ); + } ); + + describe( 'stop', () => { + it( 'should stop `beforeShow` event', () => { + const evtMock = { + stop: sinon.spy() + }; + + contextualToolbar.stop( evtMock ); + + sinon.assert.calledOnce( evtMock.stop ); + } ); + + it( 'should resolve promise and clean up listener', () => { + const balloonAddSpy = sandbox.spy( balloon, 'add' ); + + setData( editor.document, 'b[a]r' ); + + contextualToolbar.once( 'beforeShow', ( evt ) => { + contextualToolbar.stop( evt ); + } ); + + return contextualToolbar._showPanel() + .then( () => contextualToolbar._hidePanel() ) + .then( () => contextualToolbar._showPanel() ) + .then( () => contextualToolbar._hidePanel() ) + .then( () => contextualToolbar._showPanel() ) + .then( () => { + // Called twice but _showPanel was called thrice. + sinon.assert.calledTwice( balloonAddSpy ); + } ); + } ); + } ); + function stubSelectionRect( forwardSelectionRect, backwardSelectionRect ) { const editingView = editor.editing.view; const originalViewRangeToDom = editingView.domConverter.viewRangeToDom; From 096a29768a8d1575b161a80af7f03cafbe7cf318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Tue, 9 May 2017 16:26:40 +0200 Subject: [PATCH 04/11] Improved property name. --- src/toolbar/contextual/contextualtoolbar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index 21235c80..d7c96772 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -75,7 +75,7 @@ export default class ContextualToolbar extends Plugin { * @private * @member {Function} */ - this._stopShowPanel = spy(); + this._resolveShowPanelPromise = spy(); // Attach lifecycle actions. this._handleSelectionChange(); @@ -145,7 +145,7 @@ export default class ContextualToolbar extends Plugin { */ stop( evt ) { evt.stop(); - this._stopShowPanel(); + this._resolveShowPanelPromise(); this.stopListening( this, 'beforeShow' ); } @@ -172,7 +172,7 @@ export default class ContextualToolbar extends Plugin { } const showPromise = new Promise( ( resolve ) => { - this._stopShowPanel = resolve; + this._resolveShowPanelPromise = resolve; // If `beforeShow` event is not stopped by any other plugin we can display toolbar panel. this.listenTo( this, 'beforeShow', ( evt ) => { From 3f1ce0abff99a38397f856c42b45ce3ef0214a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Tue, 9 May 2017 16:31:24 +0200 Subject: [PATCH 05/11] Improved docs. --- src/toolbar/contextual/contextualtoolbar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index d7c96772..1d1a3802 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -174,7 +174,7 @@ export default class ContextualToolbar extends Plugin { const showPromise = new Promise( ( resolve ) => { this._resolveShowPanelPromise = resolve; - // If `beforeShow` event is not stopped by any other plugin we can display toolbar panel. + // If `beforeShow` event is not stopped by any external code then panel will be displayed. this.listenTo( this, 'beforeShow', ( evt ) => { // Update panel position when selection changes while balloon will be opened // (by an external document changes). @@ -191,7 +191,7 @@ export default class ContextualToolbar extends Plugin { } ) ); - // Clean up listener to be sure that won't be duplicated in the future. + // Stop listening on `beforeShow` event. evt.off(); } ); }, { priority: 'lowest' } ); @@ -254,7 +254,7 @@ export default class ContextualToolbar extends Plugin { /** * This event is fired just before balloon shows. - * It makes possible to listen to this event by the other plugins and prevent + * It makes possible to listen to this event by an external code and prevent * ContextualToolbar of being displayed by calling {@link #stop} method. * * @event beforeShow From c11cd336991b6f37d748d8437de5d3328e397f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Tue, 9 May 2017 16:33:07 +0200 Subject: [PATCH 06/11] Improved docs. --- tests/toolbar/contextual/contextualtoolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/toolbar/contextual/contextualtoolbar.js b/tests/toolbar/contextual/contextualtoolbar.js index 3dd62b68..5b2ef733 100644 --- a/tests/toolbar/contextual/contextualtoolbar.js +++ b/tests/toolbar/contextual/contextualtoolbar.js @@ -403,7 +403,7 @@ describe( 'ContextualToolbar', () => { return promise; } ); - it( 'should not show panel when `beforeShow` event will be stopped', () => { + it( 'should not show panel when `beforeShow` is stopped', () => { const balloonAddSpy = sandbox.spy( balloon, 'add' ); setData( editor.document, 'b[a]r' ); From 5f94979ad17eedd77b54c80f87c47e93c020fb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Wed, 10 May 2017 10:56:51 +0200 Subject: [PATCH 07/11] Changed property name. --- src/toolbar/contextual/contextualtoolbar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index 1d1a3802..8b8e23f8 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -75,7 +75,7 @@ export default class ContextualToolbar extends Plugin { * @private * @member {Function} */ - this._resolveShowPanelPromise = spy(); + this._showPanelPromiseResolver = spy(); // Attach lifecycle actions. this._handleSelectionChange(); @@ -145,7 +145,7 @@ export default class ContextualToolbar extends Plugin { */ stop( evt ) { evt.stop(); - this._resolveShowPanelPromise(); + this._showPanelPromiseResolver(); this.stopListening( this, 'beforeShow' ); } @@ -172,7 +172,7 @@ export default class ContextualToolbar extends Plugin { } const showPromise = new Promise( ( resolve ) => { - this._resolveShowPanelPromise = resolve; + this._showPanelPromiseResolver = resolve; // If `beforeShow` event is not stopped by any external code then panel will be displayed. this.listenTo( this, 'beforeShow', ( evt ) => { From 21e84fc7f754d422e51863695651b9405ca5b369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Wed, 10 May 2017 16:51:18 +0200 Subject: [PATCH 08/11] Drop not necessary stop() methd and simplified the code. --- src/toolbar/contextual/contextualtoolbar.js | 46 ++++++------------- tests/toolbar/contextual/contextualtoolbar.js | 38 ++------------- 2 files changed, 18 insertions(+), 66 deletions(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index 8b8e23f8..4dddeadb 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -12,7 +12,6 @@ import ContextualBalloon from '../../panel/balloon/contextualballoon'; import ToolbarView from '../toolbarview'; import BalloonPanelView from '../../panel/balloon/balloonpanelview.js'; import debounce from '@ckeditor/ckeditor5-utils/src/lib/lodash/debounce'; -import spy from '@ckeditor/ckeditor5-utils/src/spy'; const defaultPositions = BalloonPanelView.defaultPositions; @@ -68,15 +67,6 @@ export default class ContextualToolbar extends Plugin { */ this._fireSelectionChangeDebounced = debounce( () => this.fire( '_selectionChangeDebounced' ), 200 ); - /** - * Resolve {@link #_showPanel} promise. When panel is prevented of being shown we need to resolve - * this promise otherwise will be pending forever. - * - * @private - * @member {Function} - */ - this._showPanelPromiseResolver = spy(); - // Attach lifecycle actions. this._handleSelectionChange(); this._handleFocusChange(); @@ -138,17 +128,6 @@ export default class ContextualToolbar extends Plugin { this.listenTo( this, '_selectionChangeDebounced', () => this._showPanel() ); } - /** - * Prevents panel of being displayed. This should be used together with {@link #event:beforeShow}` event. - * - * @param {module:utils/eventinfo~EventInfo} evt Event object provided by the {@link #event:beforeShow} event. - */ - stop( evt ) { - evt.stop(); - this._showPanelPromiseResolver(); - this.stopListening( this, 'beforeShow' ); - } - /** * Adds panel view to the {@link: #_balloon} and attaches panel to the selection. * @@ -160,6 +139,7 @@ export default class ContextualToolbar extends Plugin { */ _showPanel() { const editingView = this.editor.editing.view; + let isStopped = false; // Do not add toolbar to the balloon stack twice. if ( this._balloon.hasView( this.toolbarView ) ) { @@ -172,10 +152,15 @@ export default class ContextualToolbar extends Plugin { } const showPromise = new Promise( ( resolve ) => { - this._showPanelPromiseResolver = resolve; - // If `beforeShow` event is not stopped by any external code then panel will be displayed. - this.listenTo( this, 'beforeShow', ( evt ) => { + this.once( 'beforeShow', () => { + if ( isStopped ) { + isStopped = false; + resolve(); + + return; + } + // Update panel position when selection changes while balloon will be opened // (by an external document changes). this.listenTo( editingView, 'render', () => { @@ -190,14 +175,12 @@ export default class ContextualToolbar extends Plugin { balloonClassName: 'ck-toolbar-container' } ) ); - - // Stop listening on `beforeShow` event. - evt.off(); } ); }, { priority: 'lowest' } ); - // Fire this event to inform interested plugins that `ContextualToolbar` is going to be shown. - this.fire( 'beforeShow' ); + // Fire this event to inform that `ContextualToolbar` is going to be shown. + // Helper function for preventing panel of being displayed is passed along the event. + this.fire( 'beforeShow', () => isStopped = true ); return showPromise; } @@ -254,10 +237,11 @@ export default class ContextualToolbar extends Plugin { /** * This event is fired just before balloon shows. - * It makes possible to listen to this event by an external code and prevent - * ContextualToolbar of being displayed by calling {@link #stop} method. + * It makes possible to listen to this event by an external code and prevent ContextualToolbar + * of being displayed by calling stop function which is passed along this event. * * @event beforeShow + * @param {Function} stop Calling this function prevents panel of being displayed. */ /** diff --git a/tests/toolbar/contextual/contextualtoolbar.js b/tests/toolbar/contextual/contextualtoolbar.js index 5b2ef733..5beed853 100644 --- a/tests/toolbar/contextual/contextualtoolbar.js +++ b/tests/toolbar/contextual/contextualtoolbar.js @@ -403,13 +403,13 @@ describe( 'ContextualToolbar', () => { return promise; } ); - it( 'should not show panel when `beforeShow` is stopped', () => { + it( 'should not show the panel when `beforeShow` event is stopped', () => { const balloonAddSpy = sandbox.spy( balloon, 'add' ); setData( editor.document, 'b[a]r' ); - contextualToolbar.on( 'beforeShow', ( evt ) => { - contextualToolbar.stop( evt ); + contextualToolbar.on( 'beforeShow', ( evt, stop ) => { + stop(); } ); return contextualToolbar._showPanel().then( () => { @@ -418,38 +418,6 @@ describe( 'ContextualToolbar', () => { } ); } ); - describe( 'stop', () => { - it( 'should stop `beforeShow` event', () => { - const evtMock = { - stop: sinon.spy() - }; - - contextualToolbar.stop( evtMock ); - - sinon.assert.calledOnce( evtMock.stop ); - } ); - - it( 'should resolve promise and clean up listener', () => { - const balloonAddSpy = sandbox.spy( balloon, 'add' ); - - setData( editor.document, 'b[a]r' ); - - contextualToolbar.once( 'beforeShow', ( evt ) => { - contextualToolbar.stop( evt ); - } ); - - return contextualToolbar._showPanel() - .then( () => contextualToolbar._hidePanel() ) - .then( () => contextualToolbar._showPanel() ) - .then( () => contextualToolbar._hidePanel() ) - .then( () => contextualToolbar._showPanel() ) - .then( () => { - // Called twice but _showPanel was called thrice. - sinon.assert.calledTwice( balloonAddSpy ); - } ); - } ); - } ); - function stubSelectionRect( forwardSelectionRect, backwardSelectionRect ) { const editingView = editor.editing.view; const originalViewRangeToDom = editingView.domConverter.viewRangeToDom; From 45701ed0ef131d097c277fab68477708dacded60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Wed, 10 May 2017 16:55:41 +0200 Subject: [PATCH 09/11] Improved docs. --- src/toolbar/contextual/contextualtoolbar.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index 4dddeadb..05f8e011 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -134,8 +134,7 @@ export default class ContextualToolbar extends Plugin { * Fires {@link #event:beforeShow} event just before displaying the panel. * * @protected - * @return {Promise} A promise resolved when the {@link #toolbarView} {@link module:ui/view~View#init} is done - * or rejected when panel will be prevented of being displayed. + * @return {Promise} A promise resolved when the {@link #toolbarView} {@link module:ui/view~View#init} is done. */ _showPanel() { const editingView = this.editor.editing.view; From 6031385f4bfc261808890f8c05cf7adb21e6bdae Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Wed, 10 May 2017 16:58:32 +0200 Subject: [PATCH 10/11] Code style and docs fixes. --- src/toolbar/contextual/contextualtoolbar.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index 05f8e011..075b1fc7 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -178,8 +178,10 @@ export default class ContextualToolbar extends Plugin { }, { priority: 'lowest' } ); // Fire this event to inform that `ContextualToolbar` is going to be shown. - // Helper function for preventing panel of being displayed is passed along the event. - this.fire( 'beforeShow', () => isStopped = true ); + // Helper function for preventing the panel from being displayed is passed along with the event. + this.fire( 'beforeShow', () => { + isStopped = true; + } ); return showPromise; } @@ -235,12 +237,12 @@ export default class ContextualToolbar extends Plugin { } /** - * This event is fired just before balloon shows. - * It makes possible to listen to this event by an external code and prevent ContextualToolbar - * of being displayed by calling stop function which is passed along this event. + * This event is fired just before the toolbar shows. + * Using this event, an external code can prevent ContextualToolbar + * from being displayed by calling a `stop` function which is passed along with this event. * * @event beforeShow - * @param {Function} stop Calling this function prevents panel of being displayed. + * @param {Function} stop Calling this function prevents panel from being displayed. */ /** From 827edae3522e20220a26c1430c5392cdc18404bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Wed, 10 May 2017 17:03:17 +0200 Subject: [PATCH 11/11] Removed not necessary value resetting. --- src/toolbar/contextual/contextualtoolbar.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/toolbar/contextual/contextualtoolbar.js b/src/toolbar/contextual/contextualtoolbar.js index 075b1fc7..d3b635e3 100644 --- a/src/toolbar/contextual/contextualtoolbar.js +++ b/src/toolbar/contextual/contextualtoolbar.js @@ -154,7 +154,6 @@ export default class ContextualToolbar extends Plugin { // If `beforeShow` event is not stopped by any external code then panel will be displayed. this.once( 'beforeShow', () => { if ( isStopped ) { - isStopped = false; resolve(); return;