| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
- /**
- * @module ui/contextualballoon
- */
- import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
- import BalloonPanelView from './panel/balloon/balloonpanelview';
- import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
- import nth from '@ckeditor/ckeditor5-utils/src/nth';
- /**
- * Provides the common contextual balloon panel for the editor.
- *
- * This plugin allows reusing a single {module:ui/panel/balloon/balloonpanelview~BalloonPanelView} instance
- * to display multiple contextual balloon panels in the editor.
- *
- * Child views of such a panel are stored in the stack and the last one in the stack is visible. When the
- * visible view is removed from the stack, the previous view becomes visible, etc. If there are no more
- * views in the stack, the balloon panel will hide.
- *
- * It simplifies managing the views and helps
- * avoid the unnecessary complexity of handling multiple {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}
- * instances in the editor.
- *
- * @extends module:core/plugin~Plugin
- */
- export default class ContextualBalloon extends Plugin {
- /**
- * @inheritDoc
- */
- static get pluginName() {
- return 'contextualballoon';
- }
- /**
- * @inheritDoc
- */
- init() {
- /**
- * The common balloon panel view.
- *
- * @readonly
- * @member {module:ui/panel/balloon/balloonpanelview~BalloonPanelView} #view
- */
- this.view = new BalloonPanelView();
- /**
- * Stack of the views injected into the balloon. Last one in the stack is displayed
- * as a content of {@link module:ui/contextualballoon~ContextualBalloon#view}.
- *
- * @private
- * @member {Map} #_stack
- */
- this._stack = new Map();
- // Add balloon panel view to editor `body` collection.
- this.editor.ui.view.body.add( this.view );
- }
- /**
- * Returns the currently visible view or `null` when there are no
- * views in the stack.
- *
- * @returns {module:ui/view~View|null}
- */
- get visibleView() {
- const item = this._stack.get( this.view.content.get( 0 ) );
- return item ? item.view : null;
- }
- /**
- * Returns `true` when the given view is in the stack. Otherwise returns `false`.
- *
- * @param {module:ui/view~View} view
- * @returns {Boolean}
- */
- hasView( view ) {
- return this._stack.has( view );
- }
- /**
- * Adds a new view to the stack and makes it visible.
- *
- * @param {Object} data Configuration of the view.
- * @param {module:ui/view~View} [data.view] Content of the balloon.
- * @param {module:utils/dom/position~Options} [data.position] Positioning options.
- * @param {String} [data.balloonClassName] Additional css class for {@link #view} added when given view is visible.
- */
- add( data ) {
- if ( this.hasView( data.view ) ) {
- /**
- * Trying to add configuration of the same view more than once.
- *
- * @error contextualballoon-add-view-exist
- */
- throw new CKEditorError( 'contextualballoon-add-view-exist: Cannot add configuration of the same view twice.' );
- }
- // When adding view to the not empty balloon.
- if ( this.visibleView ) {
- // Remove displayed content from the view.
- this.view.content.remove( this.visibleView );
- }
- // Add new view to the stack.
- this._stack.set( data.view, data );
- // And display it.
- this._show( data );
- }
- /**
- * Removes the given view from the stack. If the removed view was visible,
- * then the view preceding it in the stack will become visible instead.
- * When there is no view in the stack then balloon will hide.
- *
- * @param {module:ui/view~View} view A view to be removed from the balloon.
- */
- remove( view ) {
- if ( !this.hasView( view ) ) {
- /**
- * Trying to remove configuration of the view not defined in the stack.
- *
- * @error contextualballoon-remove-view-not-exist
- */
- throw new CKEditorError( 'contextualballoon-remove-view-not-exist: Cannot remove configuration of not existing view.' );
- }
- // When visible view is being removed.
- if ( this.visibleView === view ) {
- // We need to remove it from the view content.
- this.view.content.remove( view );
- // And then remove from the stack.
- this._stack.delete( view );
- // Next we need to check if there is other view in stack to show.
- const last = Array.from( this._stack.values() ).pop();
- // If it is some other view.
- if ( last ) {
- // Just show it.
- this._show( last );
- } else {
- // Hide the balloon panel.
- this.view.hide();
- }
- } else {
- // Just remove given view from the stack.
- this._stack.delete( view );
- }
- }
- /**
- * Updates the position of the balloon panel according to the given position data
- * or position data of the first view in the stack.
- *
- * @param {module:utils/dom/position~Options} [position] position options.
- */
- updatePosition( position ) {
- if ( position ) {
- nth( 0, this._stack )[ 1 ].position = position;
- }
- this.view.attachTo( this._getBalloonPosition() );
- }
- /**
- * Sets the view as a content of the balloon and attaches balloon using position
- * options of the first view.
- *
- * @private
- * @param {Object} data Configuration.
- * @param {module:ui/view~View} [data.view] View to show in the balloon.
- * @param {String} [data.balloonClassName=''] View to show in the balloon.
- */
- _show( { view, balloonClassName = '' } ) {
- this.view.content.add( view );
- this.view.className = balloonClassName;
- // When view is not rendered we need to wait for it. See: https://github.com/ckeditor/ckeditor5-ui/issues/187.
- if ( !view.ready ) {
- view.once( 'change:ready', () => this.view.attachTo( this._getBalloonPosition() ) );
- } else {
- this.view.attachTo( this._getBalloonPosition() );
- }
- }
- /**
- * Returns position options of the first view in the stack.
- * This keeps the balloon in the same position when view is changed.
- *
- * @private
- * @returns {module:utils/dom/position~Options}
- */
- _getBalloonPosition() {
- return nth( 0, this._stack )[ 1 ].position;
- }
- /**
- * @inheritDoc
- */
- destroy() {
- this.editor.ui.view.body.remove( this.view );
- this.view.destroy();
- super.destroy();
- }
- }
|