UNPKG

ckeditor5-image-upload-base64

Version:

The development environment of CKEditor 5 – the best browser-based rich text editor.

130 lines (110 loc) 4.72 kB
/** * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ /** * @module table/utils/ui/contextualballoon */ import { centeredBalloonPositionForLongWidgets } from '@ckeditor/ckeditor5-widget/src/utils'; import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect'; import { getTableWidgetAncestor } from './widget'; import BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview'; const DEFAULT_BALLOON_POSITIONS = BalloonPanelView.defaultPositions; const BALLOON_POSITIONS = [ DEFAULT_BALLOON_POSITIONS.northArrowSouth, DEFAULT_BALLOON_POSITIONS.northArrowSouthWest, DEFAULT_BALLOON_POSITIONS.northArrowSouthEast, DEFAULT_BALLOON_POSITIONS.southArrowNorth, DEFAULT_BALLOON_POSITIONS.southArrowNorthWest, DEFAULT_BALLOON_POSITIONS.southArrowNorthEast ]; const TABLE_PROPERTIES_BALLOON_POSITIONS = [ ...BALLOON_POSITIONS, centeredBalloonPositionForLongWidgets ]; /** * A helper utility that positions the * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} instance * with respect to the table in the editor content, if one is selected. * * @param {module:core/editor/editor~Editor} editor The editor instance. * @param {String} target Either "cell" or "table". Determines the target the balloon will * be attached to. */ export function repositionContextualBalloon( editor, target ) { const balloon = editor.plugins.get( 'ContextualBalloon' ); if ( getTableWidgetAncestor( editor.editing.view.document.selection ) ) { let position; if ( target === 'cell' ) { position = getBalloonCellPositionData( editor ); } else { position = getBalloonTablePositionData( editor ); } balloon.updatePosition( position ); } } /** * Returns the positioning options that control the geometry of the * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} with respect * to the selected table in the editor content. * * @param {module:core/editor/editor~Editor} editor The editor instance. * @returns {module:utils/dom/position~Options} */ export function getBalloonTablePositionData( editor ) { const firstPosition = editor.model.document.selection.getFirstPosition(); const modelTable = firstPosition.findAncestor( 'table' ); const viewTable = editor.editing.mapper.toViewElement( modelTable ); return { target: editor.editing.view.domConverter.viewToDom( viewTable ), positions: TABLE_PROPERTIES_BALLOON_POSITIONS }; } /** * Returns the positioning options that control the geometry of the * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} with respect * to the selected table cell in the editor content. * * @param {module:core/editor/editor~Editor} editor The editor instance. * @returns {module:utils/dom/position~Options} */ export function getBalloonCellPositionData( editor ) { const mapper = editor.editing.mapper; const domConverter = editor.editing.view.domConverter; const selection = editor.model.document.selection; if ( selection.rangeCount > 1 ) { return { target: () => createBoundingRect( selection.getRanges(), editor ), positions: BALLOON_POSITIONS }; } const modelTableCell = getTableCellAtPosition( selection.getFirstPosition() ); const viewTableCell = mapper.toViewElement( modelTableCell ); return { target: domConverter.viewToDom( viewTableCell ), positions: BALLOON_POSITIONS }; } // Returns the first selected table cell from a multi-cell or in-cell selection. // // @param {module:engine/model/position~Position} position Document position. // @returns {module:engine/model/element~Element} function getTableCellAtPosition( position ) { const isTableCellSelected = position.nodeAfter && position.nodeAfter.is( 'element', 'tableCell' ); return isTableCellSelected ? position.nodeAfter : position.findAncestor( 'tableCell' ); } // Returns bounding rectangle for given model ranges. // // @param {Iterable.<module:engine/model/range~Range>} ranges Model ranges that the bounding rect should be returned for. // @param {module:core/editor/editor~Editor} editor The editor instance. // @returns {module:utils/dom/rect~Rect} function createBoundingRect( ranges, editor ) { const mapper = editor.editing.mapper; const domConverter = editor.editing.view.domConverter; const rects = Array.from( ranges ).map( range => { const modelTableCell = getTableCellAtPosition( range.start ); const viewTableCell = mapper.toViewElement( modelTableCell ); return new Rect( domConverter.viewToDom( viewTableCell ) ); } ); return Rect.getBoundingRect( rects ); }