|
|
@@ -13,11 +13,16 @@ import View from '../../view';
|
|
|
import ButtonView from '../../button/buttonview';
|
|
|
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
|
|
|
import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
|
|
|
+import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';
|
|
|
+import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';
|
|
|
|
|
|
import prevIcon from '../../../theme/icons/previous-arrow.svg';
|
|
|
import nextIcon from '../../../theme/icons/next-arrow.svg';
|
|
|
|
|
|
import '../../../theme/components/panel/balloonrotator.css';
|
|
|
+import '../../../theme/components/panel/fakepanel.css';
|
|
|
+
|
|
|
+const toPx = toUnit( 'px' );
|
|
|
|
|
|
/**
|
|
|
* Provides the common contextual balloon for the editor.
|
|
|
@@ -141,6 +146,14 @@ export default class ContextualBalloon extends Plugin {
|
|
|
* @type {module:ui/panel/balloon/contextualballoon~RotatorView}
|
|
|
*/
|
|
|
this._rotatorView = this._createRotatorView();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Displays fake panels under the balloon panel view when multiple stacks are added to the balloon.
|
|
|
+ *
|
|
|
+ * @private
|
|
|
+ * @type {module:ui/view~View}
|
|
|
+ */
|
|
|
+ this._fakePanelsView = this._createFakePanelsView();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -259,7 +272,7 @@ export default class ContextualBalloon extends Plugin {
|
|
|
}
|
|
|
|
|
|
this.view.pin( this._getBalloonPosition() );
|
|
|
- this._rotatorView.updateIsNarrow();
|
|
|
+ this._fakePanelsView.updatePosition();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -396,6 +409,24 @@ export default class ContextualBalloon extends Plugin {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * @returns {module:ui/view~View}
|
|
|
+ */
|
|
|
+ _createFakePanelsView() {
|
|
|
+ const view = new FakePanelsView( this.editor.locale, this.view );
|
|
|
+
|
|
|
+ view.bind( 'numberOfPanels' ).to( this, '_numberOfStacks', number => {
|
|
|
+ return number < 2 ? 0 : Math.min( number - 1, 2 );
|
|
|
+ } );
|
|
|
+
|
|
|
+ view.listenTo( this.view, 'change:top', () => view.updatePosition() );
|
|
|
+ view.listenTo( this.view, 'change:left', () => view.updatePosition() );
|
|
|
+
|
|
|
+ this.editor.ui.view.body.add( view );
|
|
|
+
|
|
|
+ return view;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* Sets the view as a content of the balloon and attaches balloon using position
|
|
|
* options of the first view.
|
|
|
*
|
|
|
@@ -412,6 +443,7 @@ export default class ContextualBalloon extends Plugin {
|
|
|
this._rotatorView.showView( view );
|
|
|
this.visibleView = view;
|
|
|
this.view.pin( this._getBalloonPosition() );
|
|
|
+ this._fakePanelsView.updatePosition();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -461,13 +493,6 @@ class RotatorView extends View {
|
|
|
this.set( 'isNavigationVisible', true );
|
|
|
|
|
|
/**
|
|
|
- * Defines whether balloon should be marked as narrow or not.
|
|
|
- *
|
|
|
- * @member {Boolean} #isNarrow
|
|
|
- */
|
|
|
- this.set( 'isNarrow', false );
|
|
|
-
|
|
|
- /**
|
|
|
* Used for checking if view is focused or not.
|
|
|
*
|
|
|
* @type {module:utils/focustracker~FocusTracker}
|
|
|
@@ -521,8 +546,7 @@ class RotatorView extends View {
|
|
|
|
|
|
attributes: {
|
|
|
class: [
|
|
|
- 'ck-balloon-rotator__counter',
|
|
|
- bind.to( 'isNarrow', value => value ? 'ck-hidden' : '' )
|
|
|
+ 'ck-balloon-rotator__counter'
|
|
|
]
|
|
|
},
|
|
|
|
|
|
@@ -556,13 +580,6 @@ class RotatorView extends View {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Checks if view width is narrow and updated {@link ~RotatorView#isNarrow} state.
|
|
|
- */
|
|
|
- updateIsNarrow() {
|
|
|
- this.isNarrow = this.element.clientWidth <= 200;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
* Shows given view.
|
|
|
*
|
|
|
* @param {module:ui/view~View} view The view to show.
|
|
|
@@ -570,7 +587,6 @@ class RotatorView extends View {
|
|
|
showView( view ) {
|
|
|
this.hideView();
|
|
|
this.content.add( view );
|
|
|
- this.updateIsNarrow();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -600,3 +616,120 @@ class RotatorView extends View {
|
|
|
return view;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// Displays additional layers under the balloon when multiple stacks are added to the balloon.
|
|
|
+//
|
|
|
+// @private
|
|
|
+// @extends module:ui/view~View
|
|
|
+class FakePanelsView extends View {
|
|
|
+ // @inheritDoc
|
|
|
+ constructor( locale, balloonPanelView ) {
|
|
|
+ super( locale );
|
|
|
+
|
|
|
+ const bind = this.bindTemplate;
|
|
|
+
|
|
|
+ // Fake panels top offset.
|
|
|
+ //
|
|
|
+ // @observable
|
|
|
+ // @member {Number} #top
|
|
|
+ this.set( 'top', 0 );
|
|
|
+
|
|
|
+ // Fake panels left offset.
|
|
|
+ //
|
|
|
+ // @observable
|
|
|
+ // @member {Number} #left
|
|
|
+ this.set( 'left', 0 );
|
|
|
+
|
|
|
+ // Fake panels height.
|
|
|
+ //
|
|
|
+ // @observable
|
|
|
+ // @member {Number} #height
|
|
|
+ this.set( 'height', 0 );
|
|
|
+
|
|
|
+ // Fake panels width.
|
|
|
+ //
|
|
|
+ // @observable
|
|
|
+ // @member {Number} #width
|
|
|
+ this.set( 'width', 0 );
|
|
|
+
|
|
|
+ // Number of rendered fake panels.
|
|
|
+ //
|
|
|
+ // @observable
|
|
|
+ // @member {Number} #numberOfPanels
|
|
|
+ this.set( 'numberOfPanels', 0 );
|
|
|
+
|
|
|
+ // Collection of the child views which creates fake panel content.
|
|
|
+ //
|
|
|
+ // @readonly
|
|
|
+ // @type {module:ui/viewcollection~ViewCollection}
|
|
|
+ this.content = this.createCollection();
|
|
|
+
|
|
|
+ // Context.
|
|
|
+ //
|
|
|
+ // @private
|
|
|
+ // @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}
|
|
|
+ this._balloonPanelView = balloonPanelView;
|
|
|
+
|
|
|
+ this.setTemplate( {
|
|
|
+ tag: 'div',
|
|
|
+ attributes: {
|
|
|
+ class: [
|
|
|
+ 'ck-fake-panel',
|
|
|
+ bind.to( 'numberOfPanels', number => number ? '' : 'ck-hidden' )
|
|
|
+ ],
|
|
|
+ style: {
|
|
|
+ top: bind.to( 'top', toPx ),
|
|
|
+ left: bind.to( 'left', toPx ),
|
|
|
+ width: bind.to( 'width', toPx ),
|
|
|
+ height: bind.to( 'height', toPx )
|
|
|
+ }
|
|
|
+ },
|
|
|
+ children: this.content
|
|
|
+ } );
|
|
|
+
|
|
|
+ this.on( 'change:numberOfPanels', ( evt, name, next, prev ) => {
|
|
|
+ if ( next > prev ) {
|
|
|
+ this._addPanels( next - prev );
|
|
|
+ } else {
|
|
|
+ this._removePanels( prev - next );
|
|
|
+ }
|
|
|
+
|
|
|
+ this.updatePosition();
|
|
|
+ } );
|
|
|
+ }
|
|
|
+
|
|
|
+ // @private
|
|
|
+ // @param {Number} number
|
|
|
+ _addPanels( number ) {
|
|
|
+ while ( number-- ) {
|
|
|
+ const view = new View();
|
|
|
+
|
|
|
+ view.setTemplate( { tag: 'div' } );
|
|
|
+
|
|
|
+ this.content.add( view );
|
|
|
+ this.registerChild( view );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // @private
|
|
|
+ // @param {Number} number
|
|
|
+ _removePanels( number ) {
|
|
|
+ while ( number-- ) {
|
|
|
+ const view = this.content.last;
|
|
|
+
|
|
|
+ this.content.remove( view );
|
|
|
+ this.deregisterChild( view );
|
|
|
+ view.destroy();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Updates coordinates of fake panels.
|
|
|
+ updatePosition() {
|
|
|
+ if ( this.numberOfPanels ) {
|
|
|
+ const { top, left } = this._balloonPanelView;
|
|
|
+ const { width, height } = new Rect( this._balloonPanelView.element );
|
|
|
+
|
|
|
+ Object.assign( this, { top, left, width, height } );
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|