| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /**
- * @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
- */
- import { isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
- import { findAncestor } from './commands/utils';
- import TableWalker from './tablewalker';
- /**
- * Converts a given {@link module:engine/view/element~Element} to a table widget:
- * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the table widget element.
- * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.
- *
- * @param {module:engine/view/element~Element} viewElement
- * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.
- * @param {String} label The element's label. It will be concatenated with the table `alt` attribute if one is present.
- * @returns {module:engine/view/element~Element}
- */
- export function toTableWidget( viewElement, writer ) {
- writer.setCustomProperty( 'table', true, viewElement );
- return toWidget( viewElement, writer, { hasSelectionHandle: true } );
- }
- /**
- * Checks if a given view element is a table widget.
- *
- * @param {module:engine/view/element~Element} viewElement
- * @returns {Boolean}
- */
- export function isTableWidget( viewElement ) {
- return !!viewElement.getCustomProperty( 'table' ) && isWidget( viewElement );
- }
- /**
- * Returns a table widget editing view element if one is selected.
- *
- * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection
- * @returns {module:engine/view/element~Element|null}
- */
- export function getSelectedTableWidget( selection ) {
- const viewElement = selection.getSelectedElement();
- if ( viewElement && isTableWidget( viewElement ) ) {
- return viewElement;
- }
- return null;
- }
- /**
- * Returns a table widget editing view element if one is among the selection's ancestors.
- *
- * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection
- * @returns {module:engine/view/element~Element|null}
- */
- export function getTableWidgetAncestor( selection ) {
- const parentTable = findAncestor( 'table', selection.getFirstPosition() );
- if ( parentTable && isTableWidget( parentTable.parent ) ) {
- return parentTable.parent;
- }
- return null;
- }
- /**
- * Returns all model table cells that are fully selected (from the outside)
- * within the provided model selection's ranges.
- *
- * To obtain the cells selected from the inside, use
- * {@link module:table/utils~getTableCellsContainingSelection}.
- *
- * @param {module:engine/model/selection~Selection} selection
- * @returns {Array.<module:engine/model/element~Element>}
- */
- export function getSelectedTableCells( selection ) {
- const cells = [];
- for ( const range of sortRanges( selection.getRanges() ) ) {
- const element = range.getContainedElement();
- if ( element && element.is( 'tableCell' ) ) {
- cells.push( element );
- }
- }
- return cells;
- }
- /**
- * Returns all model table cells that the provided model selection's ranges
- * {@link module:engine/model/range~Range#start} inside.
- *
- * To obtain the cells selected from the outside, use
- * {@link module:table/utils~getSelectedTableCells}.
- *
- * @param {module:engine/model/selection~Selection} selection
- * @returns {Array.<module:engine/model/element~Element>}
- */
- export function getTableCellsContainingSelection( selection ) {
- const cells = [];
- for ( const range of selection.getRanges() ) {
- const cellWithSelection = findAncestor( 'tableCell', range.start );
- if ( cellWithSelection ) {
- cells.push( cellWithSelection );
- }
- }
- return cells;
- }
- /**
- * Returns all model table cells that are either completely selected
- * by selection ranges or host selection range
- * {@link module:engine/model/range~Range#start start positions} inside them.
- *
- * Combines {@link module:table/utils~getTableCellsContainingSelection} and
- * {@link module:table/utils~getSelectedTableCells}.
- *
- * @param {module:engine/model/selection~Selection} selection
- * @returns {Array.<module:engine/model/element~Element>}
- */
- export function getSelectionAffectedTableCells( selection ) {
- const selectedCells = getSelectedTableCells( selection );
- if ( selectedCells.length ) {
- return selectedCells;
- }
- return getTableCellsContainingSelection( selection );
- }
- /**
- * Returns an object with `first` and `last` row index contained in the given `tableCells`.
- *
- * const selectedTableCells = getSelectedTableCells( editor.model.document.selection );
- *
- * const { first, last } = getRowIndexes( selectedTableCells );
- *
- * console.log( `Selected rows: ${ first } to ${ last }` );
- *
- * @param {Array.<module:engine/model/element~Element>} tableCells
- * @returns {Object} Returns an object with `first` and `last` table row indexes.
- */
- export function getRowIndexes( tableCells ) {
- const indexes = tableCells.map( cell => cell.parent.index );
- return getFirstLastIndexesObject( indexes );
- }
- /**
- * Returns an object with `first` and `last` column index contained in the given `tableCells`.
- *
- * const selectedTableCells = getSelectedTableCells( editor.model.document.selection );
- *
- * const { first, last } = getColumnIndexes( selectedTableCells );
- *
- * console.log( `Selected columns: ${ first } to ${ last }` );
- *
- * @param {Array.<module:engine/model/element~Element>} tableCells
- * @returns {Object} Returns an object with `first` and `last` table column indexes.
- */
- export function getColumnIndexes( tableCells ) {
- const table = findAncestor( 'table', tableCells[ 0 ] );
- const tableMap = [ ...new TableWalker( table ) ];
- const indexes = tableMap
- .filter( entry => tableCells.includes( entry.cell ) )
- .map( entry => entry.column );
- return getFirstLastIndexesObject( indexes );
- }
- // Helper method to get an object with `first` and `last` indexes from an unsorted array of indexes.
- function getFirstLastIndexesObject( indexes ) {
- const allIndexesSorted = indexes.sort( ( indexA, indexB ) => indexA - indexB );
- const first = allIndexesSorted[ 0 ];
- const last = allIndexesSorted[ allIndexesSorted.length - 1 ];
- return { first, last };
- }
- function sortRanges( rangesIterator ) {
- return Array.from( rangesIterator ).sort( compareRangeOrder );
- }
- function compareRangeOrder( rangeA, rangeB ) {
- // Since table cell ranges are disjoint, it's enough to check their start positions.
- const posA = rangeA.start;
- const posB = rangeB.start;
- // Checking for equal position (returning 0) is not needed because this would be either:
- // a. Intersecting range (not allowed by model)
- // b. Collapsed range on the same position (allowed by model but should not happen).
- return posA.isBefore( posB ) ? -1 : 1;
- }
|