Procházet zdrojové kódy

(TMP) Working draft of FloatingToolbarView.

Aleksander Nowodzinski před 9 roky
rodič
revize
6bcc4d848b

+ 156 - 0
packages/ckeditor5-ui/src/toolbar/floating/floatingtoolbarview.js

@@ -0,0 +1,156 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module ui/toolbar/floating/floatingtoolbarview
+ */
+
+/* globals document */
+
+import global from '@ckeditor/ckeditor5-utils/src/dom/global';
+import Template from '../../template';
+import ToolbarView from '../toolbarview';
+import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';
+import { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';
+
+const toPx = toUnit( 'px' );
+
+/**
+ * The floating toolbar view class.
+ *
+ * @extends module:ui/toolbar/toolbarview~ToolbarView
+ */
+export default class FloatingToolbarView extends ToolbarView {
+	/**
+	 * @inheritDoc
+	 */
+	constructor( locale ) {
+		super( locale );
+
+		const bind = this.bindTemplate;
+
+		/**
+		 * Controls whether the floating toolbar should be active. When any editable
+		 * is focused in the editor, toolbar becomes active.
+		 *
+		 * @readonly
+		 * @observable
+		 * @member {Boolean} #isActive
+		 */
+		this.set( 'isActive', false );
+
+		/**
+		 * The absolute top position of the balloon panel in pixels.
+		 *
+		 * @observable
+		 * @default 0
+		 * @member {Number} #top
+		 */
+		this.set( 'top', 0 );
+
+		/**
+		 * TODO
+		 *
+		 * @readonly
+		 * @observable
+		 * @member {HTMLElement} #limiterElement
+		 */
+		this.set( 'targetElement', null );
+
+		/**
+		 * The absolute left position of the balloon panel in pixels.
+		 *
+		 * @observable
+		 * @default 0
+		 * @member {Number} #left
+		 */
+		this.set( 'left', 0 );
+
+		Template.extend( this.template, {
+			attributes: {
+				class: [
+					'ck-toolbar_floating',
+					bind.if( 'isActive', 'ck-toolbar_active' ),
+				],
+				style: {
+					top: bind.to( 'top', toPx ),
+					left: bind.to( 'left', toPx ),
+				}
+			}
+		} );
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	init() {
+		this.listenTo( global.window, 'scroll', () => this._updatePosition() );
+		this.listenTo( this, 'change:isActive', () => this._updatePosition() );
+
+		return super.init();
+	}
+
+	/**
+	 * Destroys the toolbar and removes the {@link #_elementPlaceholder}.
+	 */
+	destroy() {
+		return super.destroy();
+	}
+
+	/**
+	 * Analyzes the environment to decide where the toolbar should
+	 * be positioned.
+	 *
+	 * @protected
+	 */
+	_updatePosition() {
+		if ( !this.isActive ) {
+			return;
+		}
+
+		const defaultPositions = FloatingToolbarView.defaultPositions;
+
+		const { top, left } = getOptimalPosition( {
+			element: this.element,
+			target: this.targetElement,
+			positions: [
+				defaultPositions.nw,
+				defaultPositions.sw,
+				defaultPositions.ne,
+				defaultPositions.se
+			],
+			limiter: document.body,
+			fitInViewport: true
+		} );
+
+		Object.assign( this, { top, left } );
+	}
+}
+
+FloatingToolbarView.defaultPositions = {
+	nw: ( targetRect, toolbarRect ) => ( {
+		top: targetRect.top - toolbarRect.height,
+		left: targetRect.left,
+		name: 'nw'
+	} ),
+
+	sw: ( targetRect ) => ( {
+		top: targetRect.bottom,
+		left: targetRect.left,
+		name: 'sw'
+	} ),
+
+	ne: ( targetRect, toolbarRect ) => ( {
+		top: targetRect.top - toolbarRect.height,
+		left: targetRect.left + targetRect.width - toolbarRect.width,
+		name: 'ne'
+	} ),
+
+	se: ( targetRect, toolbarRect ) => ( {
+		top: targetRect.bottom,
+		left: targetRect.left + targetRect.width - toolbarRect.width,
+		name: 'se'
+	} )
+};