@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.
- package/README.md +1 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +23 -0
- package/lib/table-border-ranges.d.ts +5 -0
- package/lib/table-border-ranges.js +47 -0
- package/lib/table-constants.d.ts +18 -0
- package/lib/table-constants.js +21 -0
- package/lib/table-copy.service.d.ts +8 -0
- package/lib/table-copy.service.js +295 -0
- package/lib/table-merge.service.d.ts +11 -0
- package/lib/table-merge.service.js +143 -0
- package/lib/table-paste.service.d.ts +8 -0
- package/lib/table-paste.service.js +147 -0
- package/lib/table-range.d.ts +33 -0
- package/lib/table-range.js +141 -0
- package/lib/table.service.d.ts +42 -0
- package/lib/table.service.js +630 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Supplies common data structures and logic for managing document tables.
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./table-border-ranges"), exports);
|
|
18
|
+
__exportStar(require("./table-constants"), exports);
|
|
19
|
+
__exportStar(require("./table-copy.service"), exports);
|
|
20
|
+
__exportStar(require("./table-merge.service"), exports);
|
|
21
|
+
__exportStar(require("./table-paste.service"), exports);
|
|
22
|
+
__exportStar(require("./table.service"), exports);
|
|
23
|
+
__exportStar(require("./table-range"), exports);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { TableRange } from './table-range';
|
|
2
|
+
export type TableBorderType = 'all' | 'outside';
|
|
3
|
+
export declare function tableBorderRanges(range: TableRange, mergedRanges: TableRange[], includeMergeIfFirstCell?: boolean): [TableRange, TableBorderType][];
|
|
4
|
+
export declare function selectedTableBorderRanges(selectedRanges: TableRange[], mergedRanges: TableRange[]): [TableRange, TableBorderType][];
|
|
5
|
+
export declare function mergedTableRanges(range: TableRange, mergedRanges: TableRange[], includeMergeIfFirstCell?: boolean): TableRange[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergedTableRanges = exports.selectedTableBorderRanges = exports.tableBorderRanges = void 0;
|
|
4
|
+
const table_range_1 = require("./table-range");
|
|
5
|
+
function tableBorderRanges(range, mergedRanges, includeMergeIfFirstCell = false) {
|
|
6
|
+
const intersectedMergedRanges = mergedRanges.filter((r) => r.intersects(range));
|
|
7
|
+
const borderRanges = [];
|
|
8
|
+
if (intersectedMergedRanges.length <= 0) {
|
|
9
|
+
borderRanges.push([range, 'all']);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
for (let merge of intersectedMergedRanges) {
|
|
13
|
+
if (includeMergeIfFirstCell) {
|
|
14
|
+
if (merge.start().within(range)) {
|
|
15
|
+
borderRanges.push([merge, 'outside']);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
borderRanges.push([merge, 'outside']);
|
|
20
|
+
}
|
|
21
|
+
if (!range.within(merge)) {
|
|
22
|
+
const otherIntersectedMergedRanges = intersectedMergedRanges.filter((r) => !r.equals(merge));
|
|
23
|
+
range.difference(merge).forEach((diffRange) => {
|
|
24
|
+
borderRanges.push(...tableBorderRanges(diffRange, otherIntersectedMergedRanges, includeMergeIfFirstCell));
|
|
25
|
+
});
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return borderRanges;
|
|
31
|
+
}
|
|
32
|
+
exports.tableBorderRanges = tableBorderRanges;
|
|
33
|
+
function selectedTableBorderRanges(selectedRanges, mergedRanges) {
|
|
34
|
+
const selectedBorderRanges = [];
|
|
35
|
+
for (const range of selectedRanges) {
|
|
36
|
+
selectedBorderRanges.push(...tableBorderRanges(range, mergedRanges));
|
|
37
|
+
}
|
|
38
|
+
return selectedBorderRanges;
|
|
39
|
+
}
|
|
40
|
+
exports.selectedTableBorderRanges = selectedTableBorderRanges;
|
|
41
|
+
function mergedTableRangesRec(range, mergedRanges, includeMergeIfFirstCell = false) {
|
|
42
|
+
return tableBorderRanges(range, mergedRanges, includeMergeIfFirstCell).map(([range, borderType]) => range);
|
|
43
|
+
}
|
|
44
|
+
function mergedTableRanges(range, mergedRanges, includeMergeIfFirstCell = false) {
|
|
45
|
+
return (0, table_range_1.uniqueRanges)(mergedTableRangesRec(range, mergedRanges, includeMergeIfFirstCell));
|
|
46
|
+
}
|
|
47
|
+
exports.mergedTableRanges = mergedTableRanges;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const TABLE_ROW_MIN_HEIGHT = 28;
|
|
2
|
+
export declare const TABLE_COLUMN_MIN_WIDTH = 28;
|
|
3
|
+
export declare const TABLE_DRAG_HANDLE_WIDTH = 40;
|
|
4
|
+
export declare const TABLE_DRAG_HANDLE_HEIGHT = 20;
|
|
5
|
+
export declare const TABLE_DRAG_HANDLE_PADDING = 40;
|
|
6
|
+
export declare const TABLE_DRAG_HANDLE_RADIUS = 20;
|
|
7
|
+
export declare const TABLE_DRAG_HANDLE_ARROW_X = 3;
|
|
8
|
+
export declare const TABLE_DRAG_HANDLE_ARROW_Y = 4;
|
|
9
|
+
export declare const TABLE_DRAG_HANDLE_ARROW_LENGTH = 7;
|
|
10
|
+
export declare const TABLE_DRAG_HANDLE_ARROW_LINE_WIDTH = 2;
|
|
11
|
+
export declare const TABLE_CELL_WIDTH = 200;
|
|
12
|
+
export declare const TABLE_CELL_HEIGHT = 120;
|
|
13
|
+
export declare const TABLE_TEXT_PADDING = 5;
|
|
14
|
+
export declare const TRANSPARENT_COLOR = "rgba(0,0,0,0)";
|
|
15
|
+
export declare const DEFAULT_TEXT_FONT_FAMILY = "Roboto";
|
|
16
|
+
export declare const DEFAULT_TEXT_FONT_SIZE = 11;
|
|
17
|
+
export declare const TEXT_VALIGN = "top";
|
|
18
|
+
export declare const TEXT_ALIGN = "left";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TEXT_ALIGN = exports.TEXT_VALIGN = exports.DEFAULT_TEXT_FONT_SIZE = exports.DEFAULT_TEXT_FONT_FAMILY = exports.TRANSPARENT_COLOR = exports.TABLE_TEXT_PADDING = exports.TABLE_CELL_HEIGHT = exports.TABLE_CELL_WIDTH = exports.TABLE_DRAG_HANDLE_ARROW_LINE_WIDTH = exports.TABLE_DRAG_HANDLE_ARROW_LENGTH = exports.TABLE_DRAG_HANDLE_ARROW_Y = exports.TABLE_DRAG_HANDLE_ARROW_X = exports.TABLE_DRAG_HANDLE_RADIUS = exports.TABLE_DRAG_HANDLE_PADDING = exports.TABLE_DRAG_HANDLE_HEIGHT = exports.TABLE_DRAG_HANDLE_WIDTH = exports.TABLE_COLUMN_MIN_WIDTH = exports.TABLE_ROW_MIN_HEIGHT = void 0;
|
|
4
|
+
exports.TABLE_ROW_MIN_HEIGHT = 28;
|
|
5
|
+
exports.TABLE_COLUMN_MIN_WIDTH = 28;
|
|
6
|
+
exports.TABLE_DRAG_HANDLE_WIDTH = 40;
|
|
7
|
+
exports.TABLE_DRAG_HANDLE_HEIGHT = 20;
|
|
8
|
+
exports.TABLE_DRAG_HANDLE_PADDING = 40;
|
|
9
|
+
exports.TABLE_DRAG_HANDLE_RADIUS = 20;
|
|
10
|
+
exports.TABLE_DRAG_HANDLE_ARROW_X = 3;
|
|
11
|
+
exports.TABLE_DRAG_HANDLE_ARROW_Y = 4;
|
|
12
|
+
exports.TABLE_DRAG_HANDLE_ARROW_LENGTH = 7;
|
|
13
|
+
exports.TABLE_DRAG_HANDLE_ARROW_LINE_WIDTH = 2;
|
|
14
|
+
exports.TABLE_CELL_WIDTH = 200;
|
|
15
|
+
exports.TABLE_CELL_HEIGHT = 120;
|
|
16
|
+
exports.TABLE_TEXT_PADDING = 5;
|
|
17
|
+
exports.TRANSPARENT_COLOR = 'rgba(0,0,0,0)';
|
|
18
|
+
exports.DEFAULT_TEXT_FONT_FAMILY = 'Roboto';
|
|
19
|
+
exports.DEFAULT_TEXT_FONT_SIZE = 11;
|
|
20
|
+
exports.TEXT_VALIGN = 'top';
|
|
21
|
+
exports.TEXT_ALIGN = 'left';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DocumentElement } from '@contrail/documents';
|
|
2
|
+
export declare class TableCopyService {
|
|
3
|
+
constructor();
|
|
4
|
+
static copy(tableElement: DocumentElement, childElements: DocumentElement[]): DocumentElement[];
|
|
5
|
+
static createTableFromCells(element: DocumentElement, rows: DocumentElement[], columns: DocumentElement[], cells: DocumentElement[]): DocumentElement[];
|
|
6
|
+
static createTableFromCell(cellElement: DocumentElement): DocumentElement[];
|
|
7
|
+
static createTextFromCell(cellElement: DocumentElement): DocumentElement;
|
|
8
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TableCopyService = void 0;
|
|
4
|
+
const documents_1 = require("@contrail/documents");
|
|
5
|
+
const util_1 = require("@contrail/util");
|
|
6
|
+
const nanoid_1 = require("nanoid");
|
|
7
|
+
const table_constants_1 = require("./table-constants");
|
|
8
|
+
const table_service_1 = require("./table.service");
|
|
9
|
+
class TableCopyService {
|
|
10
|
+
constructor() { }
|
|
11
|
+
static copy(tableElement, childElements) {
|
|
12
|
+
const copiedChildElementIds = new Map();
|
|
13
|
+
const childElementsMap = new Map();
|
|
14
|
+
childElements.forEach(element => {
|
|
15
|
+
childElementsMap.set(element.id, element);
|
|
16
|
+
});
|
|
17
|
+
const rowIds = [];
|
|
18
|
+
const columnIds = [];
|
|
19
|
+
const oldTableElement = util_1.ObjectUtil.cloneDeep(tableElement);
|
|
20
|
+
delete oldTableElement.id;
|
|
21
|
+
const newTableElement = documents_1.DocumentElementFactory.createElement('table', oldTableElement);
|
|
22
|
+
newTableElement.tableId = newTableElement.id;
|
|
23
|
+
const newChildElements = [];
|
|
24
|
+
for (let i = 0; i < tableElement.rowIds.length; i++) {
|
|
25
|
+
const oldId = tableElement.rowIds[i];
|
|
26
|
+
const oldElement = childElementsMap.get(oldId);
|
|
27
|
+
if (!oldElement)
|
|
28
|
+
throw new Error('Invalid table element');
|
|
29
|
+
const oldElementCopy = util_1.ObjectUtil.cloneDeep(oldElement);
|
|
30
|
+
delete oldElementCopy.id;
|
|
31
|
+
delete oldElementCopy.updatedOn;
|
|
32
|
+
delete oldElementCopy.updatedById;
|
|
33
|
+
delete oldElementCopy.createdOn;
|
|
34
|
+
delete oldElementCopy.createdById;
|
|
35
|
+
oldElementCopy.tableId = newTableElement.id;
|
|
36
|
+
const newElement = documents_1.DocumentElementFactory.createElement('row', oldElementCopy);
|
|
37
|
+
copiedChildElementIds.set(oldId, newElement.id);
|
|
38
|
+
rowIds.push(newElement.id);
|
|
39
|
+
newChildElements.push(newElement);
|
|
40
|
+
}
|
|
41
|
+
for (let i = 0; i < tableElement.columnIds.length; i++) {
|
|
42
|
+
const oldId = tableElement.columnIds[i];
|
|
43
|
+
const oldElement = childElementsMap.get(oldId);
|
|
44
|
+
if (!oldElement)
|
|
45
|
+
throw new Error('Invalid table element');
|
|
46
|
+
const oldElementCopy = util_1.ObjectUtil.cloneDeep(oldElement);
|
|
47
|
+
delete oldElementCopy.id;
|
|
48
|
+
delete oldElementCopy.updatedOn;
|
|
49
|
+
delete oldElementCopy.updatedById;
|
|
50
|
+
delete oldElementCopy.createdOn;
|
|
51
|
+
delete oldElementCopy.createdById;
|
|
52
|
+
oldElementCopy.tableId = newTableElement.id;
|
|
53
|
+
const newElement = documents_1.DocumentElementFactory.createElement('column', oldElementCopy);
|
|
54
|
+
copiedChildElementIds.set(oldId, newElement.id);
|
|
55
|
+
columnIds.push(newElement.id);
|
|
56
|
+
newChildElements.push(newElement);
|
|
57
|
+
}
|
|
58
|
+
const cellElements = childElements.filter(e => e.type === 'cell');
|
|
59
|
+
if (cellElements.length < tableElement.rowIds.length * tableElement.columnIds.length) {
|
|
60
|
+
for (let i = 0; i < tableElement.rowIds.length; i++) {
|
|
61
|
+
for (let j = 0; j < tableElement.columnIds.length; j++) {
|
|
62
|
+
const rowId = tableElement.rowIds[i];
|
|
63
|
+
const columnId = tableElement.columnIds[j];
|
|
64
|
+
const cellElement = cellElements.find(e => e.type === 'cell' && e.rowId === rowId && e.columnId === columnId);
|
|
65
|
+
if (!cellElement) {
|
|
66
|
+
const row = childElements.find(e => e.id === rowId);
|
|
67
|
+
const column = childElements.find(e => e.id === columnId);
|
|
68
|
+
cellElements.push((0, table_service_1.createCell)({
|
|
69
|
+
rowId,
|
|
70
|
+
columnId,
|
|
71
|
+
tableId: tableElement.id,
|
|
72
|
+
size: {
|
|
73
|
+
width: column.size.width,
|
|
74
|
+
height: row.size.height,
|
|
75
|
+
},
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (let i = 0; i < cellElements.length; i++) {
|
|
82
|
+
const oldCell = cellElements[i];
|
|
83
|
+
const newRowId = copiedChildElementIds.get(oldCell.rowId);
|
|
84
|
+
const newColumnId = copiedChildElementIds.get(oldCell.columnId);
|
|
85
|
+
if (!newRowId || !newColumnId)
|
|
86
|
+
throw new Error('Invalid table element');
|
|
87
|
+
const oldElementCopy = util_1.ObjectUtil.cloneDeep(oldCell);
|
|
88
|
+
delete oldElementCopy.id;
|
|
89
|
+
delete oldElementCopy.updatedOn;
|
|
90
|
+
delete oldElementCopy.updatedById;
|
|
91
|
+
delete oldElementCopy.createdOn;
|
|
92
|
+
delete oldElementCopy.createdById;
|
|
93
|
+
oldElementCopy.tableId = newTableElement.id;
|
|
94
|
+
oldElementCopy.rowId = newRowId;
|
|
95
|
+
oldElementCopy.columnId = newColumnId;
|
|
96
|
+
const newElement = documents_1.DocumentElementFactory.createElement('cell', oldElementCopy);
|
|
97
|
+
newChildElements.push(newElement);
|
|
98
|
+
}
|
|
99
|
+
newTableElement.rowIds = rowIds;
|
|
100
|
+
newTableElement.columnIds = columnIds;
|
|
101
|
+
return [newTableElement, ...newChildElements];
|
|
102
|
+
}
|
|
103
|
+
static createTableFromCells(element, rows, columns, cells) {
|
|
104
|
+
const rowElements = [];
|
|
105
|
+
const rowIds = new Map();
|
|
106
|
+
const columnElements = [];
|
|
107
|
+
const columnIds = new Map();
|
|
108
|
+
const cellElements = [];
|
|
109
|
+
const existingCellsMap = new Map();
|
|
110
|
+
const tableId = (0, nanoid_1.nanoid)(16);
|
|
111
|
+
let width = 0, height = 0;
|
|
112
|
+
let startRow, endRow, startColumn, endColumn;
|
|
113
|
+
cells.forEach(cell => {
|
|
114
|
+
const rowIndex = element.rowIds.indexOf(cell.rowId);
|
|
115
|
+
const columnIndex = element.columnIds.indexOf(cell.columnId);
|
|
116
|
+
const isNotSet = startRow == undefined;
|
|
117
|
+
if (isNotSet || rowIndex < startRow)
|
|
118
|
+
startRow = rowIndex;
|
|
119
|
+
if (isNotSet || rowIndex > endRow)
|
|
120
|
+
endRow = rowIndex;
|
|
121
|
+
if (isNotSet || columnIndex < startColumn)
|
|
122
|
+
startColumn = columnIndex;
|
|
123
|
+
if (isNotSet || columnIndex > endColumn)
|
|
124
|
+
endColumn = columnIndex;
|
|
125
|
+
existingCellsMap.set(`${rowIndex}_${columnIndex}`, cell);
|
|
126
|
+
});
|
|
127
|
+
const skipRows = Array.from({ length: endRow - startRow + 1 }, (value, index) => startRow + index).filter(i => !Array.from(existingCellsMap.keys()).find(v => v.startsWith(`${i}_`)));
|
|
128
|
+
const skipColumns = Array.from({ length: endColumn - startColumn + 1 }, (value, index) => startColumn + index).filter(j => !Array.from(existingCellsMap.keys()).find(v => v.endsWith(`_${j}`)));
|
|
129
|
+
for (let i = startRow; i <= endRow; i++) {
|
|
130
|
+
if (skipRows.indexOf(i) !== -1)
|
|
131
|
+
continue;
|
|
132
|
+
const rowId = (0, nanoid_1.nanoid)(16);
|
|
133
|
+
const row = {
|
|
134
|
+
id: rowId,
|
|
135
|
+
tableId,
|
|
136
|
+
type: 'row',
|
|
137
|
+
size: {
|
|
138
|
+
width: 1,
|
|
139
|
+
height: rows[i].size.height,
|
|
140
|
+
},
|
|
141
|
+
style: {
|
|
142
|
+
backgroundColor: table_constants_1.TRANSPARENT_COLOR,
|
|
143
|
+
},
|
|
144
|
+
position: { x: 0, y: 0 },
|
|
145
|
+
};
|
|
146
|
+
height += row.size.height;
|
|
147
|
+
rowIds.set(i, rowId);
|
|
148
|
+
rowElements.push(row);
|
|
149
|
+
}
|
|
150
|
+
for (let j = startColumn; j <= endColumn; j++) {
|
|
151
|
+
if (skipColumns.indexOf(j) !== -1)
|
|
152
|
+
continue;
|
|
153
|
+
const columnId = (0, nanoid_1.nanoid)(16);
|
|
154
|
+
const column = {
|
|
155
|
+
id: columnId,
|
|
156
|
+
tableId,
|
|
157
|
+
type: 'column',
|
|
158
|
+
size: {
|
|
159
|
+
width: columns[j].size.width,
|
|
160
|
+
height: 1,
|
|
161
|
+
},
|
|
162
|
+
style: {
|
|
163
|
+
backgroundColor: table_constants_1.TRANSPARENT_COLOR,
|
|
164
|
+
},
|
|
165
|
+
position: { x: 0, y: 0 },
|
|
166
|
+
};
|
|
167
|
+
width += column.size.width;
|
|
168
|
+
columnIds.set(j, columnId);
|
|
169
|
+
columnElements.push(column);
|
|
170
|
+
}
|
|
171
|
+
for (let i = startRow; i <= endRow; i++) {
|
|
172
|
+
if (skipRows.indexOf(i) !== -1)
|
|
173
|
+
continue;
|
|
174
|
+
for (let j = startColumn; j <= endColumn; j++) {
|
|
175
|
+
if (skipColumns.indexOf(j) !== -1)
|
|
176
|
+
continue;
|
|
177
|
+
const cell = existingCellsMap.get(`${i}_${j}`);
|
|
178
|
+
if (cell) {
|
|
179
|
+
const element = (0, table_service_1.createCell)({
|
|
180
|
+
rowId: rowIds.get(i),
|
|
181
|
+
columnId: columnIds.get(j),
|
|
182
|
+
tableId,
|
|
183
|
+
text: cell.text,
|
|
184
|
+
colspan: cell.colspan,
|
|
185
|
+
rowspan: cell.rowspan,
|
|
186
|
+
size: {
|
|
187
|
+
width: cell.size.width,
|
|
188
|
+
height: cell.size.height,
|
|
189
|
+
},
|
|
190
|
+
style: util_1.ObjectUtil.cloneDeep(cell.style),
|
|
191
|
+
position: { x: 0, y: 0 },
|
|
192
|
+
});
|
|
193
|
+
cellElements.push(element);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const tableElement = {
|
|
198
|
+
type: 'table',
|
|
199
|
+
id: tableId,
|
|
200
|
+
position: Object.assign({}, element.position),
|
|
201
|
+
scale: Object.assign({}, element.scale),
|
|
202
|
+
size: {
|
|
203
|
+
width,
|
|
204
|
+
height,
|
|
205
|
+
},
|
|
206
|
+
style: {
|
|
207
|
+
backgroundColor: table_constants_1.TRANSPARENT_COLOR,
|
|
208
|
+
border: {
|
|
209
|
+
width: 1,
|
|
210
|
+
color: '#616161',
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
rowIds: Array.from(rowIds.values()),
|
|
214
|
+
columnIds: Array.from(columnIds.values()),
|
|
215
|
+
};
|
|
216
|
+
return [tableElement, ...rowElements, ...columnElements, ...cellElements];
|
|
217
|
+
}
|
|
218
|
+
static createTableFromCell(cellElement) {
|
|
219
|
+
const tableId = (0, nanoid_1.nanoid)(16);
|
|
220
|
+
const rowId = (0, nanoid_1.nanoid)(16);
|
|
221
|
+
const row = {
|
|
222
|
+
id: rowId,
|
|
223
|
+
tableId,
|
|
224
|
+
type: 'row',
|
|
225
|
+
size: {
|
|
226
|
+
width: 1,
|
|
227
|
+
height: cellElement.size.height,
|
|
228
|
+
},
|
|
229
|
+
style: {
|
|
230
|
+
backgroundColor: table_constants_1.TRANSPARENT_COLOR,
|
|
231
|
+
},
|
|
232
|
+
position: { x: 0, y: 0 },
|
|
233
|
+
};
|
|
234
|
+
const columnId = (0, nanoid_1.nanoid)(16);
|
|
235
|
+
const column = {
|
|
236
|
+
id: columnId,
|
|
237
|
+
tableId,
|
|
238
|
+
type: 'column',
|
|
239
|
+
size: {
|
|
240
|
+
width: cellElement.size.width,
|
|
241
|
+
height: 1,
|
|
242
|
+
},
|
|
243
|
+
style: {
|
|
244
|
+
backgroundColor: table_constants_1.TRANSPARENT_COLOR,
|
|
245
|
+
},
|
|
246
|
+
position: { x: 0, y: 0 },
|
|
247
|
+
};
|
|
248
|
+
const cell = util_1.ObjectUtil.mergeDeep(util_1.ObjectUtil.cloneDeep(cellElement), {
|
|
249
|
+
id: (0, nanoid_1.nanoid)(16),
|
|
250
|
+
type: 'cell',
|
|
251
|
+
rowId,
|
|
252
|
+
columnId,
|
|
253
|
+
tableId,
|
|
254
|
+
scale: undefined,
|
|
255
|
+
});
|
|
256
|
+
const tableElement = {
|
|
257
|
+
type: 'table',
|
|
258
|
+
id: tableId,
|
|
259
|
+
position: Object.assign({}, cellElement.position),
|
|
260
|
+
scale: Object.assign({}, cellElement.scale),
|
|
261
|
+
size: Object.assign({}, cellElement.size),
|
|
262
|
+
style: {
|
|
263
|
+
backgroundColor: table_constants_1.TRANSPARENT_COLOR,
|
|
264
|
+
border: {
|
|
265
|
+
width: 1,
|
|
266
|
+
color: '#616161',
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
rowIds: [rowId],
|
|
270
|
+
columnIds: [columnId],
|
|
271
|
+
};
|
|
272
|
+
return [tableElement, row, column, cell];
|
|
273
|
+
}
|
|
274
|
+
static createTextFromCell(cellElement) {
|
|
275
|
+
var _a, _b, _c, _d, _e, _f;
|
|
276
|
+
const fontFamily = `${(_c = (_b = (_a = cellElement.style) === null || _a === void 0 ? void 0 : _a.font) === null || _b === void 0 ? void 0 : _b.family) !== null && _c !== void 0 ? _c : table_constants_1.DEFAULT_TEXT_FONT_FAMILY}`;
|
|
277
|
+
const fontSize = `${(_f = (_e = (_d = cellElement.style) === null || _d === void 0 ? void 0 : _d.font) === null || _e === void 0 ? void 0 : _e.size) !== null && _f !== void 0 ? _f : table_constants_1.DEFAULT_TEXT_FONT_SIZE}pt`;
|
|
278
|
+
const size = table_service_1.TableService.getSize(cellElement.text, `width: ${cellElement.size.width -
|
|
279
|
+
table_constants_1.TABLE_TEXT_PADDING * 2}px; height: auto; font-family: ${fontFamily}; font-size: ${fontSize};`);
|
|
280
|
+
const documentElement = {
|
|
281
|
+
isTextTool: true,
|
|
282
|
+
text: cellElement.text,
|
|
283
|
+
position: Object.assign({}, cellElement.position),
|
|
284
|
+
scale: Object.assign({}, cellElement.scale),
|
|
285
|
+
size: Object.assign({}, size),
|
|
286
|
+
style: util_1.ObjectUtil.mergeDeep(util_1.ObjectUtil.cloneDeep(cellElement.style), {
|
|
287
|
+
border: {
|
|
288
|
+
width: 0,
|
|
289
|
+
},
|
|
290
|
+
}),
|
|
291
|
+
};
|
|
292
|
+
return documents_1.DocumentElementFactory.createTextElement('', documentElement);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
exports.TableCopyService = TableCopyService;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DocumentElement, DocumentElementChanges } from '@contrail/documents';
|
|
2
|
+
import { TableRange } from './table-range';
|
|
3
|
+
export declare class TableMergeService {
|
|
4
|
+
constructor();
|
|
5
|
+
static getMergedRange(tableElement: any, element: DocumentElement): TableRange;
|
|
6
|
+
static getMergedRanges(tableElement: DocumentElement, childElements: DocumentElement[]): TableRange[];
|
|
7
|
+
static getMergedCells(cell: DocumentElement, tableElement: DocumentElement, childElements: DocumentElement[]): DocumentElement[];
|
|
8
|
+
static isValidRangeToMerge(tableElement: DocumentElement, childElements: DocumentElement[], tableRange: TableRange): boolean;
|
|
9
|
+
static merge(tableElement: DocumentElement, childElements: DocumentElement[], tableRange: TableRange): DocumentElementChanges;
|
|
10
|
+
static unmerge(tableElement: DocumentElement, childElements: DocumentElement[], tableRange: TableRange): DocumentElementChanges;
|
|
11
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TableMergeService = void 0;
|
|
4
|
+
const util_1 = require("@contrail/util");
|
|
5
|
+
const table_service_1 = require("./table.service");
|
|
6
|
+
const table_range_1 = require("./table-range");
|
|
7
|
+
class TableMergeService {
|
|
8
|
+
constructor() { }
|
|
9
|
+
static getMergedRange(tableElement, element) {
|
|
10
|
+
if (element.type === 'cell' && (element.colspan > 1 || element.rowspan > 1)) {
|
|
11
|
+
const rowIndex = tableElement.rowIds.indexOf(element.rowId);
|
|
12
|
+
const columnIndex = tableElement.columnIds.indexOf(element.columnId);
|
|
13
|
+
return new table_range_1.TableRange(rowIndex, rowIndex + (element.rowspan > 1 ? element.rowspan - 1 : 0), columnIndex, columnIndex + (element.colspan > 1 ? element.colspan - 1 : 0));
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
static getMergedRanges(tableElement, childElements) {
|
|
18
|
+
const ranges = [];
|
|
19
|
+
for (const element of childElements) {
|
|
20
|
+
const mergedRange = TableMergeService.getMergedRange(tableElement, element);
|
|
21
|
+
if (mergedRange)
|
|
22
|
+
ranges.push(mergedRange);
|
|
23
|
+
}
|
|
24
|
+
return ranges;
|
|
25
|
+
}
|
|
26
|
+
static getMergedCells(cell, tableElement, childElements) {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
const mergedCells = [];
|
|
29
|
+
if (cell.colspan > 1 || cell.rowspan > 1) {
|
|
30
|
+
const rowIndex = tableElement.rowIds.indexOf(cell.rowId);
|
|
31
|
+
const columnIndex = tableElement.columnIds.indexOf(cell.columnId);
|
|
32
|
+
for (let i = rowIndex; i < rowIndex + ((_a = cell.rowspan) !== null && _a !== void 0 ? _a : 1); i++) {
|
|
33
|
+
const rowId = tableElement.rowIds[i];
|
|
34
|
+
for (let j = columnIndex; j < columnIndex + ((_b = cell.colspan) !== null && _b !== void 0 ? _b : 1); j++) {
|
|
35
|
+
const columnId = tableElement.columnIds[j];
|
|
36
|
+
const mergedCell = childElements.find(e => e.type === 'cell' && e.columnId === columnId && e.rowId === rowId);
|
|
37
|
+
if (mergedCell) {
|
|
38
|
+
mergedCells.push(mergedCell);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return mergedCells;
|
|
44
|
+
}
|
|
45
|
+
static isValidRangeToMerge(tableElement, childElements, tableRange) {
|
|
46
|
+
if (tableRange.singular())
|
|
47
|
+
return false;
|
|
48
|
+
const mergedRanges = TableMergeService.getMergedRanges(tableElement, childElements).filter(range => range.intersects(tableRange) && !range.within(tableRange));
|
|
49
|
+
return mergedRanges.length === 0;
|
|
50
|
+
}
|
|
51
|
+
static merge(tableElement, childElements, tableRange) {
|
|
52
|
+
if (!this.isValidRangeToMerge(tableElement, childElements, tableRange)) {
|
|
53
|
+
throw new Error(table_service_1.TABLE_ERROR.INVALID_RANGE_TO_MERGE);
|
|
54
|
+
}
|
|
55
|
+
const colspan = tableRange.cols + 1;
|
|
56
|
+
const rowspan = tableRange.rows + 1;
|
|
57
|
+
const elementsToUpdate = [];
|
|
58
|
+
let firstCell;
|
|
59
|
+
tableRange.each((rowIndex, columnIndex) => {
|
|
60
|
+
const rowId = tableElement.rowIds[rowIndex];
|
|
61
|
+
const columnId = tableElement.columnIds[columnIndex];
|
|
62
|
+
const element = childElements.find(e => e.type === 'cell' && e.columnId === columnId && e.rowId === rowId);
|
|
63
|
+
if (element) {
|
|
64
|
+
const elementUndo = util_1.ObjectUtil.cloneDeep(element);
|
|
65
|
+
element.colspan = 1;
|
|
66
|
+
element.rowspan = 1;
|
|
67
|
+
if (tableRange.isStart(rowIndex, columnIndex)) {
|
|
68
|
+
firstCell = element;
|
|
69
|
+
let width = 0;
|
|
70
|
+
tableRange.eachColumn(columnIndex => {
|
|
71
|
+
const columnId = tableElement.columnIds[columnIndex];
|
|
72
|
+
const column = childElements.find(e => e.type === 'column' && e.id === columnId);
|
|
73
|
+
width = width + column.size.width;
|
|
74
|
+
});
|
|
75
|
+
if (colspan > 1) {
|
|
76
|
+
element.colspan = colspan;
|
|
77
|
+
}
|
|
78
|
+
if (rowspan > 1) {
|
|
79
|
+
element.rowspan = rowspan;
|
|
80
|
+
}
|
|
81
|
+
element.size.width = width;
|
|
82
|
+
element.size.height = table_service_1.TableService.getCellSize(element).height;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
element.style = util_1.ObjectUtil.mergeDeep(util_1.ObjectUtil.cloneDeep(table_service_1.TableService.DEFAULT_CELL_STYLE), firstCell.style);
|
|
86
|
+
table_service_1.TableService.clearCell(element);
|
|
87
|
+
}
|
|
88
|
+
elementsToUpdate.push({ change: element, undo: elementUndo });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.error(`Element was not found at row:${rowIndex} and column:${columnIndex}`, tableElement, childElements);
|
|
92
|
+
throw new Error();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return { elementsToUpdate };
|
|
96
|
+
}
|
|
97
|
+
static unmerge(tableElement, childElements, tableRange) {
|
|
98
|
+
const mergedRanges = TableMergeService.getMergedRanges(tableElement, childElements);
|
|
99
|
+
if (!mergedRanges.find(range => range.equals(tableRange)))
|
|
100
|
+
throw new Error(table_service_1.TABLE_ERROR.INVALID_RANGE_TO_UNMERGE);
|
|
101
|
+
const tableUndo = Object.assign(Object.assign({}, (0, table_service_1.tableData)(tableElement)), { size: Object.assign({}, tableElement.size) });
|
|
102
|
+
const elementsToUpdate = [];
|
|
103
|
+
let firstCell;
|
|
104
|
+
tableRange.each((rowIndex, columnIndex) => {
|
|
105
|
+
const rowId = tableElement.rowIds[rowIndex];
|
|
106
|
+
const columnId = tableElement.columnIds[columnIndex];
|
|
107
|
+
const element = childElements.find(e => e.type === 'cell' && e.columnId === columnId && e.rowId === rowId);
|
|
108
|
+
const column = childElements.find(e => e.type === 'column' && e.id === columnId);
|
|
109
|
+
const row = childElements.find(e => e.type === 'row' && e.id === rowId);
|
|
110
|
+
if (element && column && row) {
|
|
111
|
+
const elementUndo = util_1.ObjectUtil.cloneDeep(element);
|
|
112
|
+
element.colspan = 1;
|
|
113
|
+
element.rowspan = 1;
|
|
114
|
+
if (tableRange.isStart(rowIndex, columnIndex)) {
|
|
115
|
+
firstCell = element;
|
|
116
|
+
element.size.width = column.size.width;
|
|
117
|
+
element.size.height = table_service_1.TableService.getCellSize(element).height;
|
|
118
|
+
if (element.size.height > row.size.height) {
|
|
119
|
+
elementsToUpdate.push(table_service_1.TableService.resizeRow(tableElement, childElements, rowId, element.size.height).elementsToUpdate[1]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
element.style = util_1.ObjectUtil.cloneDeep(firstCell.style);
|
|
124
|
+
}
|
|
125
|
+
elementsToUpdate.push({ change: element, undo: elementUndo });
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
console.error(`Element was not found at row:${rowIndex} and column:${columnIndex}`, tableElement, childElements);
|
|
129
|
+
throw new Error();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
elementsToUpdate: [
|
|
134
|
+
{
|
|
135
|
+
change: Object.assign(Object.assign({}, (0, table_service_1.tableData)(tableElement)), { size: Object.assign({}, tableElement.size) }),
|
|
136
|
+
undo: tableUndo,
|
|
137
|
+
},
|
|
138
|
+
...elementsToUpdate,
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.TableMergeService = TableMergeService;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DocumentElement, DocumentElementChanges } from '@contrail/documents';
|
|
2
|
+
export declare class TablePasteService {
|
|
3
|
+
private static isDebug;
|
|
4
|
+
constructor();
|
|
5
|
+
private static log;
|
|
6
|
+
private static pasteRowsAndColumns;
|
|
7
|
+
static pasteTableCells(tableElement: DocumentElement, childElements: DocumentElement[], elementsToPaste: DocumentElement[], targetRow: number, targetColumn: number): DocumentElementChanges;
|
|
8
|
+
}
|