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
JavaScript
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]);
}
}