8
0
Просмотр исходного кода

Merge pull request #226 from ckeditor/t/222

Other: Added the `beforeShow` event to the `ContextualToolbar` plugin. Closes #222.
Aleksander Nowodzinski 8 лет назад
Родитель
Сommit
0acaebd9ac

+ 43 - 9
packages/ckeditor5-ui/src/toolbar/contextual/contextualtoolbar.js

@@ -131,11 +131,14 @@ export default class ContextualToolbar extends Plugin {
 	/**
 	 * 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.
 	 */
 	_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 ) ) {
@@ -147,17 +150,39 @@ 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 ) => {
+			// If `beforeShow` event is not stopped by any external code then panel will be displayed.
+			this.once( 'beforeShow', () => {
+				if ( isStopped ) {
+					resolve();
+
+					return;
+				}
+
+				// 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'
+					} )
+				);
+			} );
+		}, { priority: 'lowest' } );
+
+		// Fire this event to inform that `ContextualToolbar` is going to be shown.
+		// Helper function for preventing the panel from being displayed is passed along with the event.
+		this.fire( 'beforeShow', () => {
+			isStopped = true;
 		} );
 
-		// Add panel to the common editor contextual balloon.
-		return this._balloon.add( {
-			view: this.toolbarView,
-			position: this._getBalloonPositionData(),
-			balloonClassName: 'ck-toolbar-container'
-		} );
+		return showPromise;
 	}
 
 	/**
@@ -210,6 +235,15 @@ export default class ContextualToolbar extends Plugin {
 		super.destroy();
 	}
 
+	/**
+	 * 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 from being displayed.
+	 */
+
 	/**
 	 * 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`.

+ 31 - 1
packages/ckeditor5-ui/tests/toolbar/contextual/contextualtoolbar.js

@@ -49,6 +49,7 @@ describe( 'ContextualToolbar', () => {
 
 	afterEach( () => {
 		sandbox.restore();
+		editorElement.remove();
 
 		return editor.destroy();
 	} );
@@ -234,7 +235,7 @@ describe( 'ContextualToolbar', () => {
 		let removeBalloonSpy;
 
 		beforeEach( () => {
-			removeBalloonSpy = sandbox.spy( balloon, 'remove' );
+			removeBalloonSpy = sandbox.stub( balloon, 'remove', () => {} );
 			editor.editing.view.isFocused = true;
 		} );
 
@@ -388,6 +389,35 @@ 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, '<paragraph>b[a]r</paragraph>' );
+
+			const promise = contextualToolbar._showPanel();
+
+			sinon.assert.calledOnce( spy );
+
+			return promise;
+		} );
+
+		it( 'should not show the panel when `beforeShow` event is stopped', () => {
+			const balloonAddSpy = sandbox.spy( balloon, 'add' );
+
+			setData( editor.document, '<paragraph>b[a]r</paragraph>' );
+
+			contextualToolbar.on( 'beforeShow', ( evt, stop ) => {
+				stop();
+			} );
+
+			return contextualToolbar._showPanel().then( () => {
+				sinon.assert.notCalled( balloonAddSpy );
+			} );
+		} );
+	} );
+
 	function stubSelectionRect( forwardSelectionRect, backwardSelectionRect ) {
 		const editingView = editor.editing.view;
 		const originalViewRangeToDom = editingView.domConverter.viewRangeToDom;