@ckeditor/ckeditor5-table
Version:
Table feature for CKEditor 5.
107 lines (106 loc) • 4.23 kB
JavaScript
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @module table/utils/ui/contextualballoon
*/
import { Rect } from 'ckeditor5/src/utils';
import { BalloonPanelView } from 'ckeditor5/src/ui';
import { getTableWidgetAncestor } from './widget';
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,
DEFAULT_BALLOON_POSITIONS.viewportStickyNorth
];
/**
* 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 editor The editor instance.
* @param 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 editor The editor instance.
*/
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.mapViewToDom(viewTable),
positions: 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 editor The editor instance.
*/
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.mapViewToDom(viewTableCell),
positions: BALLOON_POSITIONS
};
}
/**
* Returns the first selected table cell from a multi-cell or in-cell selection.
*
* @param position Document position.
*/
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 ranges Model ranges that the bounding rect should be returned for.
* @param editor The editor instance.
*/
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.mapViewToDom(viewTableCell));
});
return Rect.getBoundingRect(rects);
}