@contrail/document-table 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TablePasteService = void 0;
4
+ const documents_1 = require("@contrail/documents");
5
+ const util_1 = require("@contrail/util");
6
+ const table_merge_service_1 = require("./table-merge.service");
7
+ const table_service_1 = require("./table.service");
8
+ const table_range_1 = require("./table-range");
9
+ class TablePasteService {
10
+ constructor() { }
11
+ static log(...message) {
12
+ this.isDebug && console.log(...message);
13
+ }
14
+ static pasteRowsAndColumns(tableElement, childElements, elementsToPaste, targetRow, targetColumn) {
15
+ var _a, _b, _c;
16
+ const tableToPaste = elementsToPaste.find(e => e.type === 'table');
17
+ const rowsToPaste = elementsToPaste.filter(e => e.type === 'row');
18
+ const columnsToPaste = elementsToPaste.filter(e => e.type === 'column');
19
+ const cellsToPaste = elementsToPaste.filter(e => e.type === 'cell');
20
+ const startRow = targetRow;
21
+ const endRow = startRow + tableToPaste.rowIds.length - 1;
22
+ const startColumn = targetColumn;
23
+ const endColumn = startColumn + tableToPaste.columnIds.length - 1;
24
+ const existingCells = childElements.filter(e => e.type === 'cell');
25
+ const elementsToCreate = [];
26
+ const elementsToUpdate = [];
27
+ let existingMergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements);
28
+ for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {
29
+ const rowToPaste = rowsToPaste[rowIndex - targetRow];
30
+ let existingRowId = tableElement.rowIds[rowIndex];
31
+ let existingRow = childElements.find(e => e.type === 'row' && e.id === existingRowId) ||
32
+ elementsToCreate.find(e => e.type === 'row' && e.id === existingRowId);
33
+ this.log('current row', rowIndex, existingRowId, existingRow);
34
+ if (!existingRowId) {
35
+ const [newRow, ...newRowCells] = (_a = table_service_1.TableService.addRow(tableElement, [...existingCells, ...elementsToCreate], rowIndex, rowToPaste.size.height)) === null || _a === void 0 ? void 0 : _a.elementsToCreate;
36
+ elementsToCreate.push(newRow, ...newRowCells);
37
+ existingRowId = newRow.id;
38
+ existingRow = newRow;
39
+ this.log('added row', rowIndex, existingRowId, existingRow);
40
+ }
41
+ if (rowToPaste.size.height > existingRow.size.height) {
42
+ this.log('resized row', rowIndex, existingRowId, existingRow);
43
+ elementsToUpdate.push(table_service_1.TableService.resizeRow(tableElement, childElements, existingRowId, rowToPaste.size.height)
44
+ .elementsToUpdate[1]);
45
+ }
46
+ for (let columnIndex = startColumn; columnIndex <= endColumn; columnIndex++) {
47
+ const columnToPaste = columnsToPaste[columnIndex - targetColumn];
48
+ let existingColumnId = tableElement.columnIds[columnIndex];
49
+ let existingColumn = childElements.find(e => e.type === 'column' && e.id === existingColumnId) ||
50
+ elementsToCreate.find(e => e.type === 'column' && e.id === existingColumnId);
51
+ this.log('current column', columnIndex, existingColumnId, existingColumn);
52
+ if (!tableElement.columnIds[columnIndex]) {
53
+ const [newColumn, ...newColumnCells] = (_b = table_service_1.TableService.addColumn(tableElement, [...existingCells, ...elementsToCreate], columnIndex, columnToPaste.size.width)) === null || _b === void 0 ? void 0 : _b.elementsToCreate;
54
+ elementsToCreate.push(newColumn, ...newColumnCells);
55
+ existingColumnId = newColumn.id;
56
+ existingColumn = newColumn;
57
+ this.log('added column', columnIndex, existingColumnId, existingColumn);
58
+ }
59
+ if (columnToPaste.size.width > existingColumn.size.width) {
60
+ const updatedColumn = table_service_1.TableService.resizeColumn(tableElement, childElements, existingColumnId, columnToPaste.size.width).elementsToUpdate[1];
61
+ const updatedRowAndCells = table_service_1.TableService.autoFitRows(tableElement, childElements, existingColumnId)
62
+ .elementsToUpdate;
63
+ const uniqueUpdatedRowAndCells = (0, documents_1.uniqueElementsToUpdate)(updatedRowAndCells, elementsToUpdate);
64
+ elementsToUpdate.push(updatedColumn);
65
+ elementsToUpdate.push(...uniqueUpdatedRowAndCells);
66
+ this.log('resized column', columnIndex, existingColumnId, existingColumn);
67
+ this.log('resized column cells and row', uniqueUpdatedRowAndCells, uniqueUpdatedRowAndCells);
68
+ }
69
+ const cellToPaste = cellsToPaste.find(e => e.rowId === rowToPaste.id && e.columnId === columnToPaste.id);
70
+ if (!cellToPaste)
71
+ continue;
72
+ const cellRange = new table_range_1.TableRange(rowIndex, rowIndex, columnIndex, columnIndex);
73
+ const mergedRange = existingMergedRanges.find(range => range.intersects(cellRange));
74
+ const mergedRangeOther = mergedRange && !cellRange.equals(mergedRange.start());
75
+ if (mergedRange) {
76
+ existingMergedRanges = existingMergedRanges.filter(r => !r.equals(mergedRange));
77
+ }
78
+ if (mergedRangeOther) {
79
+ const [updatedTable, ...unmergedCellAndRow] = (_c = table_merge_service_1.TableMergeService.unmerge(tableElement, childElements, mergedRange)) === null || _c === void 0 ? void 0 : _c.elementsToUpdate;
80
+ const uniqueUnmergedCellAndRow = (0, documents_1.uniqueElementsToUpdate)(unmergedCellAndRow, elementsToUpdate);
81
+ elementsToUpdate.push(...uniqueUnmergedCellAndRow);
82
+ this.log('unmerged', mergedRange, unmergedCellAndRow, uniqueUnmergedCellAndRow);
83
+ }
84
+ }
85
+ }
86
+ return { elementsToCreate, elementsToUpdate };
87
+ }
88
+ static pasteTableCells(tableElement, childElements, elementsToPaste, targetRow, targetColumn) {
89
+ const tableToPaste = elementsToPaste.find(e => e.type === 'table');
90
+ const rowsToPaste = elementsToPaste.filter(e => e.type === 'row');
91
+ const columnsToPaste = elementsToPaste.filter(e => e.type === 'column');
92
+ const cellsToPaste = elementsToPaste.filter(e => e.type === 'cell');
93
+ const startRow = targetRow;
94
+ const endRow = startRow + tableToPaste.rowIds.length - 1;
95
+ const startColumn = targetColumn;
96
+ const endColumn = startColumn + tableToPaste.columnIds.length - 1;
97
+ const existingCells = childElements.filter(e => e.type === 'cell');
98
+ const tableUndo = util_1.ObjectUtil.cloneDeep(tableElement);
99
+ const { elementsToUpdate, elementsToCreate } = TablePasteService.pasteRowsAndColumns(tableElement, childElements, elementsToPaste, targetRow, targetColumn);
100
+ for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {
101
+ const rowToPaste = rowsToPaste[rowIndex - targetRow];
102
+ const existingRowId = tableElement.rowIds[rowIndex];
103
+ for (let columnIndex = startColumn; columnIndex <= endColumn; columnIndex++) {
104
+ const columnToPaste = columnsToPaste[columnIndex - targetColumn];
105
+ const existingColumnId = tableElement.columnIds[columnIndex];
106
+ const existingColumn = childElements.find(e => e.type === 'column' && e.id === existingColumnId) ||
107
+ elementsToCreate.find(e => e.type === 'column' && e.id === existingColumnId);
108
+ const cellToPaste = cellsToPaste.find(e => e.rowId === rowToPaste.id && e.columnId === columnToPaste.id);
109
+ if (!cellToPaste)
110
+ continue;
111
+ const createdCell = elementsToCreate.find(e => e.type === 'cell' && e.rowId === existingRowId && e.columnId === existingColumnId);
112
+ const existingCell = existingCells.find(e => e.rowId === existingRowId && e.columnId === existingColumnId);
113
+ const cell = createdCell !== null && createdCell !== void 0 ? createdCell : existingCell;
114
+ const cellUndo = util_1.ObjectUtil.cloneDeep(cell);
115
+ this.log('cell to paste', cellToPaste);
116
+ this.log('pasting to', cell, cellUndo, createdCell);
117
+ cell.text = cellToPaste.text;
118
+ cell.style = util_1.ObjectUtil.mergeDeep(util_1.ObjectUtil.cloneDeep(table_service_1.TableService.DEFAULT_CELL_STYLE), util_1.ObjectUtil.cloneDeep(cellToPaste.style));
119
+ cell.colspan = cellToPaste.colspan > 1 ? cellToPaste.colspan : 1;
120
+ cell.rowspan = cellToPaste.rowspan > 1 ? cellToPaste.rowspan : 1;
121
+ const cellMergedRanged = table_merge_service_1.TableMergeService.getMergedRange(tableElement, cell);
122
+ cell.size.width = cellMergedRanged
123
+ ? table_service_1.TableService.getColumnsWidth(tableElement, [...childElements, ...elementsToCreate], cellMergedRanged.startColumn, cellMergedRanged.endColumn)
124
+ : existingColumn.size.width;
125
+ cell.size.height = table_service_1.TableService.getCellSize(cell).height;
126
+ if (!createdCell && !elementsToUpdate.find(({ change }) => change.id === cell.id)) {
127
+ cellUndo.colspan = cellUndo.colspan > 1 ? cellUndo.colspan : 1;
128
+ cellUndo.rowspan = cellUndo.rowspan > 1 ? cellUndo.rowspan : 1;
129
+ elementsToUpdate.push({
130
+ change: cell,
131
+ undo: cellUndo,
132
+ });
133
+ }
134
+ }
135
+ }
136
+ elementsToUpdate.push({
137
+ change: tableElement,
138
+ undo: tableUndo,
139
+ });
140
+ return {
141
+ elementsToUpdate,
142
+ elementsToCreate,
143
+ };
144
+ }
145
+ }
146
+ exports.TablePasteService = TablePasteService;
147
+ TablePasteService.isDebug = false;
@@ -0,0 +1,33 @@
1
+ export declare class TableRange {
2
+ startRow: number;
3
+ endRow: number;
4
+ startColumn: number;
5
+ endColumn: number;
6
+ constructor(startRow: number, endRow: number, startColumn: number, endColumn: number);
7
+ start(): TableRange;
8
+ get rows(): number;
9
+ get cols(): number;
10
+ singular(): boolean;
11
+ isStart(rowIndex: number, columnIndex: number): boolean;
12
+ eachRow(cb: (index: number) => void, max?: number): TableRange;
13
+ eachColumn(cb: (index: number) => void, max?: number): TableRange;
14
+ each(cb: (rowIndex: number, columnIndex: number) => void): TableRange;
15
+ union(other: TableRange): TableRange;
16
+ intersection(other: TableRange): TableRange;
17
+ intersectsRow(startRow: number, endRow: number): boolean;
18
+ intersectsCol(startCol: number, endCol: number): boolean;
19
+ intersects({ startRow, startColumn, endRow, endColumn }: TableRange): boolean;
20
+ touches(other: TableRange): boolean;
21
+ within(other: TableRange): boolean;
22
+ equals(other: TableRange): boolean;
23
+ difference(range: TableRange): TableRange[];
24
+ }
25
+ export declare function allRangesInOtherRanges(ranges: TableRange[], otherRanges: TableRange[]): boolean;
26
+ export declare function rangesWithinOtherRanges(ranges: TableRange[], otherRanges: TableRange[]): {
27
+ withinRanges: {
28
+ range: TableRange;
29
+ otherRange: TableRange;
30
+ }[];
31
+ otherRanges: TableRange[];
32
+ };
33
+ export declare function uniqueRanges(ranges: TableRange[]): TableRange[];
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uniqueRanges = exports.rangesWithinOtherRanges = exports.allRangesInOtherRanges = exports.TableRange = void 0;
4
+ class TableRange {
5
+ constructor(startRow, endRow, startColumn, endColumn) {
6
+ this.startRow = startRow;
7
+ this.endRow = endRow;
8
+ this.startColumn = startColumn;
9
+ this.endColumn = endColumn;
10
+ }
11
+ start() {
12
+ return new TableRange(this.startRow, this.startRow, this.startColumn, this.startColumn);
13
+ }
14
+ get rows() {
15
+ return this.endRow - this.startRow;
16
+ }
17
+ get cols() {
18
+ return this.endColumn - this.startColumn;
19
+ }
20
+ singular() {
21
+ return this.cols === 0 && this.rows === 0;
22
+ }
23
+ isStart(rowIndex, columnIndex) {
24
+ return this.startRow === rowIndex && this.startColumn === columnIndex;
25
+ }
26
+ eachRow(cb, max) {
27
+ let { endRow } = this;
28
+ if (max && endRow > max)
29
+ endRow = max;
30
+ for (let row = this.startRow; row <= endRow; row += 1) {
31
+ cb(row);
32
+ }
33
+ return this;
34
+ }
35
+ eachColumn(cb, max) {
36
+ let { endColumn } = this;
37
+ if (max && endColumn > max)
38
+ endColumn = max;
39
+ for (let col = this.startColumn; col <= endColumn; col += 1) {
40
+ cb(col);
41
+ }
42
+ return this;
43
+ }
44
+ each(cb) {
45
+ this.eachRow((row) => {
46
+ this.eachColumn((col) => cb(row, col));
47
+ });
48
+ return this;
49
+ }
50
+ union(other) {
51
+ return new TableRange(other.startRow < this.startRow ? other.startRow : this.startRow, other.endRow > this.endRow ? other.endRow : this.endRow, other.startColumn < this.startColumn ? other.startColumn : this.startColumn, other.endColumn > this.endColumn ? other.endColumn : this.endColumn);
52
+ }
53
+ intersection(other) {
54
+ return new TableRange(other.startRow < this.startRow ? this.startRow : other.startRow, other.endRow > this.endRow ? this.endRow : other.endRow, other.startColumn < this.startColumn ? this.startColumn : other.startColumn, other.endColumn > this.endColumn ? this.endColumn : other.endColumn);
55
+ }
56
+ intersectsRow(startRow, endRow) {
57
+ return this.startRow <= endRow && startRow <= this.endRow;
58
+ }
59
+ intersectsCol(startCol, endCol) {
60
+ return this.startColumn <= endCol && startCol <= this.endColumn;
61
+ }
62
+ intersects({ startRow, startColumn, endRow, endColumn }) {
63
+ return this.intersectsCol(startColumn, endColumn) && this.intersectsRow(startRow, endRow);
64
+ }
65
+ touches(other) {
66
+ return ((other.startRow === this.startRow &&
67
+ other.endRow === this.endRow &&
68
+ (other.endColumn + 1 === this.startColumn || this.endColumn + 1 === other.startColumn)) ||
69
+ (other.startColumn === this.startColumn &&
70
+ other.endColumn === this.endColumn &&
71
+ (other.endRow + 1 === this.startRow || this.endRow + 1 === other.startRow)));
72
+ }
73
+ within(other) {
74
+ return (this.startRow >= other.startRow &&
75
+ this.endRow <= other.endRow &&
76
+ this.startColumn >= other.startColumn &&
77
+ this.endColumn <= other.endColumn);
78
+ }
79
+ equals(other) {
80
+ return (this.startRow === other.startRow &&
81
+ this.endRow === other.endRow &&
82
+ this.startColumn === other.startColumn &&
83
+ this.endColumn === other.endColumn);
84
+ }
85
+ difference(range) {
86
+ const ret = [];
87
+ if (!this.intersects(range))
88
+ return ret;
89
+ const { startRow, endRow, startColumn, endColumn } = this;
90
+ const intersectedRange = this.intersection(range);
91
+ const diff = [
92
+ new TableRange(startRow, intersectedRange.startRow - 1, startColumn, endColumn),
93
+ new TableRange(intersectedRange.endRow + 1, endRow, startColumn, endColumn),
94
+ new TableRange(intersectedRange.startRow, intersectedRange.endRow, startColumn, intersectedRange.startColumn - 1),
95
+ new TableRange(intersectedRange.startRow, intersectedRange.endRow, intersectedRange.endColumn + 1, endColumn),
96
+ ];
97
+ return diff.filter((it) => it.rows >= 0 && it.cols >= 0);
98
+ }
99
+ }
100
+ exports.TableRange = TableRange;
101
+ function allRangesInOtherRanges(ranges, otherRanges) {
102
+ if (ranges.length === 0)
103
+ return false;
104
+ let result = true;
105
+ for (const range of ranges) {
106
+ if (!otherRanges.find((r) => r.equals(range))) {
107
+ result = false;
108
+ break;
109
+ }
110
+ }
111
+ return result;
112
+ }
113
+ exports.allRangesInOtherRanges = allRangesInOtherRanges;
114
+ function rangesWithinOtherRanges(ranges, otherRanges) {
115
+ const withinRanges = [];
116
+ const leftoverRanges = [];
117
+ ranges.forEach((range) => {
118
+ otherRanges.forEach((otherRange) => {
119
+ if (range.within(otherRange)) {
120
+ withinRanges.push({ range, otherRange });
121
+ }
122
+ else {
123
+ if (!ranges.find((r) => r.equals(otherRange)) && !leftoverRanges.find((r) => r.equals(otherRange))) {
124
+ leftoverRanges.push(otherRange);
125
+ }
126
+ }
127
+ });
128
+ });
129
+ return { withinRanges, otherRanges: leftoverRanges };
130
+ }
131
+ exports.rangesWithinOtherRanges = rangesWithinOtherRanges;
132
+ function uniqueRanges(ranges) {
133
+ const uniqueRanges = [];
134
+ ranges.forEach((range) => {
135
+ if (!uniqueRanges.find((r) => range.equals(r))) {
136
+ uniqueRanges.push(range);
137
+ }
138
+ });
139
+ return uniqueRanges;
140
+ }
141
+ exports.uniqueRanges = uniqueRanges;
@@ -0,0 +1,42 @@
1
+ import { DocumentElement, PositionDefinition, SizeDefinition, StyleDefinition, DocumentElementChanges } from '@contrail/documents';
2
+ import { TableRange } from './table-range';
3
+ export declare enum TABLE_ERROR {
4
+ UNMERGE_TO_DELETE_COLUMN = "Unmerge cells to delete column",
5
+ UNMERGE_TO_DELETE_ROW = "Unmerge cells to delete row",
6
+ UMMERGE_TO_MOVE_COLUMN = "Unmerge cells to move column",
7
+ UMMERGE_TO_MOVE_ROW = "Unmerge cells to move row",
8
+ INVALID_RANGE_TO_MERGE = "Invalid range to merge",
9
+ INVALID_RANGE_TO_UNMERGE = "Invalid range to unmerge",
10
+ INVALID_TABLE = "Invalid table"
11
+ }
12
+ export declare function tableData(element: DocumentElement): {
13
+ id: string;
14
+ tableId: string;
15
+ type: string;
16
+ };
17
+ export declare function createCell(config: DocumentElement): DocumentElement;
18
+ export declare class TableService {
19
+ constructor();
20
+ static DEFAULT_CELL_STYLE: StyleDefinition;
21
+ static createEmptyTableElement(position: PositionDefinition, rows?: number, columns?: number): Array<DocumentElement>;
22
+ static addColumn(tableElement: DocumentElement, childElements: DocumentElement[], index: any, optionalWidth?: number): DocumentElementChanges;
23
+ static getCellsAtColumn(columnId: string, tableElement: DocumentElement, childElements: DocumentElement[]): DocumentElement[];
24
+ static getCellsAtRow(rowId: string, tableElement: DocumentElement, childElements: DocumentElement[]): DocumentElement[];
25
+ static addRow(tableElement: DocumentElement, childElements: DocumentElement[], index: any, optionalHeight?: number): DocumentElementChanges;
26
+ static getCellsAtRanges(tableElement: DocumentElement, childElements: DocumentElement[], ranges: TableRange[]): DocumentElement[];
27
+ static deleteTable(tableElement: DocumentElement, childElements: DocumentElement[]): DocumentElementChanges;
28
+ static deleteColumns(tableElement: DocumentElement, childElements: DocumentElement[], columnIndexes: number[]): DocumentElementChanges;
29
+ static deleteRows(tableElement: DocumentElement, childElements: DocumentElement[], rowIndexes: number[]): DocumentElementChanges;
30
+ static move(key: 'columnIds' | 'rowIds', tableElement: DocumentElement, childElements: DocumentElement[], from: number, to: number): DocumentElementChanges;
31
+ static resizeRow(tableElement: DocumentElement, childElements: DocumentElement[], rowId: string, height: number): DocumentElementChanges;
32
+ static resizeColumn(tableElement: DocumentElement, childElements: DocumentElement[], columnId: string, width: number): DocumentElementChanges;
33
+ private static getColumns;
34
+ static getColumnsWidth(tableElement: DocumentElement, childElements: DocumentElement[], startIndex: number, endIndex: number): number;
35
+ private static getRows;
36
+ private static getRowsHeight;
37
+ private static getCellMinHeight;
38
+ static autoFitRows(tableElement: DocumentElement, childElements: DocumentElement[], columnId: string): DocumentElementChanges;
39
+ static clearCell(element: DocumentElement): void;
40
+ static getCellSize(element: DocumentElement, text?: string): SizeDefinition;
41
+ static getSize(text: string, style: string): SizeDefinition;
42
+ }