@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,630 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TableService = exports.createCell = exports.tableData = exports.TABLE_ERROR = void 0;
4
+ const util_1 = require("@contrail/util");
5
+ const nanoid_1 = require("nanoid");
6
+ const util_2 = require("@contrail/util");
7
+ const table_constants_1 = require("./table-constants");
8
+ const table_merge_service_1 = require("./table-merge.service");
9
+ const table_range_1 = require("./table-range");
10
+ var TABLE_ERROR;
11
+ (function (TABLE_ERROR) {
12
+ TABLE_ERROR["UNMERGE_TO_DELETE_COLUMN"] = "Unmerge cells to delete column";
13
+ TABLE_ERROR["UNMERGE_TO_DELETE_ROW"] = "Unmerge cells to delete row";
14
+ TABLE_ERROR["UMMERGE_TO_MOVE_COLUMN"] = "Unmerge cells to move column";
15
+ TABLE_ERROR["UMMERGE_TO_MOVE_ROW"] = "Unmerge cells to move row";
16
+ TABLE_ERROR["INVALID_RANGE_TO_MERGE"] = "Invalid range to merge";
17
+ TABLE_ERROR["INVALID_RANGE_TO_UNMERGE"] = "Invalid range to unmerge";
18
+ TABLE_ERROR["INVALID_TABLE"] = "Invalid table";
19
+ })(TABLE_ERROR = exports.TABLE_ERROR || (exports.TABLE_ERROR = {}));
20
+ function tableData(element) {
21
+ return {
22
+ id: element.id,
23
+ tableId: element.type === 'table' ? element.id : element.tableId,
24
+ type: element.type,
25
+ };
26
+ }
27
+ exports.tableData = tableData;
28
+ function createCell(config) {
29
+ if (!config.tableId || !config.rowId || !config.columnId)
30
+ throw new Error(TABLE_ERROR.INVALID_TABLE);
31
+ return util_1.ObjectUtil.mergeDeep({
32
+ id: (0, nanoid_1.nanoid)(16),
33
+ type: 'cell',
34
+ text: '',
35
+ size: {
36
+ width: table_constants_1.TABLE_CELL_WIDTH,
37
+ height: table_constants_1.TABLE_ROW_MIN_HEIGHT,
38
+ },
39
+ style: util_1.ObjectUtil.cloneDeep(TableService.DEFAULT_CELL_STYLE),
40
+ position: { x: 0, y: 0 },
41
+ colspan: 1,
42
+ rowspan: 1,
43
+ }, config);
44
+ }
45
+ exports.createCell = createCell;
46
+ class TableService {
47
+ constructor() { }
48
+ static createEmptyTableElement(position, rows = 4, columns = 3) {
49
+ const rowElements = [];
50
+ const rowIds = [];
51
+ const columnElements = [];
52
+ const columnIds = [];
53
+ const cellElements = [];
54
+ const tableId = (0, nanoid_1.nanoid)(16);
55
+ for (let i = 0; i < rows; i++) {
56
+ const rowId = (0, nanoid_1.nanoid)(16);
57
+ const row = {
58
+ id: rowId,
59
+ tableId,
60
+ type: 'row',
61
+ size: {
62
+ width: 1,
63
+ height: table_constants_1.TABLE_CELL_HEIGHT,
64
+ },
65
+ style: {
66
+ backgroundColor: table_constants_1.TRANSPARENT_COLOR,
67
+ },
68
+ position: { x: 0, y: 0 },
69
+ };
70
+ rowIds.push(rowId);
71
+ rowElements.push(row);
72
+ }
73
+ for (let j = 0; j < columns; j++) {
74
+ const columnId = (0, nanoid_1.nanoid)(16);
75
+ const column = {
76
+ id: columnId,
77
+ tableId,
78
+ type: 'column',
79
+ size: {
80
+ width: table_constants_1.TABLE_CELL_WIDTH,
81
+ height: 1,
82
+ },
83
+ style: {
84
+ backgroundColor: table_constants_1.TRANSPARENT_COLOR,
85
+ },
86
+ position: { x: 0, y: 0 },
87
+ };
88
+ columnIds.push(columnId);
89
+ columnElements.push(column);
90
+ }
91
+ for (let i = 0; i < rowIds.length; i++) {
92
+ for (let j = 0; j < columnIds.length; j++) {
93
+ const cell = createCell({ rowId: rowIds[i], columnId: columnIds[j], tableId });
94
+ cellElements.push(cell);
95
+ }
96
+ }
97
+ const tableElement = {
98
+ type: 'table',
99
+ id: tableId,
100
+ position: {
101
+ x: position.x - table_constants_1.TABLE_CELL_WIDTH * 0.5,
102
+ y: position.y - table_constants_1.TABLE_CELL_HEIGHT * 0.5,
103
+ },
104
+ size: {
105
+ width: columns * table_constants_1.TABLE_CELL_WIDTH,
106
+ height: rows * table_constants_1.TABLE_CELL_HEIGHT,
107
+ },
108
+ style: {
109
+ backgroundColor: table_constants_1.TRANSPARENT_COLOR,
110
+ border: {
111
+ width: 1,
112
+ color: '#616161',
113
+ },
114
+ },
115
+ rowIds,
116
+ columnIds,
117
+ };
118
+ return [tableElement, ...rowElements, ...columnElements, ...cellElements];
119
+ }
120
+ static addColumn(tableElement, childElements, index, optionalWidth) {
121
+ const prevColumnId = tableElement.columnIds[Math.max(0, index - 1)];
122
+ const prevColumnCells = TableService.getCellsAtColumn(prevColumnId, tableElement, childElements);
123
+ const width = optionalWidth != null ? optionalWidth : childElements.find(e => e.id === prevColumnId).size.width;
124
+ const mergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements).filter(range => range.startColumn < index && index <= range.endColumn);
125
+ const cellsToUpdate = [];
126
+ if (mergedRanges.length > 0) {
127
+ const columnIndexes = [...new Set(mergedRanges.map(range => range.startColumn))];
128
+ for (const columnIndex of columnIndexes) {
129
+ const targetColumnId = tableElement.columnIds[columnIndex];
130
+ const targetCells = this.getCellsAtColumn(targetColumnId, tableElement, childElements);
131
+ for (const cell of targetCells) {
132
+ if (cell.colspan > 1 && columnIndex + cell.colspan > index) {
133
+ const cellUndo = {
134
+ id: cell.id,
135
+ type: cell.type,
136
+ tableId: cell.tableId,
137
+ colspan: cell.colspan,
138
+ size: Object.assign({}, cell.size),
139
+ };
140
+ cell.colspan = cell.colspan + 1;
141
+ cell.size.width = cell.size.width + width;
142
+ cell.size.height = TableService.getCellSize(cell).height;
143
+ cellsToUpdate.push({
144
+ change: {
145
+ id: cell.id,
146
+ type: cell.type,
147
+ tableId: cell.tableId,
148
+ colspan: cell.colspan,
149
+ size: cell.size,
150
+ },
151
+ undo: cellUndo,
152
+ });
153
+ }
154
+ }
155
+ }
156
+ }
157
+ const columnId = (0, nanoid_1.nanoid)(16);
158
+ const column = {
159
+ id: columnId,
160
+ tableId: tableElement.id,
161
+ type: 'column',
162
+ size: {
163
+ width,
164
+ height: 1,
165
+ },
166
+ position: { x: 0, y: 0 },
167
+ };
168
+ const tableUndo = {
169
+ id: tableElement.id,
170
+ size: Object.assign({}, tableElement.size),
171
+ type: tableElement.type,
172
+ tableId: tableElement.id,
173
+ columnIds: [...tableElement.columnIds],
174
+ };
175
+ tableElement.size.width = tableElement.size.width + width;
176
+ tableElement.columnIds.splice(index, 0, columnId);
177
+ const cellElements = [];
178
+ for (let i = 0; i < tableElement.rowIds.length; i++) {
179
+ const prevCell = prevColumnCells[i];
180
+ const cell = createCell({
181
+ rowId: tableElement.rowIds[i],
182
+ columnId,
183
+ tableId: tableElement.id,
184
+ size: {
185
+ width: width,
186
+ height: table_constants_1.TABLE_ROW_MIN_HEIGHT,
187
+ },
188
+ style: prevCell.style,
189
+ });
190
+ cellElements.push(cell);
191
+ }
192
+ return {
193
+ elementsToCreate: [column, ...cellElements],
194
+ elementsToUpdate: [
195
+ {
196
+ change: {
197
+ id: tableElement.id,
198
+ size: tableElement.size,
199
+ type: tableElement.type,
200
+ tableId: tableElement.id,
201
+ columnIds: [...tableElement.columnIds],
202
+ },
203
+ undo: tableUndo,
204
+ },
205
+ ...cellsToUpdate,
206
+ ],
207
+ };
208
+ }
209
+ static getCellsAtColumn(columnId, tableElement, childElements) {
210
+ return childElements
211
+ .filter(element => element.type === 'cell' && element.columnId === columnId)
212
+ .sort((a, b) => tableElement.rowIds.indexOf(a.rowId) - tableElement.rowIds.indexOf(b.rowId));
213
+ }
214
+ static getCellsAtRow(rowId, tableElement, childElements) {
215
+ return childElements
216
+ .filter(element => element.type === 'cell' && element.rowId === rowId)
217
+ .sort((a, b) => tableElement.columnIds.indexOf(a.columnId) - tableElement.columnIds.indexOf(b.columnId));
218
+ }
219
+ static addRow(tableElement, childElements, index, optionalHeight) {
220
+ const mergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements).filter(range => range.startRow < index && index <= range.endRow);
221
+ const cellsToUpdate = [];
222
+ if (mergedRanges.length > 0) {
223
+ const rowIndexes = [...new Set(mergedRanges.map(range => range.startRow))];
224
+ for (const rowIndex of rowIndexes) {
225
+ const targetRowId = tableElement.rowIds[rowIndex];
226
+ const targetCells = this.getCellsAtRow(targetRowId, tableElement, childElements);
227
+ for (const cell of targetCells) {
228
+ if (cell.rowspan > 1 && rowIndex + cell.rowspan > index) {
229
+ const cellUndo = {
230
+ id: cell.id,
231
+ type: cell.type,
232
+ tableId: cell.tableId,
233
+ rowspan: cell.rowspan,
234
+ };
235
+ cell.rowspan = cell.rowspan + 1;
236
+ cellsToUpdate.push({
237
+ change: {
238
+ id: cell.id,
239
+ type: cell.type,
240
+ tableId: cell.tableId,
241
+ rowspan: cell.rowspan,
242
+ },
243
+ undo: cellUndo,
244
+ });
245
+ }
246
+ }
247
+ }
248
+ }
249
+ const prevRowId = tableElement.rowIds[Math.max(0, index - 1)];
250
+ const prevRowCells = TableService.getCellsAtRow(prevRowId, tableElement, childElements);
251
+ const height = optionalHeight != null ? optionalHeight : childElements.find(e => e.id === prevRowId).size.height;
252
+ const rowId = (0, nanoid_1.nanoid)(16);
253
+ const row = {
254
+ id: rowId,
255
+ tableId: tableElement.id,
256
+ type: 'row',
257
+ size: {
258
+ width: 1,
259
+ height,
260
+ },
261
+ position: { x: 0, y: 0 },
262
+ };
263
+ const tableUndo = {
264
+ id: tableElement.id,
265
+ size: Object.assign({}, tableElement.size),
266
+ type: tableElement.type,
267
+ tableId: tableElement.id,
268
+ rowIds: [...tableElement.rowIds],
269
+ };
270
+ tableElement.size.height = tableElement.size.height + height;
271
+ tableElement.rowIds.splice(index, 0, rowId);
272
+ const cellElements = [];
273
+ for (let i = 0; i < tableElement.columnIds.length; i++) {
274
+ const prevCell = prevRowCells[i];
275
+ const cell = createCell({
276
+ rowId,
277
+ columnId: tableElement.columnIds[i],
278
+ tableId: tableElement.id,
279
+ size: {
280
+ width: prevCell.size.width,
281
+ height: table_constants_1.TABLE_ROW_MIN_HEIGHT,
282
+ },
283
+ style: prevCell.style,
284
+ });
285
+ cellElements.push(cell);
286
+ }
287
+ return {
288
+ elementsToCreate: [row, ...cellElements],
289
+ elementsToUpdate: [
290
+ {
291
+ change: {
292
+ id: tableElement.id,
293
+ size: tableElement.size,
294
+ type: tableElement.type,
295
+ tableId: tableElement.id,
296
+ rowIds: [...tableElement.rowIds],
297
+ },
298
+ undo: tableUndo,
299
+ },
300
+ ...cellsToUpdate,
301
+ ],
302
+ };
303
+ }
304
+ static getCellsAtRanges(tableElement, childElements, ranges) {
305
+ const elements = [];
306
+ const elementsMap = new Map();
307
+ for (const range of ranges) {
308
+ range.each((rowIndex, columnIndex) => {
309
+ const cell = childElements.find(e => e.type === 'cell' &&
310
+ e.rowId === tableElement.rowIds[rowIndex] &&
311
+ e.columnId === tableElement.columnIds[columnIndex]);
312
+ if (cell && !elementsMap.get(cell.id)) {
313
+ elements.push(cell);
314
+ elementsMap.set(cell.id, true);
315
+ }
316
+ });
317
+ }
318
+ return elements;
319
+ }
320
+ static deleteTable(tableElement, childElements) {
321
+ return { elementsToDelete: [tableElement, ...childElements] };
322
+ }
323
+ static deleteColumns(tableElement, childElements, columnIndexes) {
324
+ const columnIdsToDelete = tableElement.columnIds.filter((columnId, index) => columnIndexes.indexOf(index) !== -1);
325
+ if (columnIdsToDelete.length === tableElement.columnIds.length) {
326
+ return this.deleteTable(tableElement, childElements);
327
+ }
328
+ const mergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements).filter(range => columnIndexes.filter(columnIndex => range.intersectsCol(columnIndex, columnIndex)).length > 0);
329
+ const columnsToDelete = columnIdsToDelete.map(columnId => childElements.find(e => e.type === 'column' && e.id === columnId));
330
+ const cellsToDelete = childElements.filter(e => e.type === 'cell' && columnIdsToDelete.indexOf(e.columnId) !== -1);
331
+ let deleteAllowed = true;
332
+ if (mergedRanges.length > 0) {
333
+ for (const cell of this.getCellsAtRanges(tableElement, childElements, mergedRanges)) {
334
+ if (!cellsToDelete.find(e => e.id === cell.id)) {
335
+ deleteAllowed = false;
336
+ break;
337
+ }
338
+ }
339
+ }
340
+ if (!deleteAllowed) {
341
+ throw new Error(TABLE_ERROR.UNMERGE_TO_DELETE_COLUMN);
342
+ }
343
+ const tableUndo = {
344
+ id: tableElement.id,
345
+ type: tableElement.type,
346
+ tableId: tableElement.id,
347
+ size: Object.assign({}, tableElement.size),
348
+ columnIds: [...tableElement.columnIds],
349
+ };
350
+ tableElement.columnIds = tableElement.columnIds.filter(id => columnIdsToDelete.indexOf(id) === -1);
351
+ tableElement.size.width =
352
+ tableElement.size.width - columnsToDelete.reduce((totalWidth, element) => totalWidth + element.size.width, 0);
353
+ return {
354
+ elementsToDelete: [...columnsToDelete, ...cellsToDelete],
355
+ elementsToUpdate: [
356
+ {
357
+ change: {
358
+ id: tableElement.id,
359
+ type: tableElement.type,
360
+ tableId: tableElement.id,
361
+ size: Object.assign({}, tableElement.size),
362
+ columnIds: [...tableElement.columnIds],
363
+ },
364
+ undo: tableUndo,
365
+ },
366
+ ],
367
+ };
368
+ }
369
+ static deleteRows(tableElement, childElements, rowIndexes) {
370
+ const rowIdsToDelete = tableElement.rowIds.filter((rowId, index) => rowIndexes.indexOf(index) !== -1);
371
+ if (rowIdsToDelete.length === tableElement.rowIds.length) {
372
+ return this.deleteTable(tableElement, childElements);
373
+ }
374
+ const mergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements).filter(range => rowIndexes.filter(rowIndex => range.intersectsRow(rowIndex, rowIndex)).length > 0);
375
+ const rowsToDelete = rowIdsToDelete.map(rowId => childElements.find(e => e.type === 'row' && e.id === rowId));
376
+ const cellsToDelete = childElements.filter(e => e.type === 'cell' && rowIdsToDelete.indexOf(e.rowId) !== -1);
377
+ let deleteAllowed = true;
378
+ if (mergedRanges.length > 0) {
379
+ for (const cell of this.getCellsAtRanges(tableElement, childElements, mergedRanges)) {
380
+ if (!cellsToDelete.find(e => e.id === cell.id)) {
381
+ deleteAllowed = false;
382
+ break;
383
+ }
384
+ }
385
+ }
386
+ if (!deleteAllowed) {
387
+ throw new Error(TABLE_ERROR.UNMERGE_TO_DELETE_ROW);
388
+ }
389
+ const tableUndo = {
390
+ id: tableElement.id,
391
+ type: tableElement.type,
392
+ tableId: tableElement.id,
393
+ size: Object.assign({}, tableElement.size),
394
+ rowIds: [...tableElement.rowIds],
395
+ };
396
+ tableElement.rowIds = tableElement.rowIds.filter(id => rowIdsToDelete.indexOf(id) === -1);
397
+ tableElement.size.height =
398
+ tableElement.size.height - rowsToDelete.reduce((totalHeight, element) => totalHeight + element.size.height, 0);
399
+ return {
400
+ elementsToDelete: [...rowsToDelete, ...cellsToDelete],
401
+ elementsToUpdate: [
402
+ {
403
+ change: {
404
+ id: tableElement.id,
405
+ type: tableElement.type,
406
+ tableId: tableElement.id,
407
+ size: Object.assign({}, tableElement.size),
408
+ rowIds: [...tableElement.rowIds],
409
+ },
410
+ undo: tableUndo,
411
+ },
412
+ ],
413
+ };
414
+ }
415
+ static move(key, tableElement, childElements, from, to) {
416
+ const isColumn = key === 'columnIds';
417
+ const mergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements);
418
+ const fromMergedRanges = mergedRanges.filter(range => isColumn ? range.cols > 0 && range.intersectsCol(from, from) : range.rows > 0 && range.intersectsRow(from, from));
419
+ const indexIncrement = from < to ? 1 : 0;
420
+ const toMergedRanges = mergedRanges.filter(range => isColumn
421
+ ? range.startColumn - indexIncrement < to && to <= range.endColumn - indexIncrement
422
+ : range.startRow - indexIncrement < to && to <= range.endRow - indexIncrement);
423
+ if (fromMergedRanges.length > 0 || toMergedRanges.length > 0) {
424
+ throw new Error(isColumn ? TABLE_ERROR.UMMERGE_TO_MOVE_COLUMN : TABLE_ERROR.UMMERGE_TO_MOVE_ROW);
425
+ }
426
+ const tableUndo = Object.assign(Object.assign({}, tableData(tableElement)), { [key]: [...tableElement[key]] });
427
+ util_2.OrderUtil.move(tableElement[key], from, to);
428
+ return {
429
+ elementsToUpdate: [
430
+ {
431
+ change: Object.assign(Object.assign({}, tableData(tableElement)), { [key]: [...tableElement[key]] }),
432
+ undo: tableUndo,
433
+ },
434
+ ],
435
+ };
436
+ }
437
+ static resizeRow(tableElement, childElements, rowId, height) {
438
+ const row = childElements.find(e => e.type === 'row' && e.id === rowId);
439
+ const rowUndo = Object.assign(Object.assign({}, tableData(row)), { size: Object.assign({}, row.size) });
440
+ const tableUndo = Object.assign(Object.assign({}, tableData(tableElement)), { size: Object.assign({}, tableElement.size) });
441
+ row.size.height = height;
442
+ tableElement.size.height = childElements
443
+ .filter(e => e.type === 'row')
444
+ .reduce((acc, row) => acc + row.size.height, 0);
445
+ return {
446
+ elementsToUpdate: [
447
+ {
448
+ change: Object.assign(Object.assign({}, tableData(tableElement)), { size: tableElement.size }),
449
+ undo: tableUndo,
450
+ },
451
+ {
452
+ change: Object.assign(Object.assign({}, tableData(row)), { size: row.size }),
453
+ undo: rowUndo,
454
+ },
455
+ ],
456
+ };
457
+ }
458
+ static resizeColumn(tableElement, childElements, columnId, width) {
459
+ const column = childElements.find(e => e.type === 'column' && e.id === columnId);
460
+ const columnUndo = Object.assign(Object.assign({}, tableData(column)), { size: Object.assign({}, column.size) });
461
+ const tableUndo = Object.assign(Object.assign({}, tableData(tableElement)), { size: Object.assign({}, tableElement.size) });
462
+ column.size.width = width;
463
+ tableElement.size.width = childElements
464
+ .filter(e => e.type === 'column')
465
+ .reduce((acc, column) => acc + column.size.width, 0);
466
+ return {
467
+ elementsToUpdate: [
468
+ {
469
+ change: Object.assign(Object.assign({}, tableData(tableElement)), { size: tableElement.size }),
470
+ undo: tableUndo,
471
+ },
472
+ {
473
+ change: Object.assign(Object.assign({}, tableData(column)), { size: column.size }),
474
+ undo: columnUndo,
475
+ },
476
+ ],
477
+ };
478
+ }
479
+ static getColumns(tableElement, childElements) {
480
+ const columns = [];
481
+ for (const columnId of tableElement.columnIds) {
482
+ const column = childElements.find(e => e.type === 'column' && e.id === columnId);
483
+ if (!column)
484
+ throw new Error(TABLE_ERROR.INVALID_TABLE);
485
+ columns.push(column);
486
+ }
487
+ return columns;
488
+ }
489
+ static getColumnsWidth(tableElement, childElements, startIndex, endIndex) {
490
+ const columns = this.getColumns(tableElement, childElements);
491
+ let width = 0;
492
+ for (let i = startIndex; i <= endIndex; i++) {
493
+ const column = columns[i];
494
+ if (column) {
495
+ width = width + column.size.width;
496
+ }
497
+ }
498
+ return width;
499
+ }
500
+ static getRows(tableElement, childElements) {
501
+ const rows = [];
502
+ for (const rowId of tableElement.rowIds) {
503
+ const row = childElements.find(e => e.type === 'row' && e.id === rowId);
504
+ if (!row)
505
+ throw new Error(TABLE_ERROR.INVALID_TABLE);
506
+ rows.push(row);
507
+ }
508
+ return rows;
509
+ }
510
+ static getRowsHeight(tableElement, childElements, startIndex, endIndex, skipIndex) {
511
+ const rows = this.getRows(tableElement, childElements);
512
+ let height = 0;
513
+ for (let i = startIndex; i <= endIndex; i++) {
514
+ const row = rows[i];
515
+ if (row && (skipIndex == null || skipIndex !== i)) {
516
+ height = height + row.size.height;
517
+ }
518
+ }
519
+ return height;
520
+ }
521
+ static getCellMinHeight(cell, tableElement, childElements) {
522
+ let height = cell.size.height;
523
+ const rowIndex = tableElement.rowIds.indexOf(cell.rowId);
524
+ const columnIndex = tableElement.columnIds.indexOf(cell.columnId);
525
+ if (rowIndex < 0 || columnIndex < 0)
526
+ throw new Error(TABLE_ERROR.INVALID_TABLE);
527
+ const cellRange = new table_range_1.TableRange(rowIndex, rowIndex, columnIndex, columnIndex);
528
+ const mergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements);
529
+ const mergedRange = mergedRanges.find(range => cellRange.within(range));
530
+ if (mergedRange) {
531
+ const mergedRangeStart = mergedRange && cellRange.equals(mergedRange.start());
532
+ const mergedCell = mergedRangeStart
533
+ ? cell
534
+ : childElements.find(e => e.type === 'cell' &&
535
+ e.rowId === tableElement.rowIds[mergedRange.startRow] &&
536
+ e.columnId === tableElement.columnIds[mergedRange.startColumn]);
537
+ height =
538
+ mergedCell.size.height -
539
+ TableService.getRowsHeight(tableElement, childElements, mergedRange.startRow, mergedRange.endRow, rowIndex);
540
+ }
541
+ return height;
542
+ }
543
+ static autoFitRows(tableElement, childElements, columnId) {
544
+ var _a;
545
+ const elementsToUpdate = [];
546
+ const columnIndex = tableElement.columnIds.indexOf(columnId);
547
+ const column = childElements.find(e => e.type === 'column' && e.id === columnId);
548
+ const mergedRanges = table_merge_service_1.TableMergeService.getMergedRanges(tableElement, childElements);
549
+ for (const [rowIndex, rowId] of tableElement.rowIds.entries()) {
550
+ const row = childElements.find(e => e.type === 'row' && e.id === rowId);
551
+ const cell = childElements.find(e => e.type === 'cell' && e.rowId === rowId && e.columnId === columnId);
552
+ if (!row || !cell)
553
+ continue;
554
+ const cellUndo = util_1.ObjectUtil.cloneDeep(cell);
555
+ const cellRange = new table_range_1.TableRange(rowIndex, rowIndex, columnIndex, columnIndex);
556
+ const mergedRange = mergedRanges.find(range => cellRange.within(range));
557
+ const mergedRangeStart = mergedRange && cellRange.equals(mergedRange.start());
558
+ const mergedRangeOther = mergedRange && !cellRange.equals(mergedRange.start());
559
+ if (mergedRangeOther) {
560
+ const mergedCell = childElements.find(e => e.type === 'cell' &&
561
+ e.rowId === tableElement.rowIds[mergedRange.startRow] &&
562
+ e.columnId === tableElement.columnIds[mergedRange.startColumn]);
563
+ if (rowIndex === mergedRange.endRow && columnIndex !== mergedRange.startColumn) {
564
+ const mergedCellUndo = util_1.ObjectUtil.cloneDeep(mergedCell);
565
+ mergedCell.size.width = TableService.getColumnsWidth(tableElement, childElements, mergedRange.startColumn, mergedRange.endColumn);
566
+ const adjustedSize = TableService.getCellSize(mergedCell);
567
+ mergedCell.size.height = adjustedSize.height;
568
+ elementsToUpdate.push({
569
+ change: mergedCell,
570
+ undo: mergedCellUndo,
571
+ });
572
+ }
573
+ }
574
+ cell.size.width = mergedRangeStart
575
+ ? TableService.getColumnsWidth(tableElement, childElements, mergedRange.startColumn, mergedRange.endColumn)
576
+ : column.size.width;
577
+ const adjustedSize = TableService.getCellSize(cell);
578
+ cell.size.height = adjustedSize.height;
579
+ elementsToUpdate.push({
580
+ change: cell,
581
+ undo: cellUndo,
582
+ });
583
+ if (rowIndex === ((_a = mergedRange === null || mergedRange === void 0 ? void 0 : mergedRange.endRow) !== null && _a !== void 0 ? _a : rowIndex)) {
584
+ const cellHeight = TableService.getCellMinHeight(cell, tableElement, childElements);
585
+ if (cellHeight > row.size.height) {
586
+ elementsToUpdate.push(TableService.resizeRow(tableElement, childElements, rowId, cellHeight).elementsToUpdate[1]);
587
+ }
588
+ }
589
+ }
590
+ return { elementsToUpdate };
591
+ }
592
+ static clearCell(element) {
593
+ element.text = '';
594
+ element.size.height = table_constants_1.TABLE_ROW_MIN_HEIGHT;
595
+ }
596
+ static getCellSize(element, text) {
597
+ var _a, _b, _c, _d, _e, _f;
598
+ const fontFamily = `${(_c = (_b = (_a = element.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}`;
599
+ const fontSize = `${(_f = (_e = (_d = element.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`;
600
+ const fixedWidth = `${element.size.width - table_constants_1.TABLE_TEXT_PADDING * 2}px`;
601
+ const size = this.getSize(text !== null && text !== void 0 ? text : element.text, `width: ${fixedWidth}; height: auto; font-family: ${fontFamily}; font-size: ${fontSize};`);
602
+ return { height: Math.max(size.height + table_constants_1.TABLE_TEXT_PADDING * 2, table_constants_1.TABLE_ROW_MIN_HEIGHT), width: size.width };
603
+ }
604
+ static getSize(text, style) {
605
+ if (!document)
606
+ throw new Error('No document found.');
607
+ let div = document.createElement('div');
608
+ div.innerHTML = text;
609
+ div.setAttribute('class', 'text-calc');
610
+ div.setAttribute('style', style);
611
+ document.body.appendChild(div);
612
+ const width = div.clientWidth;
613
+ const height = div.clientHeight;
614
+ document.body.removeChild(div);
615
+ div = null;
616
+ return { width, height };
617
+ }
618
+ }
619
+ exports.TableService = TableService;
620
+ TableService.DEFAULT_CELL_STYLE = {
621
+ font: {
622
+ size: table_constants_1.DEFAULT_TEXT_FONT_SIZE,
623
+ family: table_constants_1.DEFAULT_TEXT_FONT_FAMILY,
624
+ },
625
+ text: {
626
+ align: table_constants_1.TEXT_ALIGN,
627
+ valign: table_constants_1.TEXT_VALIGN,
628
+ },
629
+ backgroundColor: table_constants_1.TRANSPARENT_COLOR,
630
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@contrail/document-table",
3
+ "version": "1.0.1",
4
+ "description": "Library for document tables",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
10
+ "lint": "tslint -p tsconfig.json",
11
+ "test": "jest"
12
+ },
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "ISC",
16
+ "devDependencies": {
17
+ "@types/jest": "^29.5.2",
18
+ "jest": "^29.5.0",
19
+ "nanoid": "^3.2.0",
20
+ "prettier": "^1.19.1",
21
+ "ts-jest": "^29.1.1",
22
+ "tslint": "^5.11.0",
23
+ "tslint-config-prettier": "^1.18.0",
24
+ "typescript": "^4.0.0"
25
+ },
26
+ "jest": {
27
+ "moduleFileExtensions": [
28
+ "js",
29
+ "json",
30
+ "ts"
31
+ ],
32
+ "rootDir": "src",
33
+ "testRegex": ".spec.ts$",
34
+ "transform": {
35
+ "^.+\\.(t|j)s$": "ts-jest"
36
+ },
37
+ "coverageDirectory": "../coverage",
38
+ "testEnvironment": "node"
39
+ },
40
+ "dependencies": {
41
+ "@contrail/actions": "^1.0.14",
42
+ "@contrail/documents": "^1.0.108",
43
+ "@contrail/types": "^3.0.71",
44
+ "@contrail/util": "^1.0.65",
45
+ "reflect-metadata": "^0.1.13"
46
+ }
47
+ }