quill-table-up 2.0.1 → 2.0.3

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.
Files changed (99) hide show
  1. package/dist/index.d.ts +5 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.umd.js +1 -1
  5. package/dist/index.umd.js.map +1 -1
  6. package/dist/table-creator.css +1 -1
  7. package/package.json +9 -14
  8. package/src/__tests__/e2e/custom-creator.test.ts +44 -0
  9. package/src/__tests__/e2e/table-align.test.ts +39 -0
  10. package/src/__tests__/e2e/table-resize.test.ts +152 -0
  11. package/src/__tests__/e2e/table-scrollbar.test.ts +31 -0
  12. package/src/__tests__/e2e/table-selection.test.ts +83 -0
  13. package/src/__tests__/e2e/utils.ts +6 -0
  14. package/src/__tests__/unit/table-insert-blot.test.ts +464 -0
  15. package/src/__tests__/unit/table-insert-remove-merge.test.ts +1270 -0
  16. package/src/__tests__/unit/table-redo-undo.test.ts +909 -0
  17. package/src/__tests__/unit/utils.test-d.ts +49 -0
  18. package/src/__tests__/unit/utils.test.ts +715 -0
  19. package/src/__tests__/unit/utils.ts +216 -0
  20. package/src/__tests__/unit/vitest.d.ts +12 -0
  21. package/src/formats/container-format.ts +52 -0
  22. package/src/formats/index.ts +10 -0
  23. package/src/formats/overrides/block.ts +93 -0
  24. package/src/formats/overrides/blockquote.ts +8 -0
  25. package/src/formats/overrides/code.ts +8 -0
  26. package/src/formats/overrides/header.ts +8 -0
  27. package/src/formats/overrides/index.ts +6 -0
  28. package/src/formats/overrides/list.ts +10 -0
  29. package/src/formats/overrides/scroll.ts +51 -0
  30. package/src/formats/table-body-format.ts +92 -0
  31. package/src/formats/table-cell-format.ts +139 -0
  32. package/src/formats/table-cell-inner-format.ts +251 -0
  33. package/src/formats/table-col-format.ts +174 -0
  34. package/src/formats/table-colgroup-format.ts +133 -0
  35. package/src/formats/table-main-format.ts +143 -0
  36. package/src/formats/table-row-format.ts +147 -0
  37. package/src/formats/table-wrapper-format.ts +55 -0
  38. package/src/formats/utils.ts +3 -0
  39. package/src/index.ts +1157 -0
  40. package/src/modules/index.ts +5 -0
  41. package/src/modules/table-align.ts +116 -0
  42. package/src/modules/table-menu/constants.ts +140 -0
  43. package/src/modules/table-menu/index.ts +3 -0
  44. package/src/modules/table-menu/table-menu-common.ts +249 -0
  45. package/src/modules/table-menu/table-menu-contextmenu.ts +94 -0
  46. package/src/modules/table-menu/table-menu-select.ts +28 -0
  47. package/src/modules/table-resize/index.ts +5 -0
  48. package/src/modules/table-resize/table-resize-box.ts +293 -0
  49. package/src/modules/table-resize/table-resize-common.ts +343 -0
  50. package/src/modules/table-resize/table-resize-line.ts +163 -0
  51. package/src/modules/table-resize/table-resize-scale.ts +154 -0
  52. package/src/modules/table-resize/utils.ts +3 -0
  53. package/src/modules/table-scrollbar.ts +255 -0
  54. package/src/modules/table-selection.ts +262 -0
  55. package/src/style/button.less +45 -0
  56. package/src/style/color-picker.less +134 -0
  57. package/src/style/dialog.less +53 -0
  58. package/src/style/functions.less +9 -0
  59. package/src/style/index.less +89 -0
  60. package/src/style/input.less +64 -0
  61. package/src/style/select-box.less +51 -0
  62. package/src/style/table-creator.less +68 -0
  63. package/src/style/table-menu.less +122 -0
  64. package/src/style/table-resize-scale.less +31 -0
  65. package/src/style/table-resize.less +183 -0
  66. package/src/style/table-scrollbar.less +49 -0
  67. package/src/style/table-selection.less +15 -0
  68. package/src/style/tooltip.less +19 -0
  69. package/src/style/variables.less +1 -0
  70. package/src/svg/background.svg +1 -0
  71. package/src/svg/border.svg +1 -0
  72. package/src/svg/color.svg +1 -0
  73. package/src/svg/insert-bottom.svg +1 -0
  74. package/src/svg/insert-left.svg +1 -0
  75. package/src/svg/insert-right.svg +1 -0
  76. package/src/svg/insert-top.svg +1 -0
  77. package/src/svg/merge-cell.svg +1 -0
  78. package/src/svg/remove-column.svg +1 -0
  79. package/src/svg/remove-row.svg +1 -0
  80. package/src/svg/remove-table.svg +1 -0
  81. package/src/svg/split-cell.svg +1 -0
  82. package/src/types.d.ts +4 -0
  83. package/src/utils/bem.ts +23 -0
  84. package/src/utils/color.ts +109 -0
  85. package/src/utils/components/button.ts +22 -0
  86. package/src/utils/components/color-picker.ts +236 -0
  87. package/src/utils/components/dialog.ts +41 -0
  88. package/src/utils/components/index.ts +6 -0
  89. package/src/utils/components/input.ts +74 -0
  90. package/src/utils/components/table/creator.ts +86 -0
  91. package/src/utils/components/table/index.ts +2 -0
  92. package/src/utils/components/table/select-box.ts +83 -0
  93. package/src/utils/components/tooltip.ts +186 -0
  94. package/src/utils/constants.ts +99 -0
  95. package/src/utils/index.ts +7 -0
  96. package/src/utils/is.ts +6 -0
  97. package/src/utils/position.ts +21 -0
  98. package/src/utils/types.ts +131 -0
  99. package/src/utils/utils.ts +139 -0
@@ -0,0 +1,293 @@
1
+ import type { Parchment as TypeParchment } from 'quill';
2
+ import type TableUp from '../..';
3
+ import type { TableColFormat, TableMainFormat, TableRowFormat } from '../..';
4
+ import Quill from 'quill';
5
+ import { TableBodyFormat } from '../../formats';
6
+ import { addScrollEvent, clearScrollEvent, createBEM } from '../../utils';
7
+ import { TableResizeCommon } from './table-resize-common';
8
+ import { isTableAlignRight } from './utils';
9
+
10
+ interface Point {
11
+ x: number;
12
+ y: number;
13
+ };
14
+ export class TableResizeBox extends TableResizeCommon {
15
+ root!: HTMLElement;
16
+ tableMain: TableMainFormat;
17
+ tableWrapper!: TypeParchment.Parent;
18
+ resizeObserver!: ResizeObserver;
19
+ tableCols: TableColFormat[] = [];
20
+ tableRows: TableRowFormat[] = [];
21
+ rowHeadWrapper: HTMLElement | null = null;
22
+ colHeadWrapper: HTMLElement | null = null;
23
+ corner: HTMLElement | null = null;
24
+ scrollHandler: [HTMLElement, (e: Event) => void][] = [];
25
+ lastHeaderSelect: [Point, Point] | null = null;
26
+ size: number = 12;
27
+ bem = createBEM('resize-box');
28
+
29
+ constructor(public tableModule: TableUp, public table: HTMLElement, quill: Quill) {
30
+ super(tableModule, quill);
31
+ this.tableMain = Quill.find(this.table) as TableMainFormat;
32
+
33
+ if (!this.tableMain) return;
34
+ this.tableWrapper = this.tableMain.parent;
35
+ if (!this.tableWrapper) return;
36
+
37
+ this.root = this.tableModule.addContainer(this.bem.b());
38
+ this.resizeObserver = new ResizeObserver(() => {
39
+ this.show();
40
+ });
41
+ this.resizeObserver.observe(this.table);
42
+ }
43
+
44
+ handleResizerHeader(isX: boolean, e: MouseEvent) {
45
+ const { clientX, clientY } = e;
46
+ const tableRect = this.table.getBoundingClientRect();
47
+ if (this.tableModule.tableSelection) {
48
+ const tableSelection = this.tableModule.tableSelection;
49
+ if (!e.shiftKey) {
50
+ this.lastHeaderSelect = null;
51
+ }
52
+ const currentBoundary: [Point, Point] = [
53
+ { x: isX ? tableRect.left : clientX, y: isX ? clientY : tableRect.top },
54
+ { x: isX ? tableRect.right : clientX, y: isX ? clientY : tableRect.bottom },
55
+ ];
56
+ if (this.lastHeaderSelect) {
57
+ currentBoundary[0] = {
58
+ x: Math.min(currentBoundary[0].x, this.lastHeaderSelect[0].x),
59
+ y: Math.min(currentBoundary[0].y, this.lastHeaderSelect[0].y),
60
+ };
61
+ currentBoundary[1] = {
62
+ x: Math.max(currentBoundary[1].x, this.lastHeaderSelect[1].x),
63
+ y: Math.max(currentBoundary[1].y, this.lastHeaderSelect[1].y),
64
+ };
65
+ }
66
+ else {
67
+ this.lastHeaderSelect = currentBoundary;
68
+ }
69
+
70
+ tableSelection.selectedTds = tableSelection.computeSelectedTds(...currentBoundary);
71
+ tableSelection.show();
72
+ }
73
+ };
74
+
75
+ findCurrentColIndex(e: MouseEvent): number {
76
+ return Array.from(this.root.getElementsByClassName(this.bem.be('col-separator'))).indexOf(e.target as HTMLElement);
77
+ }
78
+
79
+ colWidthChange(i: number, w: number, _isFull: boolean) {
80
+ const tableColHeads = Array.from(this.root.getElementsByClassName(this.bem.be('col-header'))) as HTMLElement[];
81
+ tableColHeads[i].style.width = `${w}px`;
82
+ }
83
+
84
+ handleColMouseDownFunc = function (this: TableResizeBox, e: MouseEvent) {
85
+ const value = this.handleColMouseDown(e);
86
+ if (value && this.dragColBreak) {
87
+ Object.assign(this.dragColBreak.style, {
88
+ top: `${value.top - this.size}px`,
89
+ left: `${value.left}px`,
90
+ height: `${value.height + this.size}px`,
91
+ });
92
+ }
93
+ return value;
94
+ }.bind(this);
95
+
96
+ bindColEvents() {
97
+ const tableColHeads = Array.from(this.root.getElementsByClassName(this.bem.be('col-header'))) as HTMLElement[];
98
+ const tableColHeadSeparators = Array.from(this.root.getElementsByClassName(this.bem.be('col-separator'))) as HTMLElement[];
99
+
100
+ addScrollEvent.call(this, this.tableWrapper.domNode, () => {
101
+ this.colHeadWrapper!.scrollLeft = this.tableWrapper.domNode.scrollLeft;
102
+ });
103
+
104
+ for (const el of tableColHeads) {
105
+ el.addEventListener('click', this.handleResizerHeader.bind(this, false));
106
+ }
107
+ for (const el of tableColHeadSeparators) {
108
+ el.addEventListener('mousedown', this.handleColMouseDownFunc);
109
+ // prevent drag
110
+ el.addEventListener('dragstart', e => e.preventDefault());
111
+ }
112
+ }
113
+
114
+ findCurrentRowIndex(e: MouseEvent): number {
115
+ return Array.from(this.root.getElementsByClassName(this.bem.be('row-separator'))).indexOf(e.target as HTMLElement);
116
+ }
117
+
118
+ rowHeightChange(i: number, h: number) {
119
+ const tableRowHeads = Array.from(this.root.getElementsByClassName(this.bem.be('row-header'))) as HTMLElement[];
120
+ tableRowHeads[i].style.height = `${h}px`;
121
+ }
122
+
123
+ handleRowMouseDownFunc = function (this: TableResizeBox, e: MouseEvent) {
124
+ const value = this.handleRowMouseDown(e);
125
+ if (value && this.dragRowBreak) {
126
+ Object.assign(this.dragRowBreak.style, {
127
+ top: `${value.top}px`,
128
+ left: `${value.left - this.size}px`,
129
+ width: `${value.width + this.size}px`,
130
+ });
131
+ }
132
+ return value;
133
+ }.bind(this);
134
+
135
+ bindRowEvents() {
136
+ const tableRowHeads = Array.from(this.root.getElementsByClassName(this.bem.be('row-header'))) as HTMLElement[];
137
+ const tableRowHeadSeparators = Array.from(this.root.getElementsByClassName(this.bem.be('row-separator'))) as HTMLElement[];
138
+
139
+ addScrollEvent.call(this, this.tableWrapper.domNode, () => {
140
+ this.rowHeadWrapper!.scrollTop = this.tableWrapper.domNode.scrollTop;
141
+ });
142
+
143
+ for (const el of tableRowHeads) {
144
+ el.addEventListener('click', this.handleResizerHeader.bind(this, true));
145
+ }
146
+ for (const el of tableRowHeadSeparators) {
147
+ el.addEventListener('mousedown', this.handleRowMouseDownFunc);
148
+ // prevent drag
149
+ el.addEventListener('dragstart', e => e.preventDefault());
150
+ }
151
+ }
152
+
153
+ update() {
154
+ const [tableBodyBlot] = this.tableMain.descendant(TableBodyFormat, this.tableMain.length() - 1);
155
+ if (!tableBodyBlot) return;
156
+ const tableBodyRect = tableBodyBlot.domNode.getBoundingClientRect();
157
+ const rootRect = this.quill.root.getBoundingClientRect();
158
+ Object.assign(this.root.style, {
159
+ top: `${tableBodyRect.y - rootRect.y}px`,
160
+ left: `${tableBodyRect.x - rootRect.x}px`,
161
+ });
162
+
163
+ const tableMainRect = this.tableMain.domNode.getBoundingClientRect();
164
+ const tableWrapperRect = this.tableWrapper.domNode.getBoundingClientRect();
165
+
166
+ let cornerTranslateX = -1 * this.size;
167
+ let rowHeadWrapperTranslateX = -1 * this.size;
168
+ if (isTableAlignRight(this.tableMain)) {
169
+ this.root.classList.add(this.bem.is('align-right'));
170
+ cornerTranslateX = Math.min(tableWrapperRect.width, tableMainRect.width);
171
+ rowHeadWrapperTranslateX = Math.min(tableWrapperRect.width, tableMainRect.width);
172
+ }
173
+ else {
174
+ this.root.classList.remove(this.bem.is('align-right'));
175
+ }
176
+
177
+ if (this.corner) {
178
+ Object.assign(this.corner.style, {
179
+ transform: `translateY(${-1 * this.size}px) translateX(${cornerTranslateX}px)`,
180
+ });
181
+ }
182
+ if (this.rowHeadWrapper) {
183
+ Object.assign(this.rowHeadWrapper.style, {
184
+ transform: `translateX(${rowHeadWrapperTranslateX}px)`,
185
+ });
186
+ }
187
+ }
188
+
189
+ show() {
190
+ this.tableCols = this.tableMain.getCols();
191
+ this.tableRows = this.tableMain.getRows();
192
+ this.root.innerHTML = '';
193
+ const tableWrapperRect = this.tableWrapper.domNode.getBoundingClientRect();
194
+ const tableMainRect = this.tableMain.domNode.getBoundingClientRect();
195
+
196
+ if (this.tableCols.length > 0 && this.tableRows.length > 0) {
197
+ this.corner = document.createElement('div');
198
+ this.corner.classList.add(this.bem.be('corner'));
199
+ Object.assign(this.corner.style, {
200
+ width: `${this.size}px`,
201
+ height: `${this.size}px`,
202
+ });
203
+ this.corner.addEventListener('click', () => {
204
+ const tableRect = this.table.getBoundingClientRect();
205
+ if (this.tableModule.tableSelection) {
206
+ const tableSelection = this.tableModule.tableSelection;
207
+ tableSelection.selectedTds = tableSelection.computeSelectedTds(
208
+ { x: tableRect.x, y: tableRect.y },
209
+ { x: tableRect.right, y: tableRect.bottom },
210
+ );
211
+ tableSelection.show();
212
+ }
213
+ });
214
+ this.root.appendChild(this.corner);
215
+ }
216
+
217
+ if (this.tableCols.length > 0) {
218
+ let colHeadStr = '';
219
+ for (const [, col] of this.tableCols.entries()) {
220
+ const width = col.domNode.getBoundingClientRect().width;
221
+ colHeadStr += `<div class="${this.bem.be('col-header')}" style="width: ${width}px">
222
+ <div class="${this.bem.be('col-separator')}" style="height: ${tableMainRect.height + this.size - 3}px"></div>
223
+ </div>`;
224
+ }
225
+ const colHeadWrapper = document.createElement('div');
226
+ colHeadWrapper.classList.add(this.bem.be('col'));
227
+ const colHead = document.createElement('div');
228
+ colHead.classList.add(this.bem.be('col-wrapper'));
229
+ Object.assign(colHeadWrapper.style, {
230
+ transform: `translateY(-${this.size}px)`,
231
+ maxWidth: `${tableWrapperRect.width}px`,
232
+ height: `${this.size}px`,
233
+ });
234
+ Object.assign(colHead.style, {
235
+ width: `${tableMainRect.width}px`,
236
+ });
237
+ colHead.innerHTML = colHeadStr;
238
+ colHeadWrapper.appendChild(colHead);
239
+ this.root.appendChild(colHeadWrapper);
240
+ colHeadWrapper.scrollLeft = this.tableWrapper.domNode.scrollLeft;
241
+ this.colHeadWrapper = colHeadWrapper;
242
+ this.bindColEvents();
243
+ }
244
+
245
+ if (this.tableRows.length > 0) {
246
+ let rowHeadStr = '';
247
+ for (const [, row] of this.tableRows.entries()) {
248
+ const height = `${row.domNode.getBoundingClientRect().height}px`;
249
+ rowHeadStr += `<div class="${this.bem.be('row-header')}" style="height: ${Number.parseFloat(height)}px">
250
+ <div class="${this.bem.be('row-separator')}" style="width: ${tableMainRect.width + this.size - 3}px"></div>
251
+ </div>`;
252
+ }
253
+ const rowHeadWrapper = document.createElement('div');
254
+ rowHeadWrapper.classList.add(this.bem.be('row'));
255
+ const rowHead = document.createElement('div');
256
+ rowHead.classList.add(this.bem.be('row-wrapper'));
257
+
258
+ Object.assign(rowHeadWrapper.style, {
259
+ transform: `translateX(-${this.size}px)`,
260
+ width: `${this.size}px`,
261
+ maxHeight: `${tableWrapperRect.height}px`,
262
+ });
263
+ Object.assign(rowHead.style, {
264
+ height: `${tableMainRect.height}px`,
265
+ });
266
+ rowHead.innerHTML = rowHeadStr;
267
+ rowHeadWrapper.appendChild(rowHead);
268
+ this.root.appendChild(rowHeadWrapper);
269
+ rowHeadWrapper.scrollTop = this.tableWrapper.domNode.scrollTop;
270
+ this.rowHeadWrapper = rowHeadWrapper;
271
+ this.bindRowEvents();
272
+ }
273
+
274
+ this.update();
275
+ addScrollEvent.call(this, this.quill.root, () => {
276
+ this.update();
277
+ });
278
+ }
279
+
280
+ hide() {
281
+ this.root.classList.add(this.bem.is('hidden'));
282
+ }
283
+
284
+ destroy() {
285
+ this.hide();
286
+ clearScrollEvent.call(this);
287
+ this.resizeObserver.disconnect();
288
+ for (const [dom, handle] of this.scrollHandler) {
289
+ dom.removeEventListener('scroll', handle);
290
+ }
291
+ this.root.remove();
292
+ }
293
+ }
@@ -0,0 +1,343 @@
1
+ import type Quill from 'quill';
2
+ import type TableUp from '../..';
3
+ import type { TableMainFormat } from '../../formats';
4
+ import { createBEM, createButton, createDialog, tableUpEvent, tableUpSize } from '../../utils';
5
+ import { isTableAlignRight } from './utils';
6
+
7
+ export class TableResizeCommon {
8
+ colIndex: number = -1;
9
+ tableMain?: TableMainFormat;
10
+ dragging = false;
11
+ dragColBreak: HTMLElement | null = null;
12
+ handleColMouseUpFunc = this.handleColMouseUp.bind(this);
13
+ handleColMouseMoveFunc = this.handleColMouseMove.bind(this);
14
+ handleColMouseDownFunc = this.handleColMouseDown.bind(this);
15
+
16
+ rowIndex: number = -1;
17
+ dragRowBreak: HTMLElement | null = null;
18
+ handleRowMouseUpFunc = this.handleRowMouseUp.bind(this);
19
+ handleRowMouseMoveFunc = this.handleRowMouseMove.bind(this);
20
+ handleRowMouseDownFunc = this.handleRowMouseDown.bind(this);
21
+
22
+ dragBEM = createBEM('drag-line');
23
+
24
+ constructor(public tableModule: TableUp, public quill: Quill) {}
25
+
26
+ findCurrentColIndex(_e: MouseEvent) {
27
+ return -1;
28
+ }
29
+
30
+ colWidthChange(_i: number, _w: number, _isFull: boolean) {}
31
+
32
+ async createConfirmDialog({ message, confirm, cancel }: {
33
+ message: string;
34
+ confirm: string;
35
+ cancel: string;
36
+ }) {
37
+ return new Promise((resolve) => {
38
+ const content = document.createElement('div');
39
+ Object.assign(content.style, {
40
+ padding: '8px 12px',
41
+ fontSize: '14px',
42
+ lineHeight: '1.5',
43
+ });
44
+ const tip = document.createElement('p');
45
+ tip.textContent = message;
46
+ const btnWrapper = document.createElement('div');
47
+ Object.assign(btnWrapper.style, {
48
+ display: 'flex',
49
+ justifyContent: 'flex-end',
50
+ gap: `6px`,
51
+ });
52
+ const cancelBtn = createButton({ content: cancel });
53
+ const confirmBtn = createButton({ type: 'confirm', content: confirm });
54
+
55
+ btnWrapper.appendChild(cancelBtn);
56
+ btnWrapper.appendChild(confirmBtn);
57
+ content.appendChild(tip);
58
+ content.appendChild(btnWrapper);
59
+
60
+ const { close } = createDialog({ child: content });
61
+
62
+ cancelBtn.addEventListener('click', () => {
63
+ resolve(false);
64
+ close();
65
+ });
66
+ confirmBtn.addEventListener('click', () => {
67
+ resolve(true);
68
+ close();
69
+ });
70
+ });
71
+ }
72
+
73
+ async handleColMouseUp() {
74
+ if (!this.dragColBreak || !this.tableMain || this.colIndex === -1) return;
75
+ const cols = this.tableMain.getCols();
76
+ const w = Number.parseInt(this.dragColBreak.dataset.w || '0');
77
+ let isFull = this.tableMain.full;
78
+ let needUpdate = false;
79
+ const updateInfo: { index: number; width: number }[] = [];
80
+ if (isFull) {
81
+ const tableMainWidth = this.tableMain.domNode.getBoundingClientRect().width;
82
+ let pre = (w / tableMainWidth) * 100;
83
+ const oldWidthPre = cols[this.colIndex].width;
84
+ if (pre < oldWidthPre) {
85
+ // minus
86
+ // if not the last col. add the reduced amount to the next col
87
+ // if is the last col. add the reduced amount to the pre col
88
+ pre = Math.max(tableUpSize.colMinWidthPre, pre);
89
+ if (cols[this.colIndex + 1] || cols[this.colIndex - 1]) {
90
+ const i = cols[this.colIndex + 1] ? this.colIndex + 1 : this.colIndex - 1;
91
+ updateInfo.push({ index: i, width: cols[i].width + oldWidthPre - pre });
92
+ }
93
+ else {
94
+ pre = 100;
95
+ }
96
+ needUpdate = true;
97
+ updateInfo.push({ index: this.colIndex, width: pre });
98
+ }
99
+ else {
100
+ // magnify col
101
+ // the last col can't magnify. control last but one minus to magnify last col
102
+ if (cols[this.colIndex + 1]) {
103
+ const totalWidthNextPre = oldWidthPre + cols[this.colIndex + 1].width;
104
+ pre = Math.min(totalWidthNextPre - tableUpSize.colMinWidthPre, pre);
105
+ needUpdate = true;
106
+ updateInfo.push(
107
+ { index: this.colIndex, width: pre },
108
+ { index: this.colIndex + 1, width: totalWidthNextPre - pre },
109
+ );
110
+ }
111
+ }
112
+ }
113
+ else {
114
+ this.tableMain.domNode.style.width = `${
115
+ Number.parseFloat(this.tableMain.domNode.style.width)
116
+ - cols[this.colIndex].domNode.getBoundingClientRect().width
117
+ + w
118
+ }px`;
119
+ needUpdate = true;
120
+ updateInfo.push({ index: this.colIndex, width: w });
121
+ }
122
+
123
+ document.body.removeChild(this.dragColBreak);
124
+ this.dragColBreak = null;
125
+ document.removeEventListener('mouseup', this.handleColMouseUpFunc);
126
+ document.removeEventListener('mousemove', this.handleColMouseMoveFunc);
127
+ this.dragging = false;
128
+
129
+ if (needUpdate) {
130
+ const tableWidth = this.tableMain.domNode.getBoundingClientRect().width;
131
+ if (isFull) {
132
+ // if full table and percentage width is larger than 100%. check if convert to fixed px
133
+ let resultWidth = 0;
134
+ const skipColIndex = new Set(updateInfo.map(({ index, width }) => {
135
+ resultWidth += width;
136
+ return index;
137
+ }));
138
+ for (const [index, col] of cols.entries()) {
139
+ if (skipColIndex.has(index)) continue;
140
+ resultWidth += col.width;
141
+ }
142
+
143
+ if (resultWidth > 100) {
144
+ if (!await this.createConfirmDialog({
145
+ message: this.tableModule.options.texts.perWidthInsufficient,
146
+ confirm: this.tableModule.options.texts.confirmText,
147
+ cancel: this.tableModule.options.texts.cancelText,
148
+ })) {
149
+ return;
150
+ }
151
+ this.tableMain.cancelFull();
152
+ isFull = false;
153
+ for (const [i, info] of updateInfo.entries()) {
154
+ const { width, index } = info;
155
+ updateInfo[i] = {
156
+ index,
157
+ width: width / 100 * tableWidth,
158
+ };
159
+ }
160
+ }
161
+ }
162
+
163
+ for (const { index, width } of updateInfo) {
164
+ cols[index].width = `${Math.round(width)}${isFull ? '%' : 'px'}`;
165
+ this.colWidthChange(index, isFull ? width / 100 * tableWidth : width, isFull);
166
+ }
167
+ }
168
+
169
+ this.quill.emitter.emit(tableUpEvent.AFTER_TABLE_RESIZE);
170
+ };
171
+
172
+ handleColMouseMove(e: MouseEvent): { left: number; width: number } | undefined {
173
+ e.preventDefault();
174
+ if (!this.dragColBreak || !this.tableMain || this.colIndex === -1) return;
175
+ const cols = this.tableMain.getCols();
176
+ const changeColRect = cols[this.colIndex].domNode.getBoundingClientRect();
177
+ const tableRect = this.tableMain.domNode.getBoundingClientRect();
178
+ let resX = e.clientX;
179
+
180
+ // table full not handle align right
181
+ if (this.tableMain.full) {
182
+ // max width = current col.width + next col.width
183
+ // if current col is last. max width = current col.width
184
+ const minWidth = (tableUpSize.colMinWidthPre / 100) * tableRect.width;
185
+ let maxRange = tableRect.right;
186
+ if (resX > changeColRect.right && cols[this.colIndex + 1]) {
187
+ maxRange = Math.max(cols[this.colIndex + 1].domNode.getBoundingClientRect().right - minWidth, changeColRect.left + minWidth);
188
+ }
189
+ const minRange = changeColRect.x + minWidth;
190
+ resX = Math.min(Math.max(resX, minRange), maxRange);
191
+ }
192
+ else {
193
+ // when table align right, mousemove to the left, the col width will be increase
194
+ if (isTableAlignRight(this.tableMain)) {
195
+ if (changeColRect.right - resX < tableUpSize.colMinWidthPx) {
196
+ resX = changeColRect.right - tableUpSize.colMinWidthPx;
197
+ }
198
+ }
199
+ else {
200
+ if (resX - changeColRect.x < tableUpSize.colMinWidthPx) {
201
+ resX = changeColRect.x + tableUpSize.colMinWidthPx;
202
+ }
203
+ }
204
+ }
205
+
206
+ let width = resX - changeColRect.x;
207
+ if (isTableAlignRight(this.tableMain)) {
208
+ width = changeColRect.right - resX;
209
+ }
210
+ this.dragColBreak.style.left = `${resX}px`;
211
+ this.dragColBreak.dataset.w = String(width);
212
+ return {
213
+ left: resX,
214
+ width,
215
+ };
216
+ };
217
+
218
+ handleColMouseDown(e: MouseEvent): { top: number; left: number; height: number } | undefined {
219
+ if (e.button !== 0) return;
220
+ e.preventDefault();
221
+ if (!this.tableMain) return;
222
+ // set drag init width
223
+ const cols = this.tableMain.getCols();
224
+ const tableMainRect = this.tableMain.domNode.getBoundingClientRect();
225
+ const fullWidth = tableMainRect.width;
226
+ this.colIndex = this.findCurrentColIndex(e);
227
+ if (this.colIndex === -1) return;
228
+ const colWidthAttr = cols[this.colIndex].width;
229
+ const width = this.tableMain.full ? colWidthAttr / 100 * fullWidth : colWidthAttr;
230
+
231
+ document.addEventListener('mouseup', this.handleColMouseUpFunc);
232
+ document.addEventListener('mousemove', this.handleColMouseMoveFunc);
233
+
234
+ this.dragging = true;
235
+
236
+ const divDom = document.createElement('div');
237
+ divDom.classList.add(this.dragBEM.b());
238
+ divDom.classList.add(this.dragBEM.is('col'));
239
+ divDom.dataset.w = String(width);
240
+
241
+ const styleValue = {
242
+ top: tableMainRect.y,
243
+ left: e.clientX,
244
+ height: tableMainRect.height,
245
+ };
246
+ Object.assign(divDom.style, {
247
+ top: `${styleValue.top}px`,
248
+ left: `${styleValue.left}px`,
249
+ height: `${styleValue.height}px`,
250
+ });
251
+ const appendTo = document.body;
252
+ appendTo.appendChild(divDom);
253
+
254
+ if (this.dragColBreak) appendTo.removeChild(this.dragColBreak);
255
+ this.dragColBreak = divDom;
256
+
257
+ return styleValue;
258
+ };
259
+
260
+ findCurrentRowIndex(_e: MouseEvent) {
261
+ return -1;
262
+ }
263
+
264
+ rowHeightChange(_i: number, _h: number) {}
265
+
266
+ handleRowMouseUp() {
267
+ if (!this.tableMain || !this.dragRowBreak || this.rowIndex === -1) return;
268
+ const h = Number.parseInt(this.dragRowBreak.dataset.h || '0');
269
+
270
+ const rows = this.tableMain.getRows();
271
+ rows[this.rowIndex].setHeight(`${h}px`);
272
+ this.rowHeightChange(this.rowIndex, h);
273
+
274
+ document.body.removeChild(this.dragRowBreak);
275
+ this.dragRowBreak = null;
276
+ document.removeEventListener('mouseup', this.handleRowMouseUpFunc);
277
+ document.removeEventListener('mousemove', this.handleRowMouseMoveFunc);
278
+ this.dragging = false;
279
+ this.quill.emitter.emit(tableUpEvent.AFTER_TABLE_RESIZE);
280
+ }
281
+
282
+ handleRowMouseMove(e: MouseEvent): { top: number; height: number } | undefined {
283
+ if (!this.tableMain || !this.dragRowBreak || this.rowIndex === -1) return;
284
+ e.preventDefault();
285
+ const rows = this.tableMain.getRows();
286
+ const rect = rows[this.rowIndex].domNode.getBoundingClientRect();
287
+ let resY = e.clientY;
288
+ if (resY - rect.y < tableUpSize.rowMinHeightPx) {
289
+ resY = rect.y + tableUpSize.rowMinHeightPx;
290
+ }
291
+ this.dragRowBreak.style.top = `${resY}px`;
292
+ this.dragRowBreak.dataset.h = String(resY - rect.y);
293
+ return {
294
+ top: resY,
295
+ height: resY - rect.y,
296
+ };
297
+ }
298
+
299
+ handleRowMouseDown(e: MouseEvent): { top: number; left: number; width: number } | undefined {
300
+ if (e.button !== 0) return;
301
+ e.preventDefault();
302
+ if (!this.tableMain) return;
303
+
304
+ this.rowIndex = this.findCurrentRowIndex(e);
305
+ if (this.rowIndex === -1) return;
306
+
307
+ this.dragging = true;
308
+ document.addEventListener('mouseup', this.handleRowMouseUpFunc);
309
+ document.addEventListener('mousemove', this.handleRowMouseMoveFunc);
310
+
311
+ const rows = this.tableMain.getRows();
312
+
313
+ // set drag init width
314
+ const height = rows[this.rowIndex].domNode.getBoundingClientRect().height;
315
+ const tableMainRect = this.tableMain.domNode.getBoundingClientRect();
316
+
317
+ const divDom = document.createElement('div');
318
+ divDom.classList.add(this.dragBEM.b());
319
+ divDom.classList.add(this.dragBEM.is('row'));
320
+ divDom.dataset.h = String(height);
321
+
322
+ const styleValue = {
323
+ top: e.clientY,
324
+ left: tableMainRect.x,
325
+ width: tableMainRect.width,
326
+ };
327
+ Object.assign(divDom.style, {
328
+ top: `${styleValue.top}px`,
329
+ left: `${styleValue.left}px`,
330
+ width: `${styleValue.width}px`,
331
+ });
332
+ const appendTo = document.body;
333
+ appendTo.appendChild(divDom);
334
+
335
+ if (this.dragRowBreak) appendTo.removeChild(this.dragRowBreak);
336
+ this.dragRowBreak = divDom;
337
+
338
+ return styleValue;
339
+ };
340
+
341
+ update() {}
342
+ destroy() {}
343
+ }