浏览代码

Introduced FakePanels for ContextualBalloon.

Oskar Wróbel 6 年之前
父节点
当前提交
58fc3f27b9
共有 1 个文件被更改,包括 144 次插入0 次删除
  1. 144 0
      packages/ckeditor5-ui/src/panel/balloon/contextualballoon.js

+ 144 - 0
packages/ckeditor5-ui/src/panel/balloon/contextualballoon.js

@@ -13,12 +13,15 @@ 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 prevIcon from '../../../theme/icons/previous-arrow.svg';
 import nextIcon from '../../../theme/icons/next-arrow.svg';
 
 import '../../../theme/components/panel/balloonrotator.css';
 
+const toPx = toUnit( 'px' );
+
 /**
  * Provides the common contextual balloon for the editor.
  *
@@ -141,6 +144,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.
+		 *
+		 * @private
+		 * @type {module:ui/view~View}
+		 */
+		this._fakePanelsView = this._createFakePanelsView();
 	}
 
 	/**
@@ -260,6 +271,7 @@ export default class ContextualBalloon extends Plugin {
 
 		this.view.pin( this._getBalloonPosition() );
 		this._rotatorView.updateIsNarrow();
+		this._fakePanelsView.updatePosition();
 	}
 
 	/**
@@ -396,6 +408,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, 3 );
+		} );
+
+		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 +442,7 @@ export default class ContextualBalloon extends Plugin {
 		this._rotatorView.showView( view );
 		this.visibleView = view;
 		this.view.pin( this._getBalloonPosition() );
+		this._fakePanelsView.updatePosition();
 	}
 
 	/**
@@ -600,3 +631,116 @@ class RotatorView extends View {
 		return view;
 	}
 }
+
+// @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-panels',
+					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 );
+			}
+		} );
+	}
+
+	// @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 ) {
+			this.top = this._balloonPanelView.top;
+			this.left = this._balloonPanelView.left;
+			this.width = this._balloonPanelView.element.clientWidth;
+			this.height = this._balloonPanelView.element.clientHeight;
+		}
+	}
+}