-
Notifications
You must be signed in to change notification settings - Fork 18
Introduced ContextualBalloon class for managing contextual balloons. #177
Changes from 15 commits
24b3784
66ed2ac
3c7fb73
20804ee
7b008e2
1958b63
0ff3a52
28ba5b2
67ee399
d4b1470
3de51b3
24e5c60
a23df06
782cb5c
c334894
dc1f532
58d7ce9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/** | ||
* @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 configuration of the currently visible view or `null` when there are no | ||
* views in the stack. | ||
* | ||
* @returns {module:ui/contextualballoon~ViewConfig|null} | ||
*/ | ||
get visible() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
https://github.com/ckeditor/ckeditor5-design/wiki/Code-Style-Naming-Guidelines There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This getter returns visible view. It's not checking if given view is visible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm... this returns not only the view but the whole configuration There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But maybe only the view should be returned. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm... looks like there is no need to return the balloon position configuration because this position is used internally by ContextualBalloon. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
return this._stack.get( this.view.content.get( 0 ) ) || 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 {module:ui/contextualballoon~ViewConfig} data Configuration of the view. | ||
*/ | ||
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.visible ) { | ||
// Remove displayed content from the view. | ||
this.view.content.remove( this.visible.view ); | ||
} | ||
|
||
// 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.visible.view === 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 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/contextualballoon~ViewConfig} data Configuration of the view. | ||
*/ | ||
_show( data ) { | ||
this.view.content.add( data.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(); | ||
} | ||
} | ||
|
||
/** | ||
* An object describing configuration of a single view added to the balloon stack. | ||
* | ||
* @typedef {Object} module:ui/contextualballoon~ViewConfig | ||
* | ||
* @property {module:ui/view~View} view Content of the balloon. | ||
* @property {module:utils/dom/position~Options} position Positioning options. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An afterthought: Since
_stack
is private we should not talk in the public docs about it. It is of no concern to the devs how the CB handles views.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I wrote about stack I wasn't thinking about var name but about the way how we store it.