Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Feature: Introduced ContextualBalloon plugin for managing contextual …
Browse files Browse the repository at this point in the history
…balloons. Closes #134.
  • Loading branch information
oskarwrobel committed Apr 5, 2017
2 parents 101b465 + 58d7ce9 commit 3ceb6a6
Show file tree
Hide file tree
Showing 5 changed files with 881 additions and 0 deletions.
192 changes: 192 additions & 0 deletions src/contextualballoon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* @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';

/**
* 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
*/
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 );
}

static get pluginName() {
return 'contextualballoon';
}

/**
* 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} view Content of the balloon.
* @param {module:utils/dom/position~Options} position Positioning options.
*/
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.view );
}

/**
* 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.view );
} 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 position data
* of the first view in the stack.
*/
updatePosition() {
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 {module:ui/view~View} view View to show in the balloon.
*/
_show( view ) {
this.view.content.add( view );
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 Array.from( this._stack.values() )[ 0 ].position;
}

/**
* @inheritDoc
*/
destroy() {
this.editor.ui.view.body.remove( this.view );
this.view.destroy();
super.destroy();
}
}
Loading

0 comments on commit 3ceb6a6

Please sign in to comment.