UNPKG

devexpress-richedit

Version:

DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.

228 lines (227 loc) 14.3 kB
import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed'; import { TablePosition } from '../../../common/model/tables/main-structures/table'; import { TableLookTypes } from '../../../common/model/tables/secondary-structures/table-base-structures'; import { TableConditionalFormattingCalculator } from '../../../common/model/tables/table-utils'; import { TableBorders } from '../../../common/model/borders/table-borders'; import { TableBordersHistoryItem, TableCellMarginsHistoryItem, TableLayoutTypeHistoryItem, TableLookTypesHistoryItem, TablePreferredWidthHistoryItem, TableShadingInfoHistoryItem, } from '../../../common/model/history/items/tables/table-properties-history-items'; import { ApplyTableStyleHistoryItem } from '../../../common/model/history/items/apply-style-history-items'; import { ShadingInfo } from '../../../common/model/shadings/shading-info'; import { StylesManager } from '../../../common/model/styles-manager'; import { InputPositionBase } from '../../../common/selection/input-position-base'; import { SelectionIntervalsInfo } from '../../../common/selection/selection-intervals-info'; import { TableRowCollection } from '../collections/table/table-row-collection'; import { IntervalApi } from '../interval'; import { TableCellApi } from './table-cell'; import { TableBordersApi } from './table-borders'; import { TABLE_STYLE_OPTIONS_KEYS, TableStyleOptionsApi } from './table-style-options'; import { ApiParametersChecker } from '../api-utils/parameter-checker'; import { TableElementBase } from './table-element-base'; export class TableApi extends TableElementBase { constructor(processor, subDocument, table) { super(processor, subDocument); this._table = table; } get index() { return this._table.index; } get interval() { return new IntervalApi(this._table.interval.start, this._table.interval.length); } delete() { this._processor.beginUpdate(); this._modelManipulator.table.removeTableWithContent(this._subDocument, this._table); this._processor.endUpdate(); } get rows() { return new TableRowCollection(this._processor, this._subDocument, this._table, this); } get parentCell() { const parentCell = this._table.parentCell; if (!parentCell) return null; const parentRow = parentCell.parentRow; const parentTable = parentRow.parentTable; const parentRowIndex = parentTable.rows.indexOf(parentRow); const parentCellIndex = parentRow.cells.indexOf(parentCell); const tablePosition = new TablePosition(parentTable, parentRowIndex, parentCellIndex).init(); return new TableCellApi(this._processor, this._subDocument, tablePosition); } get autoFit() { return Boolean(this._table.getActualTableLayout(this._table.properties)); } set autoFit(value) { const valueDescriptor = ApiParametersChecker.booleanDescriptor('autoFit', (val) => val); ApiParametersChecker.check(value, 1, false, [valueDescriptor]); const historyItem = new TableLayoutTypeHistoryItem(this._modelManipulator, this._subDocument, this._table.index, Number(value), true); this._history.addAndRedo(historyItem); } get width() { return this._getWidth(this._table.preferredWidth); } set width(value) { this._validateWidth(value); const preferredWidth = this._getModelWidth(value); const historyItem = new TablePreferredWidthHistoryItem(this._modelManipulator, this._subDocument, this._table.index, preferredWidth); this._history.addAndRedo(historyItem); } get styleName() { return this._table.style.styleName; } set styleName(value) { var _a; const valueDescriptor = ApiParametersChecker.stringDescriptor('style', (val) => val, false); ApiParametersChecker.check(value, 1, false, [valueDescriptor]); const model = this._processor.modelManager.model; const tableStyle = model.getTableStyleByName(value) || model.stylesManager.addTableStyle((_a = StylesManager.getPresetTableStyleByName(value)) === null || _a === void 0 ? void 0 : _a.clone()); if (!tableStyle) throw new Error('Style not found.'); const historyItem = new ApplyTableStyleHistoryItem(this._modelManipulator, this._subDocument, this._table.index, tableStyle); this._history.addAndRedo(historyItem); } get tableStyleOptions() { const lookTypes = this._table.lookTypes; return new TableStyleOptionsApi(!!(lookTypes & TableLookTypes.ApplyFirstRow), !!(lookTypes & TableLookTypes.ApplyLastRow), !(lookTypes & TableLookTypes.DoNotApplyRowBanding), !!(lookTypes & TableLookTypes.ApplyFirstColumn), !!(lookTypes & TableLookTypes.ApplyLastColumn), !(lookTypes & TableLookTypes.DoNotApplyColumnBanding)); } set tableStyleOptions(value) { const valueDescriptor = ApiParametersChecker.objectDescriptor('tableStyleOptions', 'TableStyleOptions', (val) => val); ApiParametersChecker.check(value, 1, false, [valueDescriptor]); for (const key of TABLE_STYLE_OPTIONS_KEYS) { const tableLookTypeDescriptor = ApiParametersChecker.booleanDescriptor(`tableStyleOptions.${key}`, (val) => val); ApiParametersChecker.check(value[key], 1, false, [tableLookTypeDescriptor]); } let lookTypes = this._table.lookTypes; lookTypes = this._calculateTableLook(value.headerRow, lookTypes, TableLookTypes.ApplyFirstRow); lookTypes = this._calculateTableLook(value.totalRow, lookTypes, TableLookTypes.ApplyLastRow); lookTypes = this._calculateTableLook(!value.bandedRows, lookTypes, TableLookTypes.DoNotApplyRowBanding); lookTypes = this._calculateTableLook(value.firstColumn, lookTypes, TableLookTypes.ApplyFirstColumn); lookTypes = this._calculateTableLook(value.lastColumn, lookTypes, TableLookTypes.ApplyLastColumn); lookTypes = this._calculateTableLook(!value.bandedColumns, lookTypes, TableLookTypes.DoNotApplyColumnBanding); this._processor.beginUpdate(); this._history.addTransaction(() => { const historyItem = new TableLookTypesHistoryItem(this._modelManipulator, this._subDocument, this._table.index, lookTypes); this._history.addAndRedo(historyItem); TableConditionalFormattingCalculator.updateTable(this._processor.modelManager, this._table, this._subDocument); }); this._processor.endUpdate(); } _calculateTableLook(value, currentLookTypes, lookType) { return !!value ? currentLookTypes | lookType : currentLookTypes & ~lookType; } get backgroundColor() { const shadingInfo = this._table.getActualShadingInfo(this._table.properties); return this._getBackgroundColor(shadingInfo); } set backgroundColor(value) { const color = this._validateColor(value, 1, 'backgroundColor'); const shadingInfo = ShadingInfo.createByColor(color); const historyItem = new TableShadingInfoHistoryItem(this._modelManipulator, this._subDocument, this._table.index, shadingInfo, true); this._history.addAndRedo(historyItem); } get contentHorizontalAlignment() { const alignment = this._getStartHorizontalAlignment(this._table.getFirstCell()); const allAlignmentsSame = this._table.rows.every(row => row.cells.every(cell => { const paragraphs = this._subDocument.getParagraphsByInterval(cell.interval); return paragraphs.every(paragraph => paragraph.getParagraphMergedProperties().alignment === alignment); })); if (!allAlignmentsSame) return null; return Number(alignment); } set contentHorizontalAlignment(value) { this._validateContentHorizontalAlignment(value); this._processor.beginUpdate(); this._history.addTransaction(() => { this._table.rows.forEach(row => { row.cells.forEach(cell => this._setCellHorizontalAlignment(cell, value)); }); }); this._processor.endUpdate(); } get contentVerticalAlignment() { const alignment = this._table.getFirstCell().properties.verticalAlignment; const allAlignmentsSame = this._table.rows.every(row => row.cells.every(cell => cell.properties.verticalAlignment === alignment)); if (!allAlignmentsSame) return null; return Number(alignment); } set contentVerticalAlignment(value) { this._validateContentVerticalAlignment(value); this._processor.beginUpdate(); this._history.addTransaction(() => { this._table.rows.forEach((row, rowIndex) => { row.cells.forEach((_, cellIndex) => { const tablePosition = new TablePosition(this._table, rowIndex, cellIndex).init(); return this._setCellVerticalAlignment(tablePosition, value); }); }); }); this._processor.endUpdate(); } get borders() { const tableBorders = this._table.getActualBorders(this._table.properties); return this._getBordersApi(TableBordersApi, tableBorders); } set borders(value) { const tableBorders = this._validateBorders(TableBorders, value); const bordersList = [tableBorders.top, tableBorders.right, tableBorders.bottom, tableBorders.left, tableBorders.insideHorizontal, tableBorders.insideVertical]; const newUsesList = bordersList.map(border => !!border ? true : void 0); const historyItem = new TableBordersHistoryItem(this._modelManipulator, this._subDocument, this._table.index, bordersList, newUsesList); this._history.addAndRedo(historyItem); } get cellMargins() { const margins = this._table.getActualMargins(this._table.properties).clone(); return this._getMarginsApi(margins); } set cellMargins(value) { const margins = this._validateMargins(value, 'cellMargins'); const marginsList = [margins.top, margins.right, margins.bottom, margins.left]; const newUsesList = marginsList.map(margin => !!margin ? true : void 0); const historyItem = new TableCellMarginsHistoryItem(this._modelManipulator, this._subDocument, this._table.index, marginsList, newUsesList); this._history.addAndRedo(historyItem); } mergeCells(startPosition, endPosition) { this._validatePosition(startPosition, 'startPosition', 1); this._validatePosition(endPosition, 'endPosition', 2); const startPositionFirstColumn = this._table.rows[startPosition.rowIndex].getCellColumnIndex(startPosition.cellIndex); const startPositionLastColumn = this._table.rows[startPosition.rowIndex].getCellColumnIndex(startPosition.cellIndex + 1) - 1; const endPositionFirstColumn = this._table.rows[endPosition.rowIndex].getCellColumnIndex(endPosition.cellIndex); const endPositionLastColumn = this._table.rows[endPosition.rowIndex].getCellColumnIndex(endPosition.cellIndex + 1) - 1; const startRowIndex = Math.min(startPosition.rowIndex, endPosition.rowIndex); const endRowIndex = Math.max(startPosition.rowIndex, endPosition.rowIndex); const startColumnIndex = Math.min(startPositionFirstColumn, endPositionFirstColumn); const endColumnIndex = Math.max(startPositionLastColumn, endPositionLastColumn); const intervals = []; for (let i = startRowIndex; i <= endRowIndex; i++) { const startCellIndex = this._table.rows[i].getCellIndex(startColumnIndex); const endCellIndex = this._table.rows[i].getCellIndex(endColumnIndex); const intervalStart = this._table.rows[i].cells[startCellIndex].interval.start; const intervalEnd = this._table.rows[i].cells[endCellIndex].interval.end; intervals.push(FixedInterval.fromPositions(intervalStart, intervalEnd)); } const tblInfo = new SelectionIntervalsInfo(this._subDocument, intervals).tableInfo; if (!tblInfo.extendedData.isSquare) throw new Error('You can only merge adjacent cells that form a rectangular or square shape.'); const inputPositionIntervals = new SelectionIntervalsInfo(this._subDocument, intervals); const inputPosition = new InputPositionBase().setIntervals(inputPositionIntervals); this._processor.beginUpdate(); this._history.addTransaction(() => { this._modelManipulator.table.mergeSelectedTableCellsHorizontally(this._subDocument, tblInfo, inputPosition); this._modelManipulator.table.mergeSelectedTableCellsVertically(this._subDocument, tblInfo, inputPosition); this._modelManipulator.table.normalizeRows(this._subDocument, this._table); this._modelManipulator.table.normalizeTableGrid(this._subDocument, this._table); this._modelManipulator.table.normalizeCellColumnSpans(this._subDocument, this._table, false); TableConditionalFormattingCalculator.updateTable(this._processor.modelManager, this._table, this._subDocument); }); this._processor.endUpdate(); } _validatePosition(position, parameterName, parameterIndex) { const positionDescriptor = ApiParametersChecker.objectDescriptor(parameterName, 'PositionCell', (val) => val); ApiParametersChecker.check(position, parameterIndex, false, [positionDescriptor]); const maxRowIndex = this._table.rows.length; const rowIndexDescriptor = ApiParametersChecker.numberDescriptor(`${parameterName}.rowIndex`, (val) => val, 0, maxRowIndex); ApiParametersChecker.check(position.rowIndex, parameterIndex, false, [rowIndexDescriptor]); const maxCellIndex = this._table.rows[position.rowIndex].cells.length; const cellIndexDescriptor = ApiParametersChecker.numberDescriptor(`${parameterName}.cellIndex`, (val) => val, 0, maxCellIndex); ApiParametersChecker.check(position.cellIndex, parameterIndex, false, [cellIndexDescriptor]); } }